import { useState } from "react"; import { Link } from "react-router"; import { ArrowUp, ArrowDown, ArrowUpDown } from "lucide-react"; import { Card, CardContent } from "~/components/ui/card"; import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "~/components/ui/table"; import { Badge } from "~/components/ui/badge"; interface TeamScoreBreakdownProps { leagueId: string; seasonId: string; numTeams: number; breakdown: { team: { id: string; name: string; } | null; picks: Array<{ pickNumber: number; round: number; participant: { id: string; name: string; sport: string; sportsSeasonId: string; }; finalPosition: number | null; points: number; projectedPoints: number | null; isComplete: boolean; isPartialScore: boolean; }>; actualPoints: number; projectedPoints: number; completedCount: number; totalCount: number; }; standing: { currentRank: number; } | null; } type SortColumn = "pick" | "points" | "sport" | "participant"; type SortDirection = "asc" | "desc"; function SortIndicator({ column, sortColumn, sortDirection }: { column: SortColumn; sortColumn: SortColumn; sortDirection: SortDirection }) { if (sortColumn !== column) return ; return sortDirection === "asc" ? : ; } function SortableHeader({ column, label, sortColumn, sortDirection, onSort, className }: { column: SortColumn; label: string; sortColumn: SortColumn; sortDirection: SortDirection; onSort: (column: SortColumn) => void; className?: string; }) { return ( ); } const cmp = (a: string, b: string) => a.localeCompare(b, undefined, { sensitivity: "base" }); function sortPicks( picks: TeamScoreBreakdownProps["breakdown"]["picks"], sortColumn: SortColumn, sortDirection: SortDirection, ) { const dir = sortDirection === "asc" ? 1 : -1; return picks.toSorted((a, b) => { if (sortColumn === "pick") { return (a.pickNumber - b.pickNumber) * dir; } if (sortColumn === "sport") { const sportCmp = cmp(a.participant.sport, b.participant.sport) * dir; if (sportCmp !== 0) return sportCmp; return cmp(a.participant.name, b.participant.name) * dir; } if (sortColumn === "participant") { return cmp(a.participant.name, b.participant.name) * dir; } // points: sort by actual first, then projected const pointsDiff = a.points - b.points; if (pointsDiff !== 0) return pointsDiff * dir; const aProjected = a.projectedPoints ?? 0; const bProjected = b.projectedPoints ?? 0; return (aProjected - bProjected) * dir; }); } /** * Display detailed team score breakdown with all drafted participants * Phase 4.3: Team breakdown pages */ export function TeamScoreBreakdown({ leagueId, seasonId, numTeams, breakdown, standing, }: TeamScoreBreakdownProps) { const [sortColumn, setSortColumn] = useState("pick"); const [sortDirection, setSortDirection] = useState("asc"); if (!breakdown.team) { return (
Team not found
); } const remaining = breakdown.totalCount - breakdown.completedCount; function handleSort(column: SortColumn) { if (sortColumn === column) { setSortDirection(sortDirection === "asc" ? "desc" : "asc"); } else { setSortColumn(column); setSortDirection(column === "points" ? "desc" : "asc"); } } const allPicks = sortPicks(breakdown.picks, sortColumn, sortDirection); return (
{/* Header */}

{breakdown.team.name}

Team Score Breakdown

{breakdown.actualPoints.toFixed(2)}
Actual Points
{breakdown.projectedPoints > breakdown.actualPoints && (
{breakdown.projectedPoints.toFixed(2)} projected
)} {remaining > 0 && (
{remaining} participant{remaining !== 1 ? "s" : ""} remaining
)} {standing && ( Rank #{standing.currentRank} )}
{/* All picks — single flat table */} Position {allPicks.map((pick) => ( {numTeams > 0 ? `${pick.round}.${String(pick.pickNumber - (pick.round - 1) * numTeams).padStart(2, "0")}` : `#${pick.pickNumber}`} (#{pick.pickNumber}) {pick.participant.sport} {pick.participant.name} {pick.isComplete && !pick.isPartialScore ? ( (pick.finalPosition ?? 0) === 0 ? ( Did Not Score ) : ( ) ) : ( Pending )} {pick.isComplete && !pick.isPartialScore ? ( {pick.points > 0 ? pick.points.toFixed(2) : "0.00"} ) : (
{pick.points.toFixed(2)} {pick.projectedPoints !== null && ( {pick.projectedPoints.toFixed(2)} )}
)}
))}
{/* Navigation */}
← Back to Standings
); } /** * Display placement badge with color coding */ function PlacementBadge({ position }: { position: number }) { const badges: Record = { 1: { label: "1st", className: "bg-amber-accent hover:bg-amber-accent/80 text-background" }, 2: { label: "2nd", className: "bg-muted hover:bg-muted/80 text-muted-foreground" }, 3: { label: "3rd", className: "bg-coral-accent hover:bg-coral-accent/80 text-background" }, 4: { label: "4th", className: "bg-electric/20 hover:bg-electric/30 text-electric" }, 5: { label: "5th", className: "bg-purple-500/20 hover:bg-purple-500/30 text-purple-400" }, 6: { label: "6th", className: "bg-emerald-500/20 hover:bg-emerald-500/30 text-emerald-400" }, 7: { label: "7th", className: "bg-pink-500/20 hover:bg-pink-500/30 text-pink-400" }, 8: { label: "8th", className: "bg-indigo-500/20 hover:bg-indigo-500/30 text-indigo-400" }, }; const badge = badges[position] || { label: `${position}th`, className: "" }; return ( {badge.label} ); }