1
- import { useState } from 'react' ;
2
- import { Flex , Grid , GridItem , Spinner , Text } from '@chakra-ui/react' ;
1
+ import { useEffect , useState } from 'react' ;
2
+ import { Flex , Grid , GridItem , Input , Spinner , Text } from '@chakra-ui/react' ;
3
3
import { Select } from 'chakra-react-select' ;
4
4
import StatsGraph from './StatsGraph' ;
5
5
import { trpc } from '../../utils/trpc' ;
@@ -90,42 +90,87 @@ const StatsView = () => {
90
90
const [ personalTicketStats , setPersonalTicketStats ] = useState < TicketStats [ ] > ( [ ] ) ;
91
91
const [ globalTimeRangeOption , setGlobalTimeRangeOption ] = useState ( timeRangeOptions [ 0 ] ) ;
92
92
const [ personalTimeRangeOption , setPersonalTimeRangeOption ] = useState ( timeRangeOptions [ 0 ] ) ;
93
+ const [ globalStartDate , setGlobalStartDate ] = useState < Date > ( ) ;
94
+ const [ personalStartDate , setPersonalStartDate ] = useState < Date > ( ) ;
93
95
94
- const { isLoading : isStatsLoading } = trpc . stats . getTicketStats . useQuery ( undefined , {
96
+ const { isFetching : isFetchingStats , fetchNextPage : fetchNextStatsPage , hasNextPage : statsHasNextPage } =
97
+ trpc . stats . getInfiniteTicketStats . useInfiniteQuery ( { limit : 10000 } , {
95
98
refetchOnWindowFocus : false ,
96
99
onSuccess : data => {
97
- setTicketStats ( data ) ;
100
+ setTicketStats ( data . pages . map ( p => p . items ) . reduce ( ( a , b ) => a . concat ( b ) ) ) ;
98
101
} ,
102
+ getNextPageParam : ( lastPage ) => lastPage . nextCursor
99
103
} ) ;
100
- const { isLoading : isPersonalStatsLoading } = trpc . stats . getTicketStatsHelpedByUser . useQuery ( undefined , {
104
+
105
+ useEffect ( ( ) => {
106
+ if ( statsHasNextPage ) {
107
+ fetchNextStatsPage ( ) ;
108
+ }
109
+ } , [ ticketStats ] )
110
+
111
+ const { isFetching : isFetchingPersonalStats , fetchNextPage : fetchNextPersonalStatsPage , hasNextPage : personalStatsHasNextPage } =
112
+ trpc . stats . getInfiniteTicketStats . useInfiniteQuery ( { limit : 10000 } , {
101
113
refetchOnWindowFocus : false ,
102
114
onSuccess : data => {
103
- setPersonalTicketStats ( data ) ;
115
+ setPersonalTicketStats ( data . pages . map ( p => p . items ) . reduce ( ( a , b ) => a . concat ( b ) ) ) ;
104
116
} ,
117
+ getNextPageParam : ( lastPage ) => lastPage . nextCursor
105
118
} ) ;
106
119
107
- const getTimeRange = ( timeRangeOption : TimeRangeType | undefined , end : Date ) : TimeRange | undefined => {
108
- let start = new Date ( end ) ;
120
+ useEffect ( ( ) => {
121
+ if ( personalStatsHasNextPage ) {
122
+ fetchNextPersonalStatsPage ( ) ;
123
+ }
124
+ } , [ personalTicketStats ] )
125
+
126
+ const isStatsLoading = isFetchingStats || statsHasNextPage || isFetchingPersonalStats || personalStatsHasNextPage ;
127
+
128
+ const getStartDateFromCurrent = ( timeRangeOption : TimeRangeType ) => {
129
+ let start = new Date ( ) ;
130
+ switch ( timeRangeOption . type ) {
131
+ case 'day' :
132
+ start . setDate ( start . getDate ( ) - 1 ) ;
133
+ break ;
134
+ case 'week' :
135
+ start . setDate ( start . getDate ( ) - 7 ) ;
136
+ break ;
137
+ case 'month' :
138
+ start . setMonth ( start . getMonth ( ) - 1 ) ;
139
+ break ;
140
+ case 'all' :
141
+ start = new Date ( 'January 1, 2023 00:00:00' ) ;
142
+ break ;
143
+ default :
144
+ break ;
145
+ }
146
+ return start ;
147
+ }
148
+
149
+ const getTimeRange = ( timeRangeOption : TimeRangeType | undefined , startDate : Date | undefined ) : TimeRange | undefined => {
109
150
if ( ! timeRangeOption ) {
110
151
return undefined ;
111
152
}
153
+ let start = new Date ( ) ;
154
+ if ( startDate !== undefined ) {
155
+ start = startDate ;
156
+ } else {
157
+ start = getStartDateFromCurrent ( timeRangeOption ) ;
158
+ }
159
+
160
+ const end = new Date ( start ) ;
112
161
switch ( timeRangeOption . type ) {
113
162
case 'day' :
114
- start . setDate ( end . getDate ( ) - 1 ) ;
163
+ end . setDate ( start . getDate ( ) + 1 ) ;
115
164
return { type : timeRangeOption , startTime : start , endTime : end } ;
116
165
case 'week' :
117
- start . setDate ( end . getDate ( ) - 7 ) ;
118
- start . setHours ( 0 , 0 , 0 , 0 ) ; // Round down start date
119
- end . setHours ( 23 , 59 , 59 , 999 ) ; // Round up end date
166
+ end . setDate ( start . getDate ( ) + 7 ) ;
120
167
return { type : timeRangeOption , startTime : start , endTime : end } ;
121
168
case 'month' :
122
- start . setMonth ( end . getMonth ( ) - 1 ) ;
123
- start . setHours ( 0 , 0 , 0 , 0 ) ; // Round down start date
124
- end . setHours ( 23 , 59 , 59 , 999 ) ; // Round up end date
169
+ end . setMonth ( start . getMonth ( ) + 1 ) ;
125
170
return { type : timeRangeOption , startTime : start , endTime : end } ;
126
171
case 'all' :
127
172
start = new Date ( 'January 1, 2023 00:00:00' ) ;
128
- return { type : timeRangeOption , startTime : start , endTime : end } ;
173
+ return { type : timeRangeOption , startTime : start , endTime : new Date ( ) } ;
129
174
default :
130
175
return { type : timeRangeOption , startTime : start , endTime : end } ;
131
176
}
@@ -134,10 +179,22 @@ const StatsView = () => {
134
179
return (
135
180
< Grid m = { 4 } h = '100%' w = 'auto' templateRows = '30px 1fr 30px 1fr' templateColumns = 'repeat(6, 1fr)' gap = { 4 } >
136
181
< GridItem rowSpan = { 1 } colSpan = { 6 } >
137
- < Flex justifyContent = 'space-between ' >
138
- < Text fontSize = '3xl' fontWeight = 'semibold' mb = { 3 } >
182
+ < Flex justifyContent = 'flex-end' alignItems = 'center '>
183
+ < Text fontSize = '3xl' fontWeight = 'semibold' mb = { 3 } mr = "auto" >
139
184
Global Statistics
140
185
</ Text >
186
+ < Text mr = { 3 } > Start Date:</ Text >
187
+ < Input
188
+ mr = { 3 }
189
+ width = "250px"
190
+ placeholder = "Select Date and Time"
191
+ size = "md"
192
+ type = "datetime-local"
193
+ onChange = { event =>
194
+ setGlobalStartDate ( event . target . value === "" ? undefined : new Date ( event . target . value ) )
195
+ }
196
+ />
197
+ < Text mr = { 3 } > Range:</ Text >
141
198
< Select
142
199
value = { globalTimeRangeOption }
143
200
onChange = { val => setGlobalTimeRangeOption ( val ?? undefined ) }
@@ -152,20 +209,32 @@ const StatsView = () => {
152
209
</ Flex >
153
210
</ GridItem >
154
211
< GridItem rowSpan = { 1 } colSpan = { 4 } >
155
- < StatsGraph timeRange = { getTimeRange ( globalTimeRangeOption ?. value , new Date ( ) ) } stats = { ticketStats } />
212
+ < StatsGraph timeRange = { getTimeRange ( globalTimeRangeOption ?. value , globalStartDate ) } stats = { ticketStats } />
156
213
</ GridItem >
157
214
< GridItem mt = { 4 } rowSpan = { 1 } colSpan = { 2 } >
158
- { isStatsLoading || isPersonalStatsLoading ? (
215
+ { isStatsLoading ? (
159
216
< Spinner />
160
217
) : (
161
- < StatsPanel timeRange = { getTimeRange ( globalTimeRangeOption ?. value , new Date ( ) ) } stats = { ticketStats } />
218
+ < StatsPanel timeRange = { getTimeRange ( globalTimeRangeOption ?. value , globalStartDate ) } stats = { ticketStats } />
162
219
) }
163
220
</ GridItem >
164
221
< GridItem rowSpan = { 1 } colSpan = { 6 } >
165
- < Flex justifyContent = 'space-between' >
166
- < Text fontSize = '3xl' fontWeight = 'semibold' mb = { 3 } >
222
+ < Flex justifyContent = 'flex-end' alignItems = "center" >
223
+ < Text fontSize = '3xl' fontWeight = 'semibold' mb = { 3 } mr = "auto" >
167
224
Personal Statistics
168
225
</ Text >
226
+ < Text mr = { 3 } > Start Date:</ Text >
227
+ < Input
228
+ mr = { 3 }
229
+ width = "250px"
230
+ placeholder = "Select Date and Time"
231
+ size = "md"
232
+ type = "datetime-local"
233
+ onChange = { event =>
234
+ setPersonalStartDate ( event . target . value === "" ? undefined : new Date ( event . target . value ) )
235
+ }
236
+ />
237
+ < Text mr = { 3 } > Range:</ Text >
169
238
< Select
170
239
value = { personalTimeRangeOption }
171
240
onChange = { val => setPersonalTimeRangeOption ( val ?? undefined ) }
@@ -180,14 +249,14 @@ const StatsView = () => {
180
249
</ Flex >
181
250
</ GridItem >
182
251
< GridItem rowSpan = { 1 } colSpan = { 4 } >
183
- < StatsGraph timeRange = { getTimeRange ( personalTimeRangeOption ?. value , new Date ( ) ) } stats = { personalTicketStats } />
252
+ < StatsGraph timeRange = { getTimeRange ( personalTimeRangeOption ?. value , personalStartDate ) } stats = { personalTicketStats } />
184
253
</ GridItem >
185
254
< GridItem mt = { 4 } rowSpan = { 1 } colSpan = { 2 } >
186
- { isStatsLoading || isPersonalStatsLoading ? (
255
+ { isStatsLoading ? (
187
256
< Spinner />
188
257
) : (
189
258
< StatsPanel
190
- timeRange = { getTimeRange ( personalTimeRangeOption ?. value , new Date ( ) ) }
259
+ timeRange = { getTimeRange ( personalTimeRangeOption ?. value , personalStartDate ) }
191
260
stats = { personalTicketStats }
192
261
/>
193
262
) }
0 commit comments