11import 'src/styles/Leaderboard.scss' ;
22
3- import React , { useEffect , useState } from 'react' ;
3+ import React , { useEffect , useMemo , useState } from 'react' ;
4+ import { useDispatch } from 'react-redux' ;
45import { useTypedSelector } from 'src/commons/utils/Hooks' ;
6+ import LeaderboardActions from 'src/features/leaderboard/LeaderboardActions' ;
57import { ContestLeaderboardRow , LeaderboardRow } from 'src/features/leaderboard/LeaderboardTypes' ;
68
79import { Role } from '../../../commons/application/ApplicationTypes' ;
8- import { useDispatch } from 'react-redux' ;
9- import LeaderboardActions from 'src/features/leaderboard/LeaderboardActions' ;
1010
1111type Props = {
12- type : string
13- contest ?: string
14- contestID ?: number
15- }
12+ type : string ;
13+ contest ?: string ;
14+ contestID ?: number ;
15+ } ;
1616
1717const LeaderboardExportButton : React . FC < Props > = ( { type, contest, contestID } ) => {
18-
1918 // Retrieve relevant leaderboard data
20- const [ exportRequested , setExportRequest ] = useState ( false ) ;
19+ const [ exportRequested , setExportRequest ] = useState ( false ) ;
2120 const dispatch = useDispatch ( ) ;
22- const data = ( type == "overall" )
23- ? useTypedSelector ( store => store . leaderboard . userXp )
24- : ( type == "score" )
25- ? useTypedSelector ( store => store . leaderboard . contestScore )
26- : useTypedSelector ( store => store . leaderboard . contestPopularVote ) ;
21+ const selectData = ( type : string ) => {
22+ switch ( type ) {
23+ case 'overall' :
24+ return ( store : { leaderboard : { userXp : any } } ) => store . leaderboard . userXp ;
25+ case 'score' :
26+ return ( store : { leaderboard : { contestScore : any } } ) => store . leaderboard . contestScore ;
27+ default :
28+ return ( store : { leaderboard : { contestPopularVote : any } } ) =>
29+ store . leaderboard . contestPopularVote ;
30+ }
31+ } ;
32+
33+ const selector = useMemo ( ( ) => selectData ( type ) , [ type ] ) ;
34+ const data = useTypedSelector ( selector ) ;
2735
2836 const visibleEntries = Number . MAX_SAFE_INTEGER ;
2937
3038 const onExportClick = ( ) => {
3139 // Dispatch relevant request
32- if ( type == "overall" ) dispatch ( LeaderboardActions . getAllUsersXp ( ) ) ;
33- else if ( type == "score" ) dispatch ( LeaderboardActions . getAllContestScores ( contestID as number , visibleEntries ) ) ;
34- else dispatch ( LeaderboardActions . getAllContestPopularVotes ( contestID as number , visibleEntries ) ) ;
35- setExportRequest ( true )
36- }
40+ if ( type == 'overall' ) dispatch ( LeaderboardActions . getAllUsersXp ( ) ) ;
41+ else if ( type == 'score' )
42+ dispatch ( LeaderboardActions . getAllContestScores ( contestID as number , visibleEntries ) ) ;
43+ else
44+ dispatch ( LeaderboardActions . getAllContestPopularVotes ( contestID as number , visibleEntries ) ) ;
45+ setExportRequest ( true ) ;
46+ } ;
3747
3848 // Return the CSV when requested and data is loaded
3949 useEffect ( ( ) => {
4050 if ( exportRequested ) {
4151 exportCSV ( ) ;
4252 setExportRequest ( false ) ; // Clear request
4353 }
44- } , [ data ] )
54+ } , [ data ] ) ;
4555
4656 const role = useTypedSelector ( store => store . session . role ) ;
4757 const exportCSV = ( ) => {
@@ -52,18 +62,33 @@ const LeaderboardExportButton: React.FC<Props> = ({ type, contest, contestID })
5262 type === 'overall' ? 'XP' : 'Score' ,
5363 type === 'overall' ? 'Achievements' : 'Submission Id'
5464 ] ;
55- const rows = data ?. map ( player => [
56- player . rank ,
57- player . name ,
58- player . username ,
59- type === 'overall' ? ( player as LeaderboardRow ) . xp : ( player as ContestLeaderboardRow ) . score ,
60- type === 'overall'
61- ? ( player as LeaderboardRow ) . achievements
62- : ( player as ContestLeaderboardRow ) . submissionId
63- ] ) ;
65+ const rows = data ?. map (
66+ ( player : {
67+ rank : any ;
68+ name : any ;
69+ username : any ;
70+ xp ?: number ;
71+ avatar ?: string ;
72+ achievements ?: string ;
73+ score ?: number ;
74+ code ?: string ;
75+ submissionId ?: number ;
76+ votingId ?: number ;
77+ } ) => [
78+ player . rank ,
79+ player . name ,
80+ player . username ,
81+ type === 'overall'
82+ ? ( player as LeaderboardRow ) . xp
83+ : ( player as ContestLeaderboardRow ) . score ,
84+ type === 'overall'
85+ ? ( player as LeaderboardRow ) . achievements
86+ : ( player as ContestLeaderboardRow ) . submissionId
87+ ]
88+ ) ;
6489
6590 // Combine headers and rows
66- const csvContent = [ headers . join ( ',' ) , ...rows . map ( row => row . join ( ',' ) ) ] . join ( '\n' ) ;
91+ const csvContent = [ headers . join ( ',' ) , ...rows . map ( ( row : any [ ] ) => row . join ( ',' ) ) ] . join ( '\n' ) ;
6792
6893 const blob = new Blob ( [ csvContent ] , { type : 'text/csv;charset=utf-8;' } ) ;
6994 const link = document . createElement ( 'a' ) ;
0 commit comments