Open-FinLLM-Leaderboard
/
frontend
/src
/pages
/LeaderboardPage
/components
/Leaderboard
/hooks
/useLeaderboardData.js
| import { useMemo, useRef, useState } from "react"; | |
| import { useQuery, useQueryClient } from "@tanstack/react-query"; | |
| import { useSearchParams } from "react-router-dom"; | |
| import { useLeaderboard } from "../context/LeaderboardContext"; | |
| import { useDataProcessing } from "../components/Table/hooks/useDataProcessing"; | |
| const CACHE_KEY = "leaderboardData"; | |
| const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes | |
| export const useLeaderboardData = () => { | |
| const queryClient = useQueryClient(); | |
| const [searchParams] = useSearchParams(); | |
| const isInitialLoadRef = useRef(true); | |
| const { data, isLoading, error } = useQuery({ | |
| queryKey: ["leaderboard"], | |
| queryFn: async () => { | |
| try { | |
| const cachedData = localStorage.getItem(CACHE_KEY); | |
| if (cachedData) { | |
| const { data: cached, timestamp } = JSON.parse(cachedData); | |
| const age = Date.now() - timestamp; | |
| if (age < CACHE_DURATION) { | |
| return cached; | |
| } | |
| } | |
| const response = await fetch("/api/leaderboard/formatted"); | |
| if (!response.ok) { | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| } | |
| const newData = await response.json(); | |
| localStorage.setItem( | |
| CACHE_KEY, | |
| JSON.stringify({ | |
| data: newData, | |
| timestamp: Date.now(), | |
| }) | |
| ); | |
| return newData; | |
| } catch (error) { | |
| console.error("Detailed error:", error); | |
| throw error; | |
| } | |
| }, | |
| staleTime: CACHE_DURATION, | |
| cacheTime: CACHE_DURATION * 2, | |
| refetchOnWindowFocus: false, | |
| enabled: isInitialLoadRef.current || !!searchParams.toString(), | |
| }); | |
| useMemo(() => { | |
| if (data && isInitialLoadRef.current) { | |
| isInitialLoadRef.current = false; | |
| } | |
| }, [data]); | |
| return { | |
| data, | |
| isLoading, | |
| error, | |
| refetch: () => queryClient.invalidateQueries(["leaderboard"]), | |
| }; | |
| }; | |
| export const useLeaderboardProcessing = () => { | |
| const { state, actions } = useLeaderboard(); | |
| const [sorting, setSorting] = useState([ | |
| { id: "model.average_score", desc: true }, | |
| ]); | |
| const memoizedData = useMemo(() => state.models, [state.models]); | |
| const memoizedFilters = useMemo( | |
| () => ({ | |
| search: state.filters.search, | |
| precisions: state.filters.precisions, | |
| types: state.filters.types, | |
| paramsRange: state.filters.paramsRange, | |
| booleanFilters: state.filters.booleanFilters, | |
| isOfficialProviderActive: state.filters.isOfficialProviderActive, | |
| }), | |
| [ | |
| state.filters.search, | |
| state.filters.precisions, | |
| state.filters.types, | |
| state.filters.paramsRange, | |
| state.filters.booleanFilters, | |
| state.filters.isOfficialProviderActive, | |
| ] | |
| ); | |
| const { | |
| table, | |
| minAverage, | |
| maxAverage, | |
| getColorForValue, | |
| processedData, | |
| filteredData, | |
| columns, | |
| columnVisibility, | |
| } = useDataProcessing( | |
| memoizedData, | |
| memoizedFilters.search, | |
| memoizedFilters.precisions, | |
| memoizedFilters.types, | |
| memoizedFilters.paramsRange, | |
| memoizedFilters.booleanFilters, | |
| sorting, | |
| state.display.rankingMode, | |
| state.display.averageMode, | |
| state.display.visibleColumns, | |
| state.display.scoreDisplay, | |
| state.pinnedModels, | |
| actions.togglePinnedModel, | |
| setSorting, | |
| memoizedFilters.isOfficialProviderActive | |
| ); | |
| return { | |
| table, | |
| minAverage, | |
| maxAverage, | |
| getColorForValue, | |
| processedData, | |
| filteredData, | |
| columns, | |
| columnVisibility, | |
| loading: state.loading, | |
| error: state.error, | |
| }; | |
| }; | |