import { useState } from "react"; import type { SeasonMatch, MatchSubGame } from "~/models/season-match"; import { PlayoffBracket, type Match as PlayoffMatch, type TeamOwnership } from "./PlayoffBracket"; type MatchWithRelations = SeasonMatch & { participant1: { id: string; name: string } | null; participant2: { id: string; name: string } | null; winner: { id: string; name: string } | null; subGames: MatchSubGame[]; }; interface Cs2TournamentBracketProps { swissMatches: MatchWithRelations[]; playoffMatches: PlayoffMatch[]; playoffRounds: string[]; bracketTemplateId?: string | null; teamOwnerships?: TeamOwnership[]; userParticipantIds?: string[]; } const STAGE_NAMES: Record = { 1: "Opening Stage", 2: "Challengers Stage", 3: "Legends Stage", }; const STATUS_BADGE: Record = { scheduled: "bg-muted text-muted-foreground text-xs px-2 py-0.5 rounded", in_progress: "bg-amber-500/15 text-amber-400 border border-amber-500/30 text-xs px-2 py-0.5 rounded", complete: "bg-emerald-500/15 text-emerald-400 border border-emerald-500/30 text-xs px-2 py-0.5 rounded", canceled: "bg-destructive/15 text-destructive text-xs px-2 py-0.5 rounded", postponed: "bg-muted text-muted-foreground text-xs px-2 py-0.5 rounded italic", }; function MapScores({ subGames, p1Id, p2Id }: { subGames: MatchSubGame[]; p1Id: string | null; p2Id: string | null }) { if (subGames.length === 0) return null; return (
{subGames.map((g) => ( {g.gameLabel && {g.gameLabel}} {g.participant1Score ?? "-"} {" – "} {g.participant2Score ?? "-"} ))}
); } function MatchCard({ match }: { match: MatchWithRelations }) { const p1 = match.participant1; const p2 = match.participant2; const winnerId = match.winnerId; const isComplete = match.status === "complete"; return (
{p1?.name ?? "TBD"} {isComplete && ( {match.participant1Score ?? ""} )}
{p2?.name ?? "TBD"} {isComplete && ( {match.participant2Score ?? ""} )}
{match.status === "in_progress" && ( )} {match.status === "complete" ? "Final" : match.status === "in_progress" ? "Live" : match.status === "scheduled" ? "Upcoming" : match.status}
); } function SwissStageTab({ stage, matches }: { stage: number; matches: MatchWithRelations[] }) { if (matches.length === 0) { return

No matches for this stage yet.

; } // Group matches by round const rounds = new Map(); for (const m of matches) { const r = m.matchRound ?? 0; if (!rounds.has(r)) rounds.set(r, []); rounds.get(r)!.push(m); } const sortedRounds = [...rounds.entries()].sort(([a], [b]) => a - b); return (
{sortedRounds.map(([round, roundMatches]) => (
{round > 0 && (

Round {round}

)}
{roundMatches.map((m) => ( ))}
))}
); } export function Cs2TournamentBracket({ swissMatches, playoffMatches, playoffRounds, bracketTemplateId, teamOwnerships, userParticipantIds, }: Cs2TournamentBracketProps) { const stages = [1, 2, 3].filter((s) => swissMatches.some((m) => m.matchStage === s)); const hasBracket = playoffMatches.length > 0; type Tab = "swiss-1" | "swiss-2" | "swiss-3" | "bracket"; const availableTabs: Tab[] = [ ...(stages.includes(1) ? (["swiss-1"] as Tab[]) : []), ...(stages.includes(2) ? (["swiss-2"] as Tab[]) : []), ...(stages.includes(3) ? (["swiss-3"] as Tab[]) : []), ...(hasBracket ? (["bracket"] as Tab[]) : []), ]; const [activeTab, setActiveTab] = useState(availableTabs[0] ?? "swiss-1"); const tabLabel: Record = { "swiss-1": "Opening Stage", "swiss-2": "Challengers Stage", "swiss-3": "Legends Stage", bracket: "Champions Stage", }; if (availableTabs.length === 0) { return (
No match data available yet.
); } return (
{/* Tab bar */}
{availableTabs.map((tab) => ( ))}
{/* Tab content */}
{activeTab === "swiss-1" && ( m.matchStage === 1)} /> )} {activeTab === "swiss-2" && ( m.matchStage === 2)} /> )} {activeTab === "swiss-3" && ( m.matchStage === 3)} /> )} {activeTab === "bracket" && hasBracket && ( )}
); }