import { useEffect, useState, useCallback } from "react"; import LoadingDisplay from "../components/LoadingDisplay"; import { useAuth } from "../contexts/AuthContext"; import { useNavigate } from "react-router"; import { NavBar } from "../components/NavBar"; import type { SupportedGame} from "../types/game"; import SessionExpiredPopup from "../components/SessionExpiredPopup"; import ScoreDisplay from "../components/displays/GenericScoreDisplay"; import DancerushScoreDisplay from "../components/displays/DancerushScoreDisplay"; import DancearoundScoreDisplay from "../components/displays/DancearoundScoreDisplay"; import DivaScoreDisplay from "../components/displays/DivaScoreDisplay"; import MusicDiverDisplay from "../components/displays/MusicDiverScoreDisplay"; import ReflecBeatScoreDisplay from "../components/displays/ReflecBeatScoreDisplay"; import NostalgiaScoreDisplay from "../components/displays/NostalgiaScoreDisplay"; type SortField = string; type SortDirection = "asc" | "desc"; import { getFilterOptions } from "../types/constants"; const Score = () => { const { user, isLoading, logout } = useAuth(); const navigate = useNavigate(); const [formattedGameName, setFormattedGameName] = useState(""); // eslint-disable-next-line @typescript-eslint/no-explicit-any const [scores, setScores] = useState([]); const [loading, setLoading] = useState(true); const [currentPage, setCurrentPage] = useState(1); const [numPages, setNumPages] = useState(1); const [viewMode, setViewMode] = useState<"cards" | "table">("cards"); const [sortField, setSortField] = useState(""); const [sortDirection, setSortDirection] = useState("asc"); const [requestOrder, setRequestOrder] = useState("timestamp"); const gameName = new URLSearchParams(window.location.search).get("game") || "dancerush"; const handleLogout = async () => { try { await logout(); navigate("/"); } catch (error) { console.error("Logout failed:", error); alert("Network error during logout. Please try again."); } }; useEffect(() => { try{ fetch(import.meta.env.VITE_API_URL + `/supportedGames`) .then(response => response.json()) .then(data => { const game = data.find((game: SupportedGame) => game.internalName === gameName); setFormattedGameName(game ? game.formattedName : gameName); }) .catch(error => console.error(error)); } catch (error) { console.error("Error:", error); alert("Network error. Please try again."); } }, [gameName]); const renderRequestFilterMenu = () => { const filterOptions = getFilterOptions(gameName); return (
{filterOptions.map((option) => ( ))}
); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any const flattenScoreData = (score: any) => { const flat = { ...score, ...score.data }; delete flat.data; delete flat.gameInternalName; return flat; }; const fetchScores = useCallback( async (pageNum: number) => { if (!user) return; setLoading(true); try { const url = new URL(import.meta.env.VITE_API_URL + "/scores"); url.searchParams.append("userId", user.id.toString()); url.searchParams.append("internalGameName", gameName); url.searchParams.append("pageNum", pageNum.toString()); url.searchParams.append("sortKey", requestOrder); url.searchParams.append("direction", "asc"); const response = await fetch(url.toString(), {credentials: 'include'}); if (!response.ok) throw new Error("Failed to fetch scores"); const data = await response.json(); const flattened = data.scores.map(flattenScoreData); setScores(flattened); setNumPages(data.num_pages); setCurrentPage(pageNum); } catch (error) { console.error("Failed to load scores:", error); alert("Failed to load scores. Please refresh the page."); } finally { setLoading(false); } }, [user, gameName, requestOrder], ); const handleDeleteScore = async (scoreId: number) => { if (!user) return; if (!confirm("Are you sure you want to delete this score? This action cannot be undone.")) { return; } try { const url = new URL(import.meta.env.VITE_API_URL + "/scores"); url.searchParams.append("userId", user.id.toString()); url.searchParams.append("internalGameName", gameName); url.searchParams.append("scoreId", scoreId.toString()); const response = await fetch(url.toString(), { method: "DELETE", credentials: "include", }); if (!response.ok) throw new Error("Failed to delete score"); await fetchScores(currentPage); } catch (error) { console.error("Failed to delete score:", error); alert("Failed to delete score. Please try again."); } }; useEffect(() => { if (user) fetchScores(1); }, [user, fetchScores]); const handleSort = (field: SortField) => { if (sortField === field) { setSortDirection(sortDirection === "asc" ? "desc" : "asc"); } else { setSortField(field); setSortDirection("desc"); } }; if (!user) { return ; } if (isLoading || loading) { return ( ); } return (

Your Scores for {formattedGameName}

{/* Filter Menu */}
{renderRequestFilterMenu()}
{(() => { switch (gameName) { case "dancerush": return ( ); case "dancearound": return ( ); case "diva": return ( ); case "musicdiver": return ( ); case "reflecbeat": return ( ); case "nostalgia": return ( ); default: return ( ); } })()} {numPages > 1 && (
{[...Array(numPages)].map((_, i) => ( ))}
)}

Displaying {scores.length} scores • Page {currentPage} of {numPages}

{viewMode === "table" && (

← Swipe horizontally to see more →

)}
); }; export default Score;