@@ -2,9 +2,9 @@ import 'ag-grid-community/styles/ag-grid.css';
2
2
import 'ag-grid-community/styles/ag-theme-alpine.css' ;
3
3
import 'src/styles/Leaderboard.scss' ;
4
4
5
- import { ColDef } from 'ag-grid-community' ;
5
+ import { ColDef , IDatasource } from 'ag-grid-community' ;
6
6
import { AgGridReact } from 'ag-grid-react' ;
7
- import React , { useEffect , useMemo } from 'react' ;
7
+ import React , { useEffect , useMemo , useRef } from 'react' ;
8
8
import { useDispatch } from 'react-redux' ;
9
9
import default_avatar from 'src/assets/default-avatar.jpg' ;
10
10
import { useTypedSelector } from 'src/commons/utils/Hooks' ;
@@ -20,28 +20,7 @@ import LeaderboardExportButton from './LeaderboardExportButton';
20
20
import LeaderboardPodium from './LeaderboardPodium' ;
21
21
22
22
const OverallLeaderboard : React . FC = ( ) => {
23
- // FOR TESTING (To be removed)
24
23
const dispatch = useDispatch ( ) ;
25
- const paginatedLeaderboard : LeaderboardRow [ ] = useTypedSelector ( store => store . leaderboard . paginatedUserXp ) ;
26
- let page = 2 ;
27
- let pageSize = 25 ;
28
- useEffect ( ( ) => {
29
- dispatch ( LeaderboardActions . getPaginatedLeaderboardXp ( page , pageSize ) )
30
- console . log ( "TEST" )
31
- } , [ dispatch , page , pageSize ] ) ;
32
-
33
- useEffect ( ( ) => {
34
- console . log ( paginatedLeaderboard ) ;
35
- } , [ paginatedLeaderboard ] )
36
-
37
-
38
-
39
- // Retrieve XP Data from store
40
- const rankedLeaderboard : LeaderboardRow [ ] = useTypedSelector ( store => store . leaderboard . userXp ) ;
41
-
42
- useEffect ( ( ) => {
43
- dispatch ( LeaderboardActions . getAllUsersXp ( ) ) ;
44
- } , [ dispatch ] ) ;
45
24
46
25
// Retrieve contests (For dropdown)
47
26
const contestDetails : LeaderboardContestDetails [ ] = useTypedSelector (
@@ -62,25 +41,6 @@ const OverallLeaderboard: React.FC = () => {
62
41
} ;
63
42
} , [ ] ) ;
64
43
65
- // Display constants
66
- const visibleEntries = useTypedSelector ( store => store . session . topLeaderboardDisplay ) ;
67
- const topX = rankedLeaderboard . slice ( 0 , Number ( visibleEntries ) ) ;
68
-
69
- // Set sample profile pictures (Seeded random)
70
- function convertToRandomNumber ( id : string ) : number {
71
- const str = id . slice ( 1 ) ;
72
- let hash = 0 ;
73
- for ( let i = 0 ; i < str . length ; i ++ ) {
74
- const char = str . charCodeAt ( i ) ;
75
- hash = ( hash << 5 ) - hash + char ;
76
- }
77
- return ( Math . abs ( hash ) % 7 ) + 1 ;
78
- }
79
-
80
- rankedLeaderboard . map ( ( row : LeaderboardRow ) => {
81
- row . avatar = `/assets/Sample_Profile_${ convertToRandomNumber ( row . username ) } .jpg` ;
82
- } ) ;
83
-
84
44
// Define column definitions for ag-Grid
85
45
const columnDefs : ColDef < LeaderboardRow > [ ] = useMemo (
86
46
( ) => [
@@ -132,29 +92,90 @@ const OverallLeaderboard: React.FC = () => {
132
92
[ ]
133
93
) ;
134
94
95
+ const paginatedLeaderboard : { rows : LeaderboardRow [ ] ; userCount : number } = useTypedSelector ( store => store . leaderboard . paginatedUserXp ) ;
96
+ const pageSize = 25 ;
97
+ const visibleEntries = useTypedSelector ( store => store . session . topLeaderboardDisplay ) ?? Number . MAX_SAFE_INTEGER ;
98
+ // const topX = rankedLeaderboard.slice(0, Number(visibleEntries));
99
+
100
+ useEffect ( ( ) => {
101
+ dispatch ( LeaderboardActions . getPaginatedLeaderboardXp ( 1 , pageSize ) )
102
+ } , [ dispatch ] ) ;
103
+
104
+ const latestParamsRef = useRef < any > ( null ) ;
105
+ const dataSourceRef = useRef < IDatasource > ( {
106
+ getRows : async ( params : any ) => {
107
+ const startRow = params . startRow ;
108
+ const endRow = params . endRow ;
109
+
110
+ const pageSize = endRow - startRow ;
111
+ const page = startRow / pageSize + 1
112
+
113
+ dispatch ( LeaderboardActions . getPaginatedLeaderboardXp ( page , pageSize ) ) ;
114
+
115
+ // Params stored to prevent re-rendering
116
+ latestParamsRef . current = params ;
117
+ } ,
118
+ } ) ;
119
+
120
+ useEffect ( ( ) => {
121
+ if (
122
+ latestParamsRef . current &&
123
+ paginatedLeaderboard . rows . length > 0
124
+ ) {
125
+ const { successCallback } = latestParamsRef . current ;
126
+ successCallback ( paginatedLeaderboard . rows , Math . min ( paginatedLeaderboard . userCount , visibleEntries ) ) ;
127
+ latestParamsRef . current = null ;
128
+ }
129
+ } , [ paginatedLeaderboard ] ) ;
130
+
131
+ // Set sample profile pictures (Seeded random)
132
+ function convertToRandomNumber ( id : string ) : number {
133
+ const str = id . slice ( 1 ) ;
134
+ let hash = 0 ;
135
+ for ( let i = 0 ; i < str . length ; i ++ ) {
136
+ const char = str . charCodeAt ( i ) ;
137
+ hash = ( hash << 5 ) - hash + char ;
138
+ }
139
+ return ( Math . abs ( hash ) % 7 ) + 1 ;
140
+ }
141
+
142
+ paginatedLeaderboard . rows . map ( ( row : LeaderboardRow ) => {
143
+ row . avatar = `/assets/Sample_Profile_${ convertToRandomNumber ( row . username ) } .jpg` ;
144
+ } ) ;
145
+
146
+ const top3Leaderboard = useMemo ( ( ) => {
147
+ if ( paginatedLeaderboard . rows . length > 0 ) {
148
+ return paginatedLeaderboard . rows . slice ( 0 , 3 ) ; // Get the top 3 users
149
+ }
150
+ return [ ] ; // Fallback if no data
151
+ } , [ paginatedLeaderboard . rows ] ) ;
152
+
135
153
return (
136
154
< div className = "leaderboard-container" >
137
155
{ /* Top 3 Ranking */ }
138
- < LeaderboardPodium type = "overall" data = { rankedLeaderboard } outputType = { undefined } />
156
+ < LeaderboardPodium type = "overall" data = { top3Leaderboard } outputType = { undefined } />
139
157
140
158
< div className = "buttons-container" >
141
159
{ /* Leaderboard Options Dropdown */ }
142
160
< LeaderboardDropdown contests = { contestDetails } />
143
161
144
162
{ /* Export Button */ }
145
- < LeaderboardExportButton type = "overall" contest = { undefined } data = { rankedLeaderboard } />
163
+ < LeaderboardExportButton type = "overall" contest = { undefined } data = { undefined } />
146
164
</ div >
147
165
148
166
{ /* Leaderboard Table (Replaced with ag-Grid) */ }
149
167
< div className = "ag-theme-alpine" >
150
168
< AgGridReact
151
- rowData = { topX }
152
- columnDefs = { columnDefs }
153
169
pagination = { true }
154
- paginationPageSize = { 25 }
155
170
paginationPageSizeSelector = { [ 25 , 50 , 100 ] }
171
+ columnDefs = { columnDefs }
172
+ rowModelType = "infinite"
173
+ paginationPageSize = { pageSize }
156
174
domLayout = "autoHeight"
157
175
rowHeight = { 60 }
176
+ cacheBlockSize = { pageSize }
177
+ maxBlocksInCache = { 5 }
178
+ datasource = { dataSourceRef . current }
158
179
/>
159
180
</ div >
160
181
</ div >
0 commit comments