1
1
import React from 'react'
2
2
import { useTranslation } from 'react-i18next'
3
- import { useLoaderData , useNavigate } from 'react-router-dom'
4
-
5
- import * as Page from '@/ui/page'
6
- import * as Table from '@/ui/table'
3
+ import { useNavigate } from 'react-router-dom'
7
4
import { motion } from 'framer-motion'
5
+ import { Icon } from '@iconify/react'
8
6
7
+
8
+ import { GetSessions , GetSessionsStatistics } from '@cmd/CommandHandler'
9
9
import type { model } from '@model'
10
- import { Button } from '@/ui/button'
11
- import { HoverCard , HoverCardContent , HoverCardTrigger } from '@/ui/hover-card'
12
10
13
- type DayGroup = Record < string , model . Session [ ] >
14
- type MonthGroup = Record < string , DayGroup >
15
- type YearGroup = Record < string , MonthGroup >
11
+
12
+ import { useErrorPopup } from '@/main/error-popup'
13
+ import { HoverCard , HoverCardContent , HoverCardTrigger } from '@/ui/hover-card'
14
+ import * as Page from '@/ui/page'
15
+ import { Button } from '@/ui/button'
16
16
17
17
export function SessionsListPage ( ) {
18
- const sessions = ( useLoaderData ( ) ?? [ ] ) as model . Session [ ]
19
18
const { i18n, t } = useTranslation ( )
20
19
const navigate = useNavigate ( )
20
+ const setError = useErrorPopup ( )
21
21
22
- const groupedSessions : YearGroup = sessions . reduce ( ( group , sesh ) => {
23
- const date = new Date ( sesh . createdAt )
24
- const year = date . getFullYear ( )
25
- const month = date . getMonth ( ) + 1
26
- const day = date . getDate ( )
22
+ const [ sessions , setSessions ] = React . useState < model . Session [ ] > ( [ ] )
23
+ const [ sessionStatistics , setSessionStatistics ] = React . useState < model . SessionsStatistics > ( )
24
+ const [ year , setYear ] = React . useState ( "" )
25
+ const [ month , setMonth ] = React . useState ( "01" )
26
+ const [ monthIndex , setMonthIndex ] = React . useState ( 0 )
27
+
28
+ const months = sessionStatistics ?. Months ?? [ ]
29
+
30
+ React . useEffect ( ( ) => {
31
+ GetSessionsStatistics ( '' ) . then ( setSessionStatistics ) . catch ( setError )
32
+ } , [ ] )
27
33
28
- group [ year ] = group [ year ] ?? { }
29
- group [ year ] [ month ] = group [ year ] [ month ] ?? [ ]
30
- group [ year ] [ month ] [ day ] = group [ year ] [ month ] [ day ] ?? [ ]
31
- group [ year ] [ month ] [ day ] . push ( sesh )
34
+ React . useEffect ( ( ) => {
35
+ if ( months . length > 0 && months [ monthIndex ] ) {
36
+ const [ month , year ] = months [ monthIndex ] . Date . split ( '-' )
37
+ setMonth ( month )
38
+ setYear ( year )
39
+ }
40
+ } , [ sessionStatistics , monthIndex ] )
32
41
42
+ React . useEffect ( ( ) => {
43
+ GetSessions ( "" , month , 0 , 0 ) . then ( setSessions ) . catch ( setError )
44
+ } , [ month ] )
45
+
46
+ const sessionsByDay = ( sessions ?? [ ] ) . reduce ( ( group , session ) => {
47
+ const date = new Date ( session . createdAt )
48
+ const day = date . getDate ( )
49
+ group [ day ] = group [ day ] ?? [ ]
50
+ group [ day ] . push ( session )
33
51
return group
34
- } , { } )
52
+ } , { } as Record < string , model . Session [ ] > )
35
53
36
54
return (
37
55
< Page . Root >
@@ -44,86 +62,89 @@ export function SessionsListPage() {
44
62
transition = { { delay : 0.125 } }
45
63
className = 'overflow-y-scroll'
46
64
>
47
- { Object . keys ( groupedSessions )
48
- . reverse ( )
49
- . map ( year => (
50
- < section key = { year } >
51
- < h2 className = 'px-8 py-6 text-4xl font-bold' > { year } </ h2 >
52
- { Object . keys ( groupedSessions [ year ] )
53
- . reverse ( )
54
- . map ( month => (
55
- < div key = { month } >
56
- < h3 className = 'px-8 py-4 text-xl font-bold' >
57
- { Intl . DateTimeFormat ( i18n . resolvedLanguage , {
58
- month : 'long'
59
- } ) . format ( new Date ( `2024-${ Number ( month ) < 10 ? '0' + month : month } -01` ) ) }
60
- </ h3 >
61
- < div
62
- style = { {
63
- background : `repeating-linear-gradient(
64
- 90deg,
65
- transparent 31.5px,
66
- transparent 224px,
67
- rgba(255, 255, 255, 0.125) 225px
68
- )`
69
- } }
70
- className = 'relative flex flex-wrap items-stretch border-y-[0.5px] border-solid border-divider px-8'
65
+ < header className = 'px-8 py-4 text-xl flex gap-2 items-center' >
66
+ < Button
67
+ className = "!py-0 !px-0 !text-md !font-normal"
68
+ disabled = { months [ monthIndex + 1 ] === undefined }
69
+ onClick = { ( ) => setMonthIndex ( monthIndex + 1 ) } >
70
+ < Icon width = { 26 } height = { 26 } icon = 'material-symbols:chevron-left' />
71
+ </ Button >
72
+ < Button
73
+ className = "!py-0 !px-0 !text-md !font-normal"
74
+ disabled = { monthIndex === 0 }
75
+ onClick = { ( ) => setMonthIndex ( monthIndex - 1 ) } >
76
+ < Icon width = { 26 } height = { 26 } icon = 'material-symbols:chevron-left' className = 'rotate-180' />
77
+ </ Button >
78
+ < h2 className = 'ml-2 font-bold' >
79
+ { year } { " " } /{ " " }
80
+ { Intl . DateTimeFormat ( i18n . resolvedLanguage , {
81
+ month : 'long'
82
+ } ) . format ( new Date ( `2024-${ month } -01` ) ) }
83
+ </ h2 >
84
+ </ header >
85
+
86
+ < div
87
+ style = { {
88
+ background : `repeating-linear-gradient(
89
+ 90deg,
90
+ transparent 31.5px,
91
+ transparent 224px,
92
+ rgba(255, 255, 255, 0.125) 225px
93
+ )`
94
+ } }
95
+ className = 'relative flex flex-wrap items-stretch border-y-[0.5px] border-solid border-divider px-8'
96
+ >
97
+ { Object . keys ( sessionsByDay ) . map ( day => (
98
+ < div
99
+ key = { day }
100
+ className = 'flex w-[193.5px] flex-col border-b-[0.5px] border-solid border-divider px-2'
101
+ >
102
+ < span className = 'text-center text-xl font-bold' > { day } </ span >
103
+ { sessionsByDay [ day ] . reverse ( ) . map ( s => (
104
+ < HoverCard key = { s . id } openDelay = { 250 } >
105
+ < HoverCardTrigger >
106
+ < Button
107
+ className = 'mb-1 w-full !justify-between gap-2 rounded-xl !px-[6px] !py-0 !pt-[2px] text-xl'
108
+ onClick = { ( ) => navigate ( `/sessions/${ s . id } /matches` ) }
71
109
>
72
- { Object . keys ( groupedSessions [ year ] [ month ] ) . map ( day => (
73
- < div
74
- key = { day }
75
- className = 'flex w-[193.5px] flex-col border-b-[0.5px] border-solid border-divider px-2'
76
- >
77
- < span className = 'text-center text-xl font-bold' > { day } </ span >
78
- { groupedSessions [ year ] [ month ] [ day ] . reverse ( ) . map ( s => (
79
- < HoverCard >
80
- < HoverCardTrigger >
81
- < Button
82
- className = 'mb-1 w-full !justify-between gap-2 rounded-xl !px-[6px] !py-0 !pt-[2px] text-xl'
83
- onClick = { ( ) => navigate ( `/sessions/${ s . id } /matches` ) }
84
- >
85
- < span className = 'text-base font-bold' >
86
- { Intl . DateTimeFormat ( i18n . resolvedLanguage , {
87
- hour : '2-digit' ,
88
- minute : '2-digit'
89
- } ) . format ( new Date ( s . createdAt ) ) }
90
- </ span >
91
- < span className = 'text-base font-light' > { s . userName } </ span >
92
- </ Button >
93
- </ HoverCardTrigger >
94
- < HoverCardContent side = 'bottom' >
95
- < dl >
96
- < div className = 'flex justify-between gap-2' >
97
- < dt > { t ( 'wins' ) } </ dt >
98
- < dd > { s . matchesWon } </ dd >
99
- </ div >
100
- < div className = 'flex justify-between gap-2' >
101
- < dt > { t ( 'losses' ) } </ dt >
102
- < dd > { s . matchesLost } </ dd >
103
- </ div >
104
- { s . lpGain != 0 && s . mrGain != 0 && (
105
- < >
106
- < div className = 'flex justify-between gap-2' >
107
- < dt > { t ( 'mrGain' ) } </ dt >
108
- < dd > { s . mrGain } </ dd >
109
- </ div >
110
- < div className = 'flex justify-between gap-2' >
111
- < dt > { t ( 'lpGain' ) } </ dt >
112
- < dd > { s . lpGain } </ dd >
113
- </ div >
114
- </ >
115
- ) }
116
- </ dl >
117
- </ HoverCardContent >
118
- </ HoverCard >
119
- ) ) }
120
- </ div >
121
- ) ) }
122
- </ div >
123
- </ div >
124
- ) ) }
125
- </ section >
110
+ < span className = 'text-base font-bold' >
111
+ { Intl . DateTimeFormat ( i18n . resolvedLanguage , {
112
+ hour : '2-digit' ,
113
+ minute : '2-digit'
114
+ } ) . format ( new Date ( s . createdAt ) ) }
115
+ </ span >
116
+ < span className = 'text-base font-light' > { s . userName } </ span >
117
+ </ Button >
118
+ </ HoverCardTrigger >
119
+ < HoverCardContent side = 'bottom' >
120
+ < dl >
121
+ < div className = 'flex justify-between gap-2' >
122
+ < dt > { t ( 'wins' ) } </ dt >
123
+ < dd > { s . matchesWon } </ dd >
124
+ </ div >
125
+ < div className = 'flex justify-between gap-2' >
126
+ < dt > { t ( 'losses' ) } </ dt >
127
+ < dd > { s . matchesLost } </ dd >
128
+ </ div >
129
+ { s . lpGain != 0 && s . mrGain != 0 && (
130
+ < >
131
+ < div className = 'flex justify-between gap-2' >
132
+ < dt > { t ( 'mrGain' ) } </ dt >
133
+ < dd > { s . mrGain } </ dd >
134
+ </ div >
135
+ < div className = 'flex justify-between gap-2' >
136
+ < dt > { t ( 'lpGain' ) } </ dt >
137
+ < dd > { s . lpGain } </ dd >
138
+ </ div >
139
+ </ >
140
+ ) }
141
+ </ dl >
142
+ </ HoverCardContent >
143
+ </ HoverCard >
144
+ ) ) }
145
+ </ div >
126
146
) ) }
147
+ </ div >
127
148
</ motion . div >
128
149
</ Page . Root >
129
150
)
0 commit comments