"use client"; import { useState } from "react"; import { UserStat } from "@/lib/types"; type SortKey = "totalBytes" | "requestCount" | "avgGB" | "plays" | "watchHours"; interface LeaderboardTableProps { users: UserStat[]; hasTautulli: boolean; } function formatGB(gb: number): string { return gb >= 1000 ? `${(gb / 1000).toFixed(2)} TB` : `${gb.toFixed(1)} GB`; } function formatHours(h: number): string { if (h >= 1000) return `${(h / 1000).toFixed(1)}k h`; return `${h.toFixed(0)}h`; } function Rank({ rank, total }: { rank: number | null; total: number }) { if (rank === null) return ; return ( #{rank}/{total} ); } function SortChevrons({ active, asc }: { active: boolean; asc: boolean }) { return ( {active ? ( {asc ? : } ) : ( )} ); } export default function LeaderboardTable({ users, hasTautulli, }: LeaderboardTableProps) { const [sortKey, setSortKey] = useState("totalBytes"); const [sortAsc, setSortAsc] = useState(false); const sorted = [...users].sort((a, b) => { const av = (a[sortKey] ?? -1) as number; const bv = (b[sortKey] ?? -1) as number; return sortAsc ? av - bv : bv - av; }); function handleSort(key: SortKey) { if (key === sortKey) setSortAsc((p) => !p); else { setSortKey(key); setSortAsc(false); } } function Th({ label, col, right, }: { label: string; col?: SortKey; right?: boolean; }) { const active = col === sortKey; return ( handleSort(col) : undefined} className={[ "group py-3 px-4 text-xs font-semibold uppercase tracking-wider whitespace-nowrap select-none", right ? "text-right" : "text-left", col ? "cursor-pointer" : "", active ? "text-yellow-400" : "text-slate-500 hover:text-slate-300", ].join(" ")} > {label} {col && } ); } const total = users.length; return (
{sorted.map((user, idx) => ( {/* Row index */} {/* User */} {/* Requests */} {/* Storage */} {/* Avg / Request */} {/* Plays */} {hasTautulli && ( )} {/* Watch Time */} {hasTautulli && ( )} ))}
{hasTautulli && } {hasTautulli && }
{idx + 1}
{user.displayName}
{user.email}
{user.requestCount.toLocaleString()}
{formatGB(user.totalGB)}
{user.requestCount > 0 ? formatGB(user.avgGB) : "—"}
{user.plays !== null ? user.plays.toLocaleString() : "—"}
{user.watchHours !== null && user.watchHours > 0 ? formatHours(user.watchHours) : user.watchHours === 0 ? "0h" : "—"}
); }