From aba0d4ba57283dcbc42b5d79b71e2bfcda3b7936 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 12 Sep 2024 12:47:21 +0100 Subject: [PATCH] load initial scores server sided to prevent flashing --- src/app/(pages)/player/[...slug]/page.tsx | 3 +- src/common/data-fetcher/impl/beatsaver.ts | 4 +- src/components/player/player-data.tsx | 6 +- src/components/player/player-scores.tsx | 67 ++++++++++------------- 4 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/app/(pages)/player/[...slug]/page.tsx b/src/app/(pages)/player/[...slug]/page.tsx index 6cae418..0eb59fe 100644 --- a/src/app/(pages)/player/[...slug]/page.tsx +++ b/src/app/(pages)/player/[...slug]/page.tsx @@ -43,6 +43,7 @@ export default async function Search({ params: { slug } }: Props) { const sort: ScoreSort = (slug[1] as ScoreSort) || "recent"; // The sorting method const page = parseInt(slug[2]) || 1; // The page number const player = await scoresaberFetcher.lookupPlayer(id, false); + const scores = await scoresaberFetcher.lookupPlayerScores(id, sort, page); if (player == undefined) { // Invalid player id @@ -51,7 +52,7 @@ export default async function Search({ params: { slug } }: Props) { return (
- +
); } diff --git a/src/common/data-fetcher/impl/beatsaver.ts b/src/common/data-fetcher/impl/beatsaver.ts index f9eb11e..14bea99 100644 --- a/src/common/data-fetcher/impl/beatsaver.ts +++ b/src/common/data-fetcher/impl/beatsaver.ts @@ -18,11 +18,12 @@ class BeatSaverFetcher extends DataFetcher { * @returns the map that match the query, or undefined if no map were found */ async getMapBsr(query: string, useProxy = true): Promise { - this.log(`Looking up the bsr for the map with hash ${query}...`); + this.log(`Looking up the bsr for map hash ${query}...`); const map = await db.beatSaverMaps.get(query); // The map is cached if (map != undefined) { + this.log(`Found cached bsr ${map.bsr} for map hash ${query}`); return map.bsr; } @@ -42,6 +43,7 @@ class BeatSaverFetcher extends DataFetcher { hash: query, bsr: bsr, }); + this.log(`Looked up bsr ${bsr} for map hash ${query}`); return bsr; } } diff --git a/src/components/player/player-data.tsx b/src/components/player/player-data.tsx index 01effd3..96383de 100644 --- a/src/components/player/player-data.tsx +++ b/src/components/player/player-data.tsx @@ -3,6 +3,7 @@ import { scoresaberFetcher } from "@/common/data-fetcher/impl/scoresaber"; import { ScoreSort } from "@/common/data-fetcher/sort"; import ScoreSaberPlayer from "@/common/data-fetcher/types/scoresaber/scoresaber-player"; +import ScoreSaberPlayerScoresPage from "@/common/data-fetcher/types/scoresaber/scoresaber-player-scores-page"; import { useQuery } from "@tanstack/react-query"; import PlayerHeader from "./player-header"; import PlayerRankChart from "./player-rank-chart"; @@ -12,11 +13,12 @@ const REFRESH_INTERVAL = 5 * 60 * 1000; // 5 minutes type Props = { initalPlayerData: ScoreSaberPlayer; + initialScoreData?: ScoreSaberPlayerScoresPage; sort: ScoreSort; page: number; }; -export default function PlayerData({ initalPlayerData, sort, page }: Props) { +export default function PlayerData({ initalPlayerData, initialScoreData, sort, page }: Props) { let player = initalPlayerData; const { data, isLoading, isError } = useQuery({ queryKey: ["player", player.id], @@ -36,7 +38,7 @@ export default function PlayerData({ initalPlayerData, sort, page }: Props) { )} - + ); } diff --git a/src/components/player/player-scores.tsx b/src/components/player/player-scores.tsx index 1e48ea6..646ec74 100644 --- a/src/components/player/player-scores.tsx +++ b/src/components/player/player-scores.tsx @@ -15,70 +15,63 @@ import { Button } from "../ui/button"; import Score from "./score/score"; type Props = { + initialScoreData?: ScoreSaberPlayerScoresPage; player: ScoreSaberPlayer; sort: ScoreSort; page: number; }; -export default function PlayerScores({ player, sort, page }: Props) { +export default function PlayerScores({ initialScoreData, player, sort, page }: Props) { const { width } = useWindowDimensions(); const controls = useAnimation(); const [currentSort, setCurrentSort] = useState(sort); const [currentPage, setCurrentPage] = useState(page); - const [previousScores, setPreviousScores] = useState(); - const { data, isError, isLoading, refetch } = useQuery({ + const { + data: scores, + isError, + isLoading, + refetch, + } = useQuery({ queryKey: ["playerScores", player.id, currentSort, currentPage], queryFn: () => scoresaberFetcher.lookupPlayerScores(player.id, currentSort, currentPage), - staleTime: 30 * 1000, // Data will be cached for 30 seconds + staleTime: 30 * 1000, // Cache data for 30 seconds + initialData: initialScoreData, }); const handleAnimation = useCallback(() => { - controls.set({ - x: -50, - opacity: 0, - }); - controls.start({ - x: 0, - opacity: 1, - transition: { duration: 0.25 }, - }); + controls.set({ x: -50, opacity: 0 }); + controls.start({ x: 0, opacity: 1, transition: { duration: 0.25 } }); }, [controls]); useEffect(() => { - if (data == undefined) { - return; + if (scores) { + handleAnimation(); } - setPreviousScores(data); - handleAnimation(); - }, [data, handleAnimation]); + }, [scores, handleAnimation]); useEffect(() => { - // Update URL and refetch data when currentSort or currentPage changes const newUrl = `/player/${player.id}/${currentSort}/${currentPage}`; window.history.replaceState({ ...window.history.state, as: newUrl, url: newUrl }, "", newUrl); refetch(); }, [currentSort, currentPage, refetch, player.id]); - /** - * Updates the current sort and resets the page to 1 - */ - function handleSortChange(newSort: ScoreSort) { + const handleSortChange = (newSort: ScoreSort) => { if (newSort !== currentSort) { setCurrentSort(newSort); - setCurrentPage(1); // Reset the page + setCurrentPage(1); // Reset page to 1 on sort change } - } + }; - if (previousScores === undefined) { - return null; + if (scores === undefined) { + return undefined; } if (isError) { return ( -

Oopsies!

+

Oopsies! Something went wrong.

); } @@ -86,20 +79,20 @@ export default function PlayerScores({ player, sort, page }: Props) { return (
- {Object.keys(ScoreSort).map((sort, index) => ( + {Object.values(ScoreSort).map((sortOption) => ( ))}
- {previousScores.playerScores.map((playerScore, index) => ( + {scores.playerScores.map((playerScore, index) => ( ))}
@@ -108,11 +101,9 @@ export default function PlayerScores({ player, sort, page }: Props) { { - setCurrentPage(newPage); - }} + onPageChange={setCurrentPage} />
);