"use client"; import { useEffect, useState } from "react"; import { Flag, Trophy } from "lucide-react"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { cn } from "@/lib/utils"; import type { EodDifficulty } from "@/app/(frontend)/minigames/eod/actions"; import type { PresenceParticipant } from "@/hooks/useRealtimePresence"; interface ApiUser { id: number; username?: string | null; displayName?: string | null; payloadDisplayName?: string | null; } interface ApiProfile { id: number; profileTitle?: string | null; user?: ApiUser | number | null; progression?: { minigames?: { eodMinesweeper?: { gamesPlayed?: number | null; wins?: number | null; bestScore?: number | null; xpEarned?: number | null; bestTrainingTime?: number | null; bestPerimeterTime?: number | null; bestSupplyRoadTime?: number | null; bestTrainingFlags?: number | null; bestPerimeterFlags?: number | null; bestSupplyRoadFlags?: number | null; } | null; } | null; } | null; } interface LeaderboardRow { id: number; userId: number | null; name: string; gamesPlayed: number; wins: number; bestScore: number; xpEarned: number; bestTime: number; bestFlags: number; isCurrentUser: boolean; isOutsideTopTen?: boolean; } interface EodLeaderboardProps { refreshKey?: number; currentUserId?: number | string; activeTeams?: PresenceParticipant[]; difficulty: EodDifficulty; onDifficultyChange: (difficulty: EodDifficulty) => void; } function rankClass(index: number) { if (index === 0) return "font-bold text-amber-400"; if (index === 1) return "font-semibold text-slate-300"; if (index === 2) return "font-semibold text-amber-700"; return "text-muted-foreground"; } export function EodLeaderboard({ refreshKey = 0, currentUserId, activeTeams = [], difficulty, onDifficultyChange, }: EodLeaderboardProps) { const [rows, setRows] = useState(null); const [failed, setFailed] = useState(false); useEffect(() => { let cancelled = false; setFailed(false); const difficultyLabel = difficulty === "training" ? "Training" : difficulty === "perimeter" ? "Perimeter" : "SupplyRoad"; const timeField = `progression.minigames.eodMinesweeper.best${difficultyLabel}Time`; const flagsField = `progression.minigames.eodMinesweeper.best${difficultyLabel}Flags`; const params = new URLSearchParams({ sort: `${timeField},${flagsField}`, limit: "100", depth: "1", }); params.set(`where[${timeField}][greater_than]`, "0"); fetch(`/api/profiles?${params.toString()}`) .then((res) => { if (!res.ok) throw new Error("leaderboard fetch failed"); return res.json() as Promise<{ docs?: ApiProfile[] }>; }) .then((data) => { if (cancelled) return; const mapped: LeaderboardRow[] = (data.docs ?? []).map((doc) => { const eod = doc.progression?.minigames?.eodMinesweeper ?? {}; const user = typeof doc.user === "object" && doc.user !== null ? doc.user : null; const name = user?.displayName || doc.profileTitle || user?.username || `Operator #${doc.id}`; return { id: doc.id, userId: user?.id ?? null, name, gamesPlayed: eod.gamesPlayed ?? 0, wins: eod.wins ?? 0, bestScore: eod.bestScore ?? 0, xpEarned: eod.xpEarned ?? 0, bestTime: eod[`best${difficultyLabel}Time` as keyof typeof eod] ?? 0, bestFlags: eod[`best${difficultyLabel}Flags` as keyof typeof eod] ?? 0, isCurrentUser: user ? String(user.id) === String(currentUserId) : false, }; }); const scored = mapped .filter((row) => row.bestTime > 0) .sort((a, b) => a.bestTime - b.bestTime || a.bestFlags - b.bestFlags); const visible = scored.slice(0, 10); const current = mapped.find((row) => row.isCurrentUser); if (current && !visible.some((row) => row.id === current.id)) { visible.push({ ...current, isOutsideTopTen: true }); } setRows(visible); }) .catch(() => { if (!cancelled) setFailed(true); }); return () => { cancelled = true; }; }, [difficulty, refreshKey, currentUserId]); return (

Minefield Clearance Leaderboard

Top 10 ยท fastest clear
{activeTeams.length} defusal teams on site {activeTeams.length > 0 && ( ({activeTeams.map((team) => team.name).join(", ")}) )}
{failed ? (

Could not load the leaderboard.

) : rows === null ? (
) : rows.length === 0 ? (

No clearances logged yet. Take the first sector!

) : (
{rows.map((row, index) => ( ))}
# Operator Games Wins Time XP
{row.isOutsideTopTen ? "-" : index + 1} {row.name} {row.isCurrentUser && ( (you) )} {row.isOutsideTopTen && ( unranked )} {row.userId !== null && activeTeams.some((team) => team.id === row.userId) && ( )} {row.gamesPlayed} {row.wins} {row.bestTime}s {row.bestFlags} {row.xpEarned}
)}
); }