import { Link } from "react-router"; import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "~/components/ui/table"; import { Badge } from "~/components/ui/badge"; import { type TeamStanding } from "~/types/standings"; interface StandingsTableProps { standings: TeamStanding[]; leagueId: string; seasonId: string; showPlacementBreakdown?: boolean; } /** * Display team standings with ranking, points, and placement breakdown * Phase 4.1: Enhanced standings table with tiebreakers * Phase 4.3: Added clickable links to team breakdown pages */ export function StandingsTable({ standings, leagueId, seasonId, showPlacementBreakdown = true, }: StandingsTableProps) { return (
Rank Team Points Projected {showPlacementBreakdown && ( Placements )} Remaining {standings.length === 0 ? ( No standings data available ) : ( standings.map((standing) => (
{standing.rankChange !== 0 && ( )}
{standing.teamName} {standing.actualPoints !== null && standing.actualPoints !== undefined ? standing.actualPoints.toFixed(1) : standing.totalPoints.toFixed(1)} {standing.projectedPoints !== null && standing.projectedPoints !== undefined ? (
{standing.projectedPoints.toFixed(1)} {standing.participantsRemaining > 0 && ( +{(standing.projectedPoints - (standing.actualPoints ?? standing.totalPoints)).toFixed(1)} EV )}
) : ( - )}
{showPlacementBreakdown && ( )} {standing.participantsRemaining > 0 ? ( {standing.participantsRemaining} remaining ) : ( Complete )}
)) )}
); } /** * Display rank badge with special styling for top 3 */ function RankBadge({ rank }: { rank: number }) { if (rank === 1) { return ( 🏆 1st ); } if (rank === 2) { return ( 🥈 2nd ); } if (rank === 3) { return ( 🥉 3rd ); } return ( {rank} ); } /** * Show movement indicator (up/down arrow) */ function MovementIndicator({ change }: { change: number }) { if (change > 0) { return ( ↑{change} ); } if (change < 0) { return ( ↓{Math.abs(change)} ); } return null; } /** * Display placement breakdown showing counts for each placement (1st-8th) */ function PlacementBreakdown({ placements, }: { placements: { first: number; second: number; third: number; fourth: number; fifth: number; sixth: number; seventh: number; eighth: number; }; }) { const items = [ { label: "1st", count: placements.first, color: "text-yellow-600" }, { label: "2nd", count: placements.second, color: "text-gray-500" }, { label: "3rd", count: placements.third, color: "text-orange-600" }, { label: "4th", count: placements.fourth, color: "text-blue-600" }, { label: "5th", count: placements.fifth, color: "text-purple-600" }, { label: "6th", count: placements.sixth, color: "text-green-600" }, { label: "7th", count: placements.seventh, color: "text-pink-600" }, { label: "8th", count: placements.eighth, color: "text-indigo-600" }, ]; // Only show placements that have counts > 0 const nonZero = items.filter((item) => item.count > 0); if (nonZero.length === 0) { return None yet; } return (
{nonZero.map((item) => ( {item.label}×{item.count} ))}
); }