@@ -2,6 +2,7 @@ import { Express } from 'express';
2
2
import { PrismaClient } from '@prisma/client' ;
3
3
import { CURSUS_ID } from '../../env' ;
4
4
import { ChartConfiguration } from 'chart.js' ;
5
+ import { CoalitionScore , getCoalitionScore } from '../../utils' ;
5
6
6
7
export const setupAdminChartsRoutes = function ( app : Express , prisma : PrismaClient ) : void {
7
8
app . get ( '/admin/charts/coalitions/users/distribution' , async ( req , res ) => {
@@ -174,4 +175,185 @@ export const setupAdminChartsRoutes = function(app: Express, prisma: PrismaClien
174
175
return res . status ( 400 ) . json ( { error : err } ) ;
175
176
}
176
177
} ) ;
178
+
179
+ app . get ( '/admin/charts/coalitions/scores/history' , async ( req , res ) => {
180
+ // TODO: change this to the full overview of a tournament deadline instead of past 30 days
181
+ try {
182
+ const coalitions = await prisma . intraCoalition . findMany ( {
183
+ select : {
184
+ id : true ,
185
+ name : true ,
186
+ color : true ,
187
+ }
188
+ } ) ;
189
+ if ( coalitions . length === 0 ) {
190
+ throw new Error ( 'No coalitions found' ) ;
191
+ }
192
+ // Get the score for the past 30 days per day, 2 points per day (00:00 and 12:00)
193
+ const dates = [ ] ;
194
+ const now = new Date ( ) ;
195
+ now . setHours ( ( now . getHours ( ) > 12 ) ? 12 : 0 , 0 , 0 , 0 ) ;
196
+ const monthAgo = new Date ( now . getTime ( ) - 30 * 24 * 60 * 60 * 1000 ) ;
197
+ for ( let i = 0 ; i <= 60 ; i ++ ) {
198
+ dates . push ( new Date ( monthAgo . getTime ( ) + i * 12 * 60 * 60 * 1000 ) ) ;
199
+ }
200
+
201
+ // Get the scores for each coalition
202
+ const coalitionDataPoints : { [ key : number ] : CoalitionScore [ ] } = { } ;
203
+ for ( const coalition of coalitions ) {
204
+ const dataPoints : CoalitionScore [ ] = [ ] ;
205
+ for ( const date of dates ) {
206
+ dataPoints [ date . getTime ( ) ] = await getCoalitionScore ( prisma , coalition . id , date ) ;
207
+ }
208
+ coalitionDataPoints [ coalition . id ] = dataPoints ;
209
+ }
210
+
211
+ // Compose the returnable data (in a format Chart.js can understand)
212
+ const chartJSData : ChartConfiguration = {
213
+ type : 'line' ,
214
+ data : {
215
+ labels : dates . map ( ( date ) => `${ date . toLocaleDateString ( ) } ${ date . getHours ( ) } :00` ) ,
216
+ datasets : [ ] ,
217
+ } ,
218
+ options : {
219
+ showLines : true ,
220
+ scales : {
221
+ // @ts -ignore
222
+ x : {
223
+ title : {
224
+ display : false ,
225
+ text : 'Date' ,
226
+ } ,
227
+ } ,
228
+ y : {
229
+ title : {
230
+ display : true ,
231
+ text : 'Amount of points' ,
232
+ } ,
233
+ } ,
234
+ } ,
235
+ }
236
+ } ;
237
+ for ( const coalition of coalitions ) {
238
+ chartJSData . data ! . datasets ! . push ( {
239
+ label : coalition . name ,
240
+ data : Object . values ( coalitionDataPoints [ coalition . id ] ) . map ( ( score ) => score . score ) ,
241
+ borderColor : coalition . color ? coalition . color : '#808080' ,
242
+ backgroundColor : coalition . color ? coalition . color : '#808080' ,
243
+ fill : false ,
244
+ // @ts -ignore
245
+ tension : 0.25 ,
246
+ } ) ;
247
+ }
248
+
249
+ return res . json ( chartJSData ) ;
250
+ }
251
+ catch ( err ) {
252
+ console . error ( err ) ;
253
+ return res . status ( 400 ) . json ( { error : err } ) ;
254
+ }
255
+ } ) ;
256
+
257
+ app . get ( '/admin/charts/coalitions/:coalitionId/scores/history' , async ( req , res ) => {
258
+ try {
259
+ const coalitionId = parseInt ( req . params . coalitionId ) ;
260
+ const coalition = await prisma . intraCoalition . findFirst ( {
261
+ where : {
262
+ id : coalitionId ,
263
+ } ,
264
+ select : {
265
+ id : true ,
266
+ name : true ,
267
+ color : true ,
268
+ }
269
+ } ) ;
270
+ if ( ! coalition ) {
271
+ throw new Error ( 'Invalid coalition ID' ) ;
272
+ }
273
+ // Get the score for the past 30 days per day, 2 points per day (00:00 and 12:00)
274
+ const dataPoints : CoalitionScore [ ] = [ ] ;
275
+ const monthAgo = new Date ( Date . now ( ) - 30 * 24 * 60 * 60 * 1000 ) ;
276
+ monthAgo . setHours ( 0 , 0 , 0 , 0 ) ;
277
+ for ( let i = 0 ; i < 60 ; i ++ ) {
278
+ const date = new Date ( monthAgo . getTime ( ) + i * 12 * 60 * 60 * 1000 ) ;
279
+ dataPoints [ date . getTime ( ) ] = await getCoalitionScore ( prisma , coalitionId , date ) ;
280
+ }
281
+
282
+ // Compose the returnable data (in a format Chart.js can understand)
283
+ const chartJSData : ChartConfiguration = {
284
+ type : 'line' ,
285
+ data : {
286
+ labels : Object . keys ( dataPoints ) . map ( ( timestamp ) => new Date ( parseInt ( timestamp ) ) . toLocaleDateString ( ) ) ,
287
+ datasets : [
288
+ {
289
+ label : 'Score' ,
290
+ data : Object . values ( dataPoints ) . map ( ( score ) => score . score ) ,
291
+ // borderColor: coalition.color ? coalition.color : '#808080',
292
+ // backgroundColor: coalition.color ? coalition.color : '#808080',
293
+ fill : false ,
294
+ // @ts -ignore
295
+ tension : 0.25 ,
296
+ } ,
297
+ {
298
+ label : 'Average points' ,
299
+ data : Object . values ( dataPoints ) . map ( ( score ) => score . avgPoints ) ,
300
+ // borderColor: coalition.color ? coalition.color : '#808080',
301
+ // backgroundColor: coalition.color ? coalition.color : '#808080',
302
+ fill : false ,
303
+ // @ts -ignore
304
+ tension : 0.25 ,
305
+ } ,
306
+ {
307
+ label : 'Standard deviation' ,
308
+ data : Object . values ( dataPoints ) . map ( ( score ) => score . stdDevPoints ) ,
309
+ // borderColor: coalition.color ? coalition.color : '#808080',
310
+ // backgroundColor: coalition.color ? coalition.color : '#808080',
311
+ fill : false ,
312
+ // @ts -ignore
313
+ tension : 0.25 ,
314
+ } ,
315
+ {
316
+ label : 'Min active points' ,
317
+ data : Object . values ( dataPoints ) . map ( ( score ) => score . minActivePoints ) ,
318
+ // borderColor: coalition.color ? coalition.color : '#808080',
319
+ // backgroundColor: coalition.color ? coalition.color : '#808080',
320
+ fill : false ,
321
+ // @ts -ignore
322
+ tension : 0.25 ,
323
+ } ,
324
+ ] ,
325
+ } ,
326
+ options : {
327
+ showLines : true ,
328
+ scales : {
329
+ // @ts -ignore
330
+ x : {
331
+ title : {
332
+ display : true ,
333
+ text : 'Date' ,
334
+ } ,
335
+ } ,
336
+ y : {
337
+ title : {
338
+ display : true ,
339
+ text : 'Amount of points' ,
340
+ } ,
341
+ min : 0 ,
342
+ } ,
343
+ } ,
344
+ plugins : {
345
+ legend : {
346
+ display : true ,
347
+ }
348
+ } ,
349
+ }
350
+ } ;
351
+
352
+ return res . json ( chartJSData ) ;
353
+ }
354
+ catch ( err ) {
355
+ console . error ( err ) ;
356
+ return res . status ( 400 ) . json ( { error : err } ) ;
357
+ }
358
+ } ) ;
177
359
}
0 commit comments