@@ -4,6 +4,7 @@ import { PlayerWithStats, getPlayers } from '../services/player-service';
44import { typedjson , useTypedLoaderData } from 'remix-typedjson' ;
55import Select , { createFilter } from 'react-select' ;
66import { PageContainerStyling } from './team-duel' ;
7+ import { BASE_ELO } from '../utils/constants' ;
78
89export const meta : MetaFunction = ( ) => {
910 return [
@@ -76,12 +77,67 @@ const findPlayerWinStats = (
7677 } ;
7778} ;
7879
80+ const findMatchesBetweenPlayers = (
81+ player1 : PlayerWithStats ,
82+ player2 : PlayerWithStats
83+ ) => {
84+ const sortedLogs = [ ...player1 . eloLogs ] . sort (
85+ ( a , b ) => new Date ( a . date ) . getTime ( ) - new Date ( b . date ) . getTime ( )
86+ ) ;
87+
88+ const allMatches = [ ...player1 . matchesAsWinner , ...player1 . matchesAsLoser ]
89+ . filter (
90+ ( match ) =>
91+ ( match . winnerId === player1 . id && match . loserId === player2 . id ) ||
92+ ( match . winnerId === player2 . id && match . loserId === player1 . id )
93+ )
94+ . sort ( ( a , b ) => new Date ( b . date ) . getTime ( ) - new Date ( a . date ) . getTime ( ) )
95+ . map ( ( match ) => {
96+ const matchLog = sortedLogs . find ( ( log ) => log . matchId === match . id ) ;
97+
98+ let eloDiff = 0 ;
99+ let player1Elo = BASE_ELO ;
100+ let player2Elo = BASE_ELO ;
101+
102+ if ( matchLog ) {
103+ const matchIndex = sortedLogs . indexOf ( matchLog ) ;
104+ const previousElo =
105+ matchIndex === 0 ? BASE_ELO : sortedLogs [ matchIndex - 1 ] . elo ;
106+ eloDiff = matchLog . elo - previousElo ;
107+ player1Elo = matchLog . elo ;
108+ }
109+
110+ return {
111+ ...match ,
112+ eloDiff : match . winnerId === player1 . id ? eloDiff : - eloDiff ,
113+ player1Elo,
114+ player2Elo,
115+ winner : match . winnerId === player1 . id ? player1 : player2 ,
116+ loser : match . loserId === player1 . id ? player1 : player2 ,
117+ accumulatedEloDiff : 0 ,
118+ } ;
119+ } ) ;
120+
121+ let runningTotal = 0 ;
122+ allMatches . reverse ( ) . forEach ( ( match ) => {
123+ const matchEloDiff = Math . abs ( match . eloDiff ) ;
124+ runningTotal +=
125+ match . winner . id === player1 . id ? matchEloDiff : - matchEloDiff ;
126+ match . accumulatedEloDiff = runningTotal ;
127+ } ) ;
128+ allMatches . reverse ( ) ;
129+
130+ return allMatches ;
131+ } ;
132+
79133export default function Index ( ) {
80134 const navigate = useNavigate ( ) ;
81135 const { playerOptions, player1, player2, player1WinStats } =
82136 useTypedLoaderData < typeof loader > ( ) ;
83137
84- // TODO: migrate datamodel to include elo gains/loses (recalculate elo values?)
138+ const matchHistory =
139+ player1 && player2 ? findMatchesBetweenPlayers ( player1 , player2 ) : [ ] ;
140+
85141 return (
86142 < div className = { PageContainerStyling } >
87143 < div className = "flex justify-center py-4" >
@@ -154,15 +210,97 @@ export default function Index() {
154210 < div className = "text-center" >
155211 < div className = "text-3xl font-bold text-blue-600 dark:text-blue-400" >
156212 { player1WinStats ?. winPercentage
157- ? player1WinStats . winPercentage . toFixed ( 2 )
213+ ? player1WinStats . winPercentage . toFixed ( 1 )
158214 : 0 }
159215 %
160216 </ div >
161217 < div className = "mt-1 text-sm text-gray-600 dark:text-gray-400" >
162- Overlegenhet
218+ Win rate
163219 </ div >
164220 </ div >
165221 </ div >
222+
223+ < h2 className = "mb-4 mt-8 text-2xl font-bold text-gray-900 dark:text-white" >
224+ Kamphistorikk 📋
225+ </ h2 >
226+ < div className = "overflow-x-auto rounded-lg bg-white p-6 shadow-lg dark:bg-gray-800" >
227+ < table className = "min-w-full" >
228+ < thead >
229+ < tr className = "border-b dark:border-gray-700" >
230+ < th className = "py-2 text-left text-gray-900 dark:text-white" >
231+ Dato
232+ </ th >
233+ < th className = "py-2 text-left text-gray-900 dark:text-white" >
234+ Vinner
235+ </ th >
236+ < th className = "py-2 text-left text-gray-900 dark:text-white" >
237+ Taper
238+ </ th >
239+ < th className = "py-2 text-right text-gray-900 dark:text-white" >
240+ ELO
241+ </ th >
242+ < th className = "py-2 text-right text-gray-900 dark:text-white" >
243+ ELO totalt
244+ </ th >
245+ </ tr >
246+ </ thead >
247+ < tbody >
248+ { matchHistory . map ( ( match ) => (
249+ < tr key = { match . id } className = "border-b dark:border-gray-700" >
250+ < td className = "py-2 text-gray-900 dark:text-white" >
251+ { new Date ( match . date ) . toLocaleString ( 'no-NO' , {
252+ year : 'numeric' ,
253+ month : 'short' ,
254+ day : '2-digit' ,
255+ } ) }
256+ </ td >
257+ < td className = "py-2 font-semibold text-gray-900 dark:text-white" >
258+ { match . winner . name } { ' ' }
259+ < span className = "font-normal text-gray-600 dark:text-gray-400" >
260+ (
261+ { match . winner . id === player1 . id
262+ ? match . player1Elo
263+ : match . player2Elo }
264+ )
265+ </ span >
266+ </ td >
267+ < td className = "py-2 font-semibold text-gray-900 dark:text-white" >
268+ { match . loser . name } { ' ' }
269+ < span className = "font-normal text-gray-600 dark:text-gray-400" >
270+ (
271+ { match . loser . id === player1 . id
272+ ? match . player1Elo
273+ : match . player2Elo }
274+ )
275+ </ span >
276+ </ td >
277+ < td
278+ className = { `py-2 text-right font-semibold ${
279+ match . winner . id === player1 . id
280+ ? 'text-green-600 dark:text-green-400'
281+ : 'text-red-600 dark:text-red-400'
282+ } `}
283+ >
284+ { match . winner . id === player1 . id ? '+' : '-' }
285+ { Math . abs ( match . eloDiff ) }
286+ </ td >
287+ < td
288+ className = { `py-2 text-right font-semibold ${
289+ match . accumulatedEloDiff > 0
290+ ? 'text-green-600 dark:text-green-400'
291+ : match . accumulatedEloDiff < 0
292+ ? 'text-red-600 dark:text-red-400'
293+ : 'text-gray-900 dark:text-white'
294+ } `}
295+ >
296+ { match . accumulatedEloDiff > 0 ? '+' : '' }
297+ { match . accumulatedEloDiff }
298+ </ td >
299+ </ tr >
300+ ) ) }
301+ </ tbody >
302+ </ table >
303+ </ div >
166304 </ div >
167305 ) }
168306 </ div >
0 commit comments