"use client"; import { useEffect, useState } from "react"; import { Trophy } from "lucide-react"; import { cn } from "@/lib/utils"; 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?: { flappyBird?: { gamesPlayed?: number | null; totalPasses?: number | null; bestScore?: number | null; xpEarned?: number | null; } | null; } | null; } | null; } interface LeaderboardRow { id: number; userId: number | null; name: string; gamesPlayed: number; totalPasses: number; bestScore: number; xpEarned: number; isCurrentUser: boolean; isOutsideTopTen?: boolean; } interface FlappyLeaderboardProps { refreshKey?: number; currentUserId?: number | string; activePilots?: PresenceParticipant[]; } 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 FlappyLeaderboard({ refreshKey = 0, currentUserId, activePilots = [] }: FlappyLeaderboardProps) { const [rows, setRows] = useState(null); const [failed, setFailed] = useState(false); useEffect(() => { let cancelled = false; setFailed(false); const params = new URLSearchParams({ sort: "-progression.minigames.flappyBird.bestScore", // Fetch enough profiles to keep the current pilot visible even when // they have not completed a scored run yet. limit: "100", depth: "1", }); 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 flappy = doc.progression?.minigames?.flappyBird ?? {}; const user = typeof doc.user === "object" && doc.user !== null ? doc.user : null; const name = user?.displayName || doc.profileTitle || user?.username || `Pilot #${doc.id}`; return { id: doc.id, userId: user?.id ?? null, name, gamesPlayed: flappy.gamesPlayed ?? 0, totalPasses: flappy.totalPasses ?? 0, bestScore: flappy.bestScore ?? 0, xpEarned: flappy.xpEarned ?? 0, isCurrentUser: user ? String(user.id) === String(currentUserId) : false, }; }); const scored = mapped.filter((row) => row.bestScore > 0); 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; }; }, [refreshKey, currentUserId]); return (

Flight Simulator Leaderboard

Top 10 ยท best run (bird-free)
{activePilots.length}{" "} {activePilots.length === 1 ? "pilot is" : "pilots are"} flying now {activePilots.length > 0 && ( ({activePilots.map((pilot) => pilot.name).join(", ")}) )}
{failed ? (

Could not load the leaderboard.

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

No pilots on the board yet. Be the first to pass a pipe!

) : ( {rows.map((row, i) => ( ))}
# Pilot Games Passes Best XP
{row.isOutsideTopTen ? "-" : i + 1} {row.name} {row.isCurrentUser && ( (you) )} {row.isOutsideTopTen && ( unranked )} {row.userId !== null && activePilots.some((pilot) => pilot.id === row.userId) && ( )} {row.gamesPlayed} {row.totalPasses} {row.bestScore} {row.xpEarned}
)}
); }