import { Form, Link } from "react-router"; import type { Route } from "./+types/admin.sports-seasons.$id.events.$eventId.bracket"; import { loader, action } from "./admin.sports-seasons.$id.events.$eventId.bracket.server"; import { Button } from "~/components/ui/button"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "~/components/ui/card"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "~/components/ui/select"; import { ArrowLeft, Plus, Trophy } from "lucide-react"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "~/components/ui/table"; export { loader, action }; export default function EventBracket({ loaderData, actionData, }: Route.ComponentProps) { const { sportsSeason, event, participants, matches } = loaderData; // Group matches by round const matchesByRound: Record = {}; for (const match of matches) { if (!matchesByRound[match.round]) { matchesByRound[match.round] = []; } matchesByRound[match.round].push(match); } const rounds = ["Quarterfinals", "Semifinals", "Finals"]; const availableRounds = rounds.filter(r => matchesByRound[r]); // Get participants not yet in any match const participantsInMatches = new Set( matches.flatMap(m => [m.participant1Id, m.participant2Id].filter(Boolean)) ); const availableParticipants = participants.filter( (p: { id: string }) => !participantsInMatches.has(p.id) ); return (

Playoff Bracket

{event.name} - {sportsSeason.sport.name} {sportsSeason.name}

{actionData?.error && (
{actionData.error}
)} {actionData?.success && (
{actionData.success}
)} {/* Generate Bracket Form */} {matches.length === 0 && ( Generate Bracket Create the bracket structure for this playoff event

Select {8} participants for the bracket

{[...Array(8)].map((_, i) => ( ))}
)} {/* Bracket Display */} {availableRounds.map(round => ( {round} {matchesByRound[round].length} {matchesByRound[round].length === 1 ? "match" : "matches"} Match Participant 1 Score vs Score Participant 2 Winner Actions {matchesByRound[round].map((match) => ( {match.matchNumber} {match.participant1?.name || "TBD"} {match.participant1Score ? parseFloat(match.participant1Score) : "-"} vs {match.participant2Score ? parseFloat(match.participant2Score) : "-"} {match.participant2?.name || "TBD"} {match.winner?.name ? (
{match.winner.name}
) : ( "-" )}
{!match.isComplete && match.participant1Id && match.participant2Id ? (
) : match.isComplete ? ( Complete ) : ( Waiting )}
))}
))} {/* Complete Round Button */} {availableRounds.length > 0 && ( Complete Round Finalize the current round and calculate placements
)}
); }