@@ -4,6 +4,7 @@ import { PlayerWithStats, getPlayers } from '../services/player-service';
4
4
import { typedjson , useTypedLoaderData } from 'remix-typedjson' ;
5
5
import Select , { createFilter } from 'react-select' ;
6
6
import { PageContainerStyling } from './team-duel' ;
7
+ import { BASE_ELO } from '../utils/constants' ;
7
8
8
9
export const meta : MetaFunction = ( ) => {
9
10
return [
@@ -76,12 +77,67 @@ const findPlayerWinStats = (
76
77
} ;
77
78
} ;
78
79
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
+
79
133
export default function Index ( ) {
80
134
const navigate = useNavigate ( ) ;
81
135
const { playerOptions, player1, player2, player1WinStats } =
82
136
useTypedLoaderData < typeof loader > ( ) ;
83
137
84
- // TODO: migrate datamodel to include elo gains/loses (recalculate elo values?)
138
+ const matchHistory =
139
+ player1 && player2 ? findMatchesBetweenPlayers ( player1 , player2 ) : [ ] ;
140
+
85
141
return (
86
142
< div className = { PageContainerStyling } >
87
143
< div className = "flex justify-center py-4" >
@@ -154,15 +210,97 @@ export default function Index() {
154
210
< div className = "text-center" >
155
211
< div className = "text-3xl font-bold text-blue-600 dark:text-blue-400" >
156
212
{ player1WinStats ?. winPercentage
157
- ? player1WinStats . winPercentage . toFixed ( 2 )
213
+ ? player1WinStats . winPercentage . toFixed ( 1 )
158
214
: 0 }
159
215
%
160
216
</ div >
161
217
< div className = "mt-1 text-sm text-gray-600 dark:text-gray-400" >
162
- Overlegenhet
218
+ Win rate
163
219
</ div >
164
220
</ div >
165
221
</ 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 >
166
304
</ div >
167
305
) }
168
306
</ div >
0 commit comments