import { format } from "date-fns"; import { Calendar, CheckCircle2, ChevronRight, Clock, Layers, ListOrdered, SquareStack, Trophy } from "lucide-react"; import { Link } from "react-router"; import { Badge } from "~/components/ui/badge"; import { Button } from "~/components/ui/button"; import { Card, CardContent, CardHeader } from "~/components/ui/card"; import { GradientIcon } from "~/components/ui/GradientIcon"; import type { UpcomingParticipantEvent } from "~/models/scoring-event"; // ─── Types ──────────────────────────────────────────────────────────────────── export interface DraftedParticipantSummary { id: string; name: string; /** Fantasy league points earned (position → scoring rules). null = no result yet. */ earnedPoints: number | null; /** Accumulated qualifying points for qualifying_points sports. null for other sports. */ currentQP: number | null; } export interface SportSeasonSummaryItem { id: string; sportName: string; seasonName: string; status: "upcoming" | "active" | "completed"; scoringPattern?: string | null; upcomingParticipantEvents?: UpcomingParticipantEvent[]; /** All participants the current user drafted for this sport, with points data. */ draftedParticipants?: DraftedParticipantSummary[]; } export interface SportsSeasonsSummaryProps { leagueId: string; sportsSeasons: SportSeasonSummaryItem[]; /** Link to the full sports seasons list, if one exists. */ allSeasonsHref?: string; } // ─── Helpers ────────────────────────────────────────────────────────────────── const STATUS_ORDER: Record = { active: 0, upcoming: 1, completed: 2, }; function sortedByStatus(items: SportSeasonSummaryItem[]): SportSeasonSummaryItem[] { return [...items].toSorted((a, b) => { const diff = STATUS_ORDER[a.status] - STATUS_ORDER[b.status]; if (diff !== 0) return diff; return a.sportName.localeCompare(b.sportName); }); } const PATTERN_ICON: Record = { playoff_bracket: { icon: ChevronRight, title: "Bracket" }, season_standings: { icon: ListOrdered, title: "Season Standings" }, qualifying_points: { icon: SquareStack, title: "Qualifying Points" }, }; function SportIcon({ pattern }: { pattern?: string | null }) { const entry = pattern ? PATTERN_ICON[pattern] : null; const Icon = entry?.icon ?? Trophy; return (
); } /** Format the next upcoming event into a short string. */ function formatNextEvent(event: UpcomingParticipantEvent): string { const base = event.matchLabel ? `${event.name} — ${event.matchLabel}` : event.name; const date = event.earliestGameTime ? format(new Date(event.earliestGameTime), "MMM d") : event.eventDate ? format(new Date(event.eventDate + "T00:00:00"), "MMM d") : null; return date ? `${base} · ${date}` : base; } function formatPoints(p: DraftedParticipantSummary, scoringPattern?: string | null): string | null { if (scoringPattern === "qualifying_points" && p.earnedPoints === null) { if (!p.currentQP) return null; return `${p.currentQP % 1 === 0 ? p.currentQP : p.currentQP.toFixed(1)} QP`; } if (p.earnedPoints === null) return null; return `${Math.round(p.earnedPoints)} pts`; } // ─── Section header ─────────────────────────────────────────────────────────── type SectionStatus = "active" | "upcoming" | "completed"; function SectionHeader({ status }: { status: SectionStatus }) { if (status === "active") { return (
Active
); } if (status === "upcoming") { return (
Upcoming
); } return (
Completed
); } // ─── Participant chip ───────────────────────────────────────────────────────── function ParticipantChip({ participant, scoringPattern, }: { participant: DraftedParticipantSummary; scoringPattern?: string | null; }) { const pointsLabel = formatPoints(participant, scoringPattern); return ( {participant.name} {pointsLabel && ( · {pointsLabel} )} ); } // ─── Single sport row ───────────────────────────────────────────────────────── function SportRow({ item, leagueId, }: { item: SportSeasonSummaryItem; leagueId: string; }) { const participants = item.draftedParticipants ?? []; const events = item.upcomingParticipantEvents ?? []; const nextEvent = events[0] ?? null; const isCompleted = item.status === "completed"; const inner = (
{/* Left: scoring pattern icon in black box */} {/* Right: name + participants + next event */}

{item.sportName}

{item.seasonName}

{participants.length > 0 && (
{participants.map((p) => ( ))}
)} {nextEvent && (
{formatNextEvent(nextEvent)}
)}
); return ( {inner} ); } // ─── Section ────────────────────────────────────────────────────────────────── function Section({ status, items, leagueId, }: { status: SectionStatus; items: SportSeasonSummaryItem[]; leagueId: string; }) { if (items.length === 0) return null; return (
{items.map((item) => ( ))}
); } // ─── Public API ─────────────────────────────────────────────────────────────── export function SportsSeasonsSummary({ leagueId, sportsSeasons, allSeasonsHref, }: SportsSeasonsSummaryProps) { const sorted = sortedByStatus(sportsSeasons); const active = sorted.filter((s) => s.status === "active"); const upcoming = sorted.filter((s) => s.status === "upcoming"); const completed = sorted.filter((s) => s.status === "completed"); return (

Sports

{allSeasonsHref && ( )}
{active.length > 0 && upcoming.length > 0 && (
)}
{(active.length > 0 || upcoming.length > 0) && completed.length > 0 && (
)}
); }