"use client"; import { useMemo, useState } from "react"; import type { FanProfile, LeaderboardEntry, PassportStats } from "../../types/passport"; import { formatCompactNumber } from "../../utils/passportMetrics"; import MetricCard from "../shared/MetricCard"; import StatusPill from "../shared/StatusPill"; interface LeaderboardScreenProps { leaderboard: LeaderboardEntry[]; profile: FanProfile; stats: PassportStats; } type LeaderboardScope = "global" | "country" | "friends"; export default function LeaderboardScreen({ leaderboard, profile, stats, }: LeaderboardScreenProps) { const [scope, setScope] = useState("global"); const rankedEntries = useMemo(() => { const hydrated = leaderboard.map((entry) => entry.isCurrentUser ? { ...entry, displayName: profile.displayName, country: profile.country, avatarEmoji: profile.avatarEmoji, points: stats.totalScore, badges: stats.unlockedAchievements, streakDays: stats.currentStreak, } : entry, ); const scoped = scope === "country" ? hydrated.filter((entry) => entry.country === profile.country || entry.isCurrentUser) : scope === "friends" ? hydrated.filter((entry) => entry.isCurrentUser || entry.rank <= 6) : hydrated; return [...scoped] .sort((a, b) => b.points - a.points) .map((entry, index) => ({ ...entry, rank: index + 1 })); }, [leaderboard, profile.avatarEmoji, profile.country, profile.displayName, scope, stats]); const currentUser = rankedEntries.find((entry) => entry.isCurrentUser); return (

Global leaderboard

Compete with fans worldwide.

Leaderboards make collections social: global ranking, country ranking, friend slices, streak bragging rights, and sponsor-ready seasonal competitions.

{(["global", "country", "friends"] as const).map((nextScope) => ( ))}

Live mock ranking

{scope === "global" ? "Global top fans" : scope === "country" ? "Country table" : "Friend race"}

Updates with your actions
{rankedEntries.map((entry) => { const movement = entry.movement === 0 ? "โ€”" : entry.movement > 0 ? `โ†‘ ${entry.movement}` : `โ†“ ${Math.abs(entry.movement)}`; return (
#{entry.rank}
{entry.displayName}

{entry.handle} ยท {entry.country} ยท {entry.streakDays} day streak

{formatCompactNumber(entry.points)}

{entry.badges} badges ยท {movement}

); })}
); }