"use client"; import { ScoresaberLeaderboardInfo } from "@/schemas/scoresaber/leaderboard"; import { ScoreSaberAPI } from "@/utils/scoresaber/api"; import Image from "next/image"; import { ScoresaberScore } from "@/schemas/scoresaber/score"; import { formatNumber } from "@/utils/numberUtils"; import { scoresaberDifficultyNumberToName } from "@/utils/songUtils"; import { StarIcon } from "@heroicons/react/20/solid"; import Link from "next/link"; import { useCallback, useEffect, useState } from "react"; import Card from "../Card"; import Container from "../Container"; import Pagination from "../Pagination"; import LeaderboardScore from "./LeaderboardScore"; type LeaderboardProps = { id: string; page: number; }; type PageInfo = { loading: boolean; page: number; totalPages: number; scores: ScoresaberScore[]; }; export default function Leaderboard({ id, page }: LeaderboardProps) { const [mounted, setMounted] = useState(false); const [leaderboardData, setLeaderboardData] = useState( undefined as ScoresaberLeaderboardInfo | undefined, ); const [leaderboardScoredsData, setLeaderboardScoredsData] = useState({ loading: true, page: page, totalPages: 1, scores: [], }); const fetchLeaderboard = useCallback(async () => { const leaderboard = await ScoreSaberAPI.fetchLeaderboardInfo(id); setLeaderboardData(leaderboard); }, [id]); const updateScoresPage = useCallback( async (page: number) => { const leaderboardScores = await ScoreSaberAPI.fetchLeaderboardScores( id, page, ); if (!leaderboardScores) { return; } setLeaderboardScoredsData({ ...leaderboardScoredsData, scores: leaderboardScores.scores, totalPages: leaderboardScores.pageInfo.totalPages, loading: false, page: page, }); window.history.pushState({}, "", `/leaderboard/${id}/${page}`); console.log(`Switched page to ${page}`); }, [id, leaderboardScoredsData], ); useEffect(() => { if (mounted) return; fetchLeaderboard(); updateScoresPage(1); setMounted(true); }, [fetchLeaderboard, mounted, updateScoresPage]); if (!leaderboardData) { return null; } const leaderboardScores = leaderboardScoredsData.scores; const { coverImage, songName, songSubName, levelAuthorName, stars, plays, dailyPlays, ranked, difficulties, } = leaderboardData; return (
Song Cover

{songName}

{songSubName}

Mapped By: {levelAuthorName}

Status: {ranked ? "Ranked" : "Unranked"}

Stars:

{stars}

Plays: {formatNumber(plays)} ({dailyPlays} in the last day)

{difficulties.map((diff) => { return (
{scoresaberDifficultyNumberToName(diff.difficulty)}
); })}
{leaderboardScores?.map((score, index) => { return (
); })}
{/* Pagination */}
{ updateScoresPage(page); }} />
); }