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}
))}
);
}