@@ -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,80 @@ const findPlayerWinStats = (
7677 } ;
7778} ;
7879
80+ const findMatchesBetweenPlayers = (
81+ player1 : PlayerWithStats ,
82+ player2 : PlayerWithStats
83+ ) => {
84+ const sortedLogs1 = [ ...player1 . eloLogs ] . sort (
85+ ( a , b ) => new Date ( a . date ) . getTime ( ) - new Date ( b . date ) . getTime ( )
86+ ) ;
87+ const sortedLogs2 = [ ...player2 . eloLogs ] . sort (
88+ ( a , b ) => new Date ( a . date ) . getTime ( ) - new Date ( b . date ) . getTime ( )
89+ ) ;
90+
91+ const allMatches = [ ...player1 . matchesAsWinner , ...player1 . matchesAsLoser ]
92+ . filter (
93+ ( match ) =>
94+ ( match . winnerId === player1 . id && match . loserId === player2 . id ) ||
95+ ( match . winnerId === player2 . id && match . loserId === player1 . id )
96+ )
97+ . sort ( ( a , b ) => new Date ( b . date ) . getTime ( ) - new Date ( a . date ) . getTime ( ) )
98+ . map ( ( match ) => {
99+ const matchLog1 = sortedLogs1 . find ( ( log ) => log . matchId === match . id ) ;
100+ const matchLog2 = sortedLogs2 . find ( ( log ) => log . matchId === match . id ) ;
101+
102+ let eloDiff1 = 0 ;
103+ let eloDiff2 = 0 ;
104+ let player1Elo = BASE_ELO ;
105+ let player2Elo = BASE_ELO ;
106+
107+ if ( matchLog1 ) {
108+ const matchIndex = sortedLogs1 . indexOf ( matchLog1 ) ;
109+ const previousElo =
110+ matchIndex === 0 ? BASE_ELO : sortedLogs1 [ matchIndex - 1 ] . elo ;
111+ eloDiff1 = matchLog1 . elo - previousElo ;
112+ player1Elo = matchLog1 . elo ;
113+ }
114+
115+ if ( matchLog2 ) {
116+ const matchIndex = sortedLogs2 . indexOf ( matchLog2 ) ;
117+ const previousElo =
118+ matchIndex === 0 ? BASE_ELO : sortedLogs2 [ matchIndex - 1 ] . elo ;
119+ eloDiff2 = matchLog2 . elo - previousElo ;
120+ player2Elo = matchLog2 . elo ;
121+ }
122+
123+ return {
124+ ...match ,
125+ eloDiff : match . winnerId === player1 . id ? eloDiff1 : - eloDiff1 ,
126+ player1Elo,
127+ player2Elo,
128+ winner : match . winnerId === player1 . id ? player1 : player2 ,
129+ loser : match . loserId === player1 . id ? player1 : player2 ,
130+ accumulatedEloDiff : 0 ,
131+ } ;
132+ } ) ;
133+
134+ let runningTotal = 0 ;
135+ allMatches . reverse ( ) . forEach ( ( match ) => {
136+ const matchEloDiff = Math . abs ( match . eloDiff ) ;
137+ runningTotal +=
138+ match . winner . id === player1 . id ? matchEloDiff : - matchEloDiff ;
139+ match . accumulatedEloDiff = runningTotal ;
140+ } ) ;
141+ allMatches . reverse ( ) ;
142+
143+ return allMatches ;
144+ } ;
145+
79146export default function Index ( ) {
80147 const navigate = useNavigate ( ) ;
81148 const { playerOptions, player1, player2, player1WinStats } =
82149 useTypedLoaderData < typeof loader > ( ) ;
83150
84- // TODO: migrate datamodel to include elo gains/loses (recalculate elo values?)
151+ const matchHistory =
152+ player1 && player2 ? findMatchesBetweenPlayers ( player1 , player2 ) : [ ] ;
153+
85154 return (
86155 < div className = { PageContainerStyling } >
87156 < div className = "flex justify-center py-4" >
@@ -154,15 +223,97 @@ export default function Index() {
154223 < div className = "text-center" >
155224 < div className = "text-3xl font-bold text-blue-600 dark:text-blue-400" >
156225 { player1WinStats ?. winPercentage
157- ? player1WinStats . winPercentage . toFixed ( 2 )
226+ ? player1WinStats . winPercentage . toFixed ( 1 )
158227 : 0 }
159228 %
160229 </ div >
161230 < div className = "mt-1 text-sm text-gray-600 dark:text-gray-400" >
162- Overlegenhet
231+ Win rate
163232 </ div >
164233 </ div >
165234 </ div >
235+
236+ < h2 className = "mb-4 mt-8 text-2xl font-bold text-gray-900 dark:text-white" >
237+ Kamphistorikk 📋
238+ </ h2 >
239+ < div className = "overflow-x-auto rounded-lg bg-white p-6 shadow-lg dark:bg-gray-800" >
240+ < table className = "min-w-full" >
241+ < thead >
242+ < tr className = "border-b dark:border-gray-700" >
243+ < th className = "py-2 text-left text-gray-900 dark:text-white" >
244+ Dato
245+ </ th >
246+ < th className = "py-2 text-left text-gray-900 dark:text-white" >
247+ Vinner
248+ </ th >
249+ < th className = "py-2 text-left text-gray-900 dark:text-white" >
250+ Taper
251+ </ th >
252+ < th className = "py-2 text-right text-gray-900 dark:text-white" >
253+ ELO
254+ </ th >
255+ < th className = "py-2 text-right text-gray-900 dark:text-white" >
256+ Total ELO
257+ </ th >
258+ </ tr >
259+ </ thead >
260+ < tbody >
261+ { matchHistory . map ( ( match ) => (
262+ < tr key = { match . id } className = "border-b dark:border-gray-700" >
263+ < td className = "py-2 text-gray-900 dark:text-white" >
264+ { new Date ( match . date ) . toLocaleString ( 'no-NO' , {
265+ year : 'numeric' ,
266+ month : 'short' ,
267+ day : '2-digit' ,
268+ } ) }
269+ </ td >
270+ < td className = "py-2 font-semibold text-gray-900 dark:text-white" >
271+ { match . winner . name } { ' ' }
272+ < span className = "font-normal text-gray-600 dark:text-gray-400" >
273+ (
274+ { match . winner . id === player1 . id
275+ ? match . player1Elo
276+ : match . player2Elo }
277+ )
278+ </ span >
279+ </ td >
280+ < td className = "py-2 font-semibold text-gray-900 dark:text-white" >
281+ { match . loser . name } { ' ' }
282+ < span className = "font-normal text-gray-600 dark:text-gray-400" >
283+ (
284+ { match . loser . id === player1 . id
285+ ? match . player1Elo
286+ : match . player2Elo }
287+ )
288+ </ span >
289+ </ td >
290+ < td
291+ className = { `py-2 text-right font-semibold ${
292+ match . winner . id === player1 . id
293+ ? 'text-green-600 dark:text-green-400'
294+ : 'text-red-600 dark:text-red-400'
295+ } `}
296+ >
297+ { match . winner . id === player1 . id ? '+' : '-' }
298+ { Math . abs ( match . eloDiff ) }
299+ </ td >
300+ < td
301+ className = { `py-2 text-right font-semibold ${
302+ match . accumulatedEloDiff > 0
303+ ? 'text-green-600 dark:text-green-400'
304+ : match . accumulatedEloDiff < 0
305+ ? 'text-red-600 dark:text-red-400'
306+ : 'text-gray-900 dark:text-white'
307+ } `}
308+ >
309+ { match . accumulatedEloDiff > 0 ? '+' : '' }
310+ { match . accumulatedEloDiff }
311+ </ td >
312+ </ tr >
313+ ) ) }
314+ </ tbody >
315+ </ table >
316+ </ div >
166317 </ div >
167318 ) }
168319 </ div >
0 commit comments