99 Typography ,
1010} from "@mui/material" ;
1111import Grid from "@mui/material/Grid" ;
12- import { useEffect , useState , useMemo } from "react" ;
12+ import { useEffect , useState } from "react" ;
1313import { fetchLeaderBoard , searchUsers } from "../../api/api" ;
1414import { fetcherApiCallback } from "../../lib/hooks/useApi" ;
1515import { isExpired , toDateUtc } from "../../lib/date/utils" ;
@@ -24,14 +24,13 @@ import { SubmissionMode } from "../../lib/types/mode";
2424import { useAuthStore } from "../../lib/store/authStore" ;
2525import SubmissionHistorySection from "./components/submission-history/SubmissionHistorySection" ;
2626import LeaderboardSubmit from "./components/LeaderboardSubmit" ;
27- import AiTrendChart from "./components/AiTrendChart" ;
2827import UserTrendChart from "./components/UserTrendChart" ;
2928export const CardTitle = styled ( Typography ) ( ( ) => ( {
3029 fontSize : "1.5rem" ,
3130 fontWeight : "bold" ,
3231} ) ) ;
3332
34- type TabKey = "rankings" | "reference" | "submission" | "ai_trend" ;
33+ type TabKey = "rankings" | "reference" | "submission" ;
3534
3635// Tab accessibility props
3736function a11yProps ( index : number ) {
@@ -70,27 +69,16 @@ export default function Leaderboard() {
7069 const isAuthed = ! ! ( me && me . authenticated ) ;
7170 const userId = me ?. user ?. identity ?? null ;
7271
73- // State for top user (strongest submission) and default GPU type
74- const [ defaultUser , setDefaultUser ] = useState < {
75- userId : string ;
76- username : string ;
77- } | null > ( null ) ;
72+ // State for top users (strongest submissions) and default GPU type
73+ const [ defaultUsers , setDefaultUsers ] = useState <
74+ Array < { userId : string ; username : string } >
75+ > ( [ ] ) ;
7876 const [ defaultGpuType , setDefaultGpuType ] = useState < string | null > ( null ) ;
7977
8078 // Sync tab state with query parameter
8179 const [ searchParams , setSearchParams ] = useSearchParams ( ) ;
8280
83- // Check if AI Trend should be shown
84- const showAiTrend = searchParams . get ( "showAiTrend" ) === "true" ;
85-
86- // Build tab keys dynamically based on showAiTrend
87- const TAB_KEYS : TabKey [ ] = useMemo ( ( ) => {
88- const keys : TabKey [ ] = [ "rankings" , "reference" , "submission" ] ;
89- if ( showAiTrend ) {
90- keys . push ( "ai_trend" ) ;
91- }
92- return keys ;
93- } , [ showAiTrend ] ) ;
81+ const TAB_KEYS : TabKey [ ] = [ "rankings" , "reference" , "submission" ] ;
9482
9583 const initialTabFromUrl = ( ( ) : TabKey => {
9684 const t = ( searchParams . get ( "tab" ) || "" ) . toLowerCase ( ) ;
@@ -116,10 +104,10 @@ export default function Leaderboard() {
116104 if ( id ) call ( id ) ;
117105 } , [ id , call ] ) ;
118106
119- // Fetch top user (strongest submission ) when rankings are available
107+ // Fetch top users (strongest submissions ) when rankings are available
120108 // Select from the GPU with the most unique users
121109 useEffect ( ( ) => {
122- const findTopUser = async ( ) => {
110+ const findTopUsers = async ( ) => {
123111 if ( ! id || ! data ?. rankings ) return ;
124112
125113 const gpuTypes = Object . keys ( data . rankings ) ;
@@ -139,26 +127,35 @@ export default function Leaderboard() {
139127 const mostActiveGpuRankings = data . rankings [ mostActiveGpu ] ;
140128 if ( ! mostActiveGpuRankings || mostActiveGpuRankings . length === 0 ) return ;
141129
142- // The first item is the top user (sorted by score ascending)
143- const topUserName = mostActiveGpuRankings [ 0 ] . user_name ;
144- if ( ! topUserName ) return ;
130+ // Get top 5 users (sorted by score ascending)
131+ const topUserNames = mostActiveGpuRankings
132+ . slice ( 0 , 5 )
133+ . map ( ( r ) => r . user_name )
134+ . filter ( Boolean ) ;
135+
136+ if ( topUserNames . length === 0 ) return ;
145137
146138 try {
147- // Search for the user by username to get their user_id
148- const result = await searchUsers ( id , topUserName , 1 ) ;
149- if ( result . users && result . users . length > 0 ) {
150- const foundUser = result . users [ 0 ] ;
151- setDefaultUser ( {
152- userId : foundUser . user_id ,
153- username : foundUser . username ,
154- } ) ;
155- }
139+ // Search for each user by username to get their user_id
140+ const userPromises = topUserNames . map ( ( userName : string ) =>
141+ searchUsers ( id , userName , 1 )
142+ ) ;
143+ const results = await Promise . all ( userPromises ) ;
144+
145+ const foundUsers = results
146+ . filter ( ( result ) => result . users && result . users . length > 0 )
147+ . map ( ( result ) => ( {
148+ userId : result . users [ 0 ] . user_id ,
149+ username : result . users [ 0 ] . username ,
150+ } ) ) ;
151+
152+ setDefaultUsers ( foundUsers ) ;
156153 } catch ( err ) {
157- console . error ( "Failed to fetch top user :" , err ) ;
154+ console . error ( "Failed to fetch top users :" , err ) ;
158155 }
159156 } ;
160157
161- findTopUser ( ) ;
158+ findTopUsers ( ) ;
162159 } , [ id , data ?. rankings ] ) ;
163160
164161 if ( loading ) return < Loading /> ;
@@ -213,21 +210,27 @@ export default function Leaderboard() {
213210 < Tab label = "Rankings" value = "rankings" { ...a11yProps ( 0 ) } />
214211 < Tab label = "Reference" value = "reference" { ...a11yProps ( 1 ) } />
215212 < Tab label = "Submission" value = "submission" { ...a11yProps ( 2 ) } />
216- { showAiTrend && (
217- < Tab label = "AI Trend" value = "ai_trend" { ...a11yProps ( 3 ) } />
218- ) }
219213 </ Tabs >
220214 </ Box >
221215
222216 { /* Ranking Tab */ }
223217 < TabPanel value = { tab } tabKey = "rankings" >
224218 < Box >
225219 { Object . entries ( data . rankings ) . length > 0 ? (
226- < RankingsList
227- rankings = { data . rankings }
228- leaderboardId = { id }
229- deadline = { data . deadline }
230- />
220+ < >
221+ < RankingsList
222+ rankings = { data . rankings }
223+ leaderboardId = { id }
224+ deadline = { data . deadline }
225+ />
226+ < Box sx = { { my : 4 , borderTop : 1 , borderColor : "divider" } } />
227+ < Card >
228+ < CardContent >
229+ < CardTitle fontWeight = "bold" > Performance Trend</ CardTitle >
230+ < UserTrendChart leaderboardId = { id ! } defaultUsers = { defaultUsers } defaultGpuType = { defaultGpuType } rankings = { data . rankings } />
231+ </ CardContent >
232+ </ Card >
233+ </ >
231234 ) : (
232235 < Box display = "flex" flexDirection = "column" alignItems = "center" >
233236 < Typography variant = "h6" fontWeight = "bold" >
@@ -305,25 +308,6 @@ export default function Leaderboard() {
305308 ) }
306309 </ TabPanel >
307310
308- { /* AI Trend Tab - only shown when showAiTrend=true */ }
309- { showAiTrend && (
310- < TabPanel value = { tab } tabKey = "ai_trend" >
311- < Card >
312- < CardContent >
313- < CardTitle fontWeight = "bold" >
314- AI Model Performance Trend
315- </ CardTitle >
316- < AiTrendChart leaderboardId = { id ! } rankings = { data . rankings } />
317- </ CardContent >
318- </ Card >
319- < Card sx = { { mt : 2 } } >
320- < CardContent >
321- < CardTitle fontWeight = "bold" > User Performance Trend</ CardTitle >
322- < UserTrendChart leaderboardId = { id ! } defaultUser = { defaultUser } defaultGpuType = { defaultGpuType } />
323- </ CardContent >
324- </ Card >
325- </ TabPanel >
326- ) }
327311 </ Box >
328312 </ ConstrainedContainer >
329313 ) ;
0 commit comments