feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
import { Form, Link } from "react-router";
|
2025-11-08 21:36:29 -08:00
|
|
|
|
import { useState, useEffect, useMemo } from "react";
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
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";
|
2026-02-14 22:30:12 -08:00
|
|
|
|
import { ArrowLeft, Plus, Trophy, X, Check } from "lucide-react";
|
2025-11-04 22:09:44 -08:00
|
|
|
|
import { getAllBracketTemplates, getBracketTemplate } from "~/lib/bracket-templates";
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
import {
|
|
|
|
|
|
Table,
|
|
|
|
|
|
TableBody,
|
|
|
|
|
|
TableCell,
|
|
|
|
|
|
TableHead,
|
|
|
|
|
|
TableHeader,
|
|
|
|
|
|
TableRow,
|
|
|
|
|
|
} from "~/components/ui/table";
|
2026-02-14 22:30:12 -08:00
|
|
|
|
import { Badge } from "~/components/ui/badge";
|
2025-11-08 21:36:29 -08:00
|
|
|
|
import { ParticipantSelector } from "~/components/ParticipantSelector";
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
|
|
|
|
|
|
export { loader, action };
|
|
|
|
|
|
|
|
|
|
|
|
export default function EventBracket({
|
|
|
|
|
|
loaderData,
|
|
|
|
|
|
actionData,
|
|
|
|
|
|
}: Route.ComponentProps) {
|
2026-02-14 22:30:12 -08:00
|
|
|
|
const { sportsSeason, event, participants, matches, tournamentGroups } = loaderData;
|
2025-11-04 22:09:44 -08:00
|
|
|
|
const [selectedTemplate, setSelectedTemplate] = useState("simple_8");
|
|
|
|
|
|
const [selectedParticipants, setSelectedParticipants] = useState<Record<number, string>>({});
|
|
|
|
|
|
const [selectedWinners, setSelectedWinners] = useState<Record<string, string>>({});
|
2026-02-14 22:30:12 -08:00
|
|
|
|
const [knockoutAssignments, setKnockoutAssignments] = useState<Record<string, string>>({});
|
2025-11-04 22:09:44 -08:00
|
|
|
|
const templates = getAllBracketTemplates();
|
|
|
|
|
|
const template = templates.find((t) => t.id === selectedTemplate);
|
|
|
|
|
|
|
2026-02-14 22:30:12 -08:00
|
|
|
|
// Determine if this is a group-stage event
|
|
|
|
|
|
const hasGroupStage = template?.groupStage != null;
|
|
|
|
|
|
const isGroupStageEvent = tournamentGroups.length > 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Determine the phase for group-stage events
|
|
|
|
|
|
const knockoutPopulated = useMemo(() => {
|
|
|
|
|
|
if (!isGroupStageEvent) return false;
|
|
|
|
|
|
// Check if any Round of 32 match has participants assigned
|
|
|
|
|
|
const r32Matches = matches.filter((m: any) => m.round === "Round of 32");
|
|
|
|
|
|
return r32Matches.some((m: any) => m.participant1Id || m.participant2Id);
|
|
|
|
|
|
}, [isGroupStageEvent, matches]);
|
|
|
|
|
|
|
|
|
|
|
|
// Group stage stats
|
|
|
|
|
|
const groupStageStats = useMemo(() => {
|
|
|
|
|
|
if (!isGroupStageEvent) return null;
|
|
|
|
|
|
let eliminated = 0;
|
|
|
|
|
|
let total = 0;
|
|
|
|
|
|
for (const group of tournamentGroups) {
|
|
|
|
|
|
for (const member of (group as any).members || []) {
|
|
|
|
|
|
total++;
|
|
|
|
|
|
if (member.eliminated) eliminated++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return { eliminated, advancing: total - eliminated, total };
|
|
|
|
|
|
}, [isGroupStageEvent, tournamentGroups]);
|
|
|
|
|
|
|
|
|
|
|
|
// Advancing participants (non-eliminated) for knockout assignment
|
|
|
|
|
|
const advancingParticipants = useMemo(() => {
|
|
|
|
|
|
if (!isGroupStageEvent) return [];
|
|
|
|
|
|
const advancing: Array<{ id: string; name: string }> = [];
|
|
|
|
|
|
for (const group of tournamentGroups) {
|
|
|
|
|
|
for (const member of (group as any).members || []) {
|
|
|
|
|
|
if (!member.eliminated && member.participant) {
|
|
|
|
|
|
advancing.push({
|
|
|
|
|
|
id: member.participant.id,
|
|
|
|
|
|
name: member.participant.name,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return advancing;
|
|
|
|
|
|
}, [isGroupStageEvent, tournamentGroups]);
|
|
|
|
|
|
|
|
|
|
|
|
// Available advancing participants for knockout assignment (exclude already assigned)
|
|
|
|
|
|
const availableAdvancingMap = useMemo(() => {
|
|
|
|
|
|
const assignedIds = new Set(Object.values(knockoutAssignments).filter(Boolean));
|
|
|
|
|
|
const map: Record<string, typeof advancingParticipants> = {};
|
|
|
|
|
|
|
|
|
|
|
|
// Create 32 slots (16 matches × 2 slots)
|
|
|
|
|
|
for (let m = 1; m <= 16; m++) {
|
|
|
|
|
|
for (const slot of ["participant1Id", "participant2Id"]) {
|
|
|
|
|
|
const key = `match-${m}-${slot}`;
|
|
|
|
|
|
const currentSelection = knockoutAssignments[key];
|
|
|
|
|
|
map[key] = advancingParticipants.filter(
|
|
|
|
|
|
(p) => !assignedIds.has(p.id) || p.id === currentSelection
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return map;
|
|
|
|
|
|
}, [knockoutAssignments, advancingParticipants]);
|
|
|
|
|
|
|
2025-11-04 22:09:44 -08:00
|
|
|
|
// Clear selected winners after successful batch submission
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (actionData?.success) {
|
|
|
|
|
|
setSelectedWinners({});
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [actionData?.success]);
|
|
|
|
|
|
|
|
|
|
|
|
// Reset selected participants when template changes
|
|
|
|
|
|
const handleTemplateChange = (newTemplateId: string) => {
|
|
|
|
|
|
setSelectedTemplate(newTemplateId);
|
|
|
|
|
|
setSelectedParticipants({});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Update selected participant for a seed
|
|
|
|
|
|
const handleParticipantChange = (seedIndex: number, participantId: string) => {
|
|
|
|
|
|
setSelectedParticipants(prev => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
[seedIndex]: participantId
|
|
|
|
|
|
}));
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-14 22:30:12 -08:00
|
|
|
|
// Memoized available participants calculation
|
2025-11-08 21:36:29 -08:00
|
|
|
|
const availableParticipantsMap = useMemo(() => {
|
|
|
|
|
|
const selectedIdsSet = new Set(Object.values(selectedParticipants));
|
|
|
|
|
|
const map: Record<number, typeof participants> = {};
|
|
|
|
|
|
const totalSeeds = template?.totalTeams || 8;
|
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < totalSeeds; i++) {
|
|
|
|
|
|
const currentSelection = selectedParticipants[i];
|
|
|
|
|
|
map[i] = participants.filter((p: { id: string; name: string }) => {
|
|
|
|
|
|
return !selectedIdsSet.has(p.id) || p.id === currentSelection;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
return map;
|
|
|
|
|
|
}, [selectedParticipants, participants, template?.totalTeams]);
|
|
|
|
|
|
|
|
|
|
|
|
const getAvailableParticipants = (seedIndex: number) => {
|
|
|
|
|
|
return availableParticipantsMap[seedIndex] || participants;
|
2025-11-04 22:09:44 -08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Update selected winner for a match
|
|
|
|
|
|
const handleWinnerChange = (matchId: string, winnerId: string) => {
|
|
|
|
|
|
setSelectedWinners(prev => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
[matchId]: winnerId
|
|
|
|
|
|
}));
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Get matches with pending winner selections in a round
|
|
|
|
|
|
const getPendingWinnersInRound = (round: string) => {
|
|
|
|
|
|
return Object.entries(selectedWinners)
|
|
|
|
|
|
.filter(([matchId]) => {
|
|
|
|
|
|
const match = matches.find((m: any) => m.id === matchId);
|
|
|
|
|
|
return match && match.round === round && !match.isComplete;
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
|
2025-11-08 21:36:29 -08:00
|
|
|
|
// Memoized: Group matches by round
|
|
|
|
|
|
const matchesByRound = useMemo(() => {
|
|
|
|
|
|
const grouped: Record<string, typeof matches> = {};
|
|
|
|
|
|
for (const match of matches) {
|
|
|
|
|
|
if (!grouped[match.round]) {
|
|
|
|
|
|
grouped[match.round] = [];
|
|
|
|
|
|
}
|
|
|
|
|
|
grouped[match.round].push(match);
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
}
|
2025-11-08 21:36:29 -08:00
|
|
|
|
return grouped;
|
|
|
|
|
|
}, [matches]);
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
|
2026-02-14 22:30:12 -08:00
|
|
|
|
// Memoized: Get available rounds in chronological order
|
2025-11-08 21:36:29 -08:00
|
|
|
|
const availableRounds = useMemo(() => {
|
2025-11-04 22:09:44 -08:00
|
|
|
|
const roundsInMatches = Array.from(new Set(matches.map(m => m.round)));
|
|
|
|
|
|
|
|
|
|
|
|
if (event.bracketTemplateId) {
|
|
|
|
|
|
const eventTemplate = getBracketTemplate(event.bracketTemplateId);
|
|
|
|
|
|
if (eventTemplate) {
|
|
|
|
|
|
return eventTemplate.rounds
|
|
|
|
|
|
.map((r) => r.name)
|
|
|
|
|
|
.filter((roundName: string) => roundsInMatches.includes(roundName));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return roundsInMatches;
|
2025-11-08 21:36:29 -08:00
|
|
|
|
}, [matches, event.bracketTemplateId]);
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
|
2025-11-14 20:01:21 -08:00
|
|
|
|
// Check if all matches are complete
|
|
|
|
|
|
const allMatchesComplete = useMemo(() => {
|
|
|
|
|
|
return matches.length > 0 && matches.every((m: any) => m.isComplete);
|
|
|
|
|
|
}, [matches]);
|
|
|
|
|
|
|
2026-02-14 22:30:12 -08:00
|
|
|
|
// No bracket and no groups yet = setup phase
|
|
|
|
|
|
const showSetup = matches.length === 0 && !isGroupStageEvent;
|
|
|
|
|
|
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
return (
|
|
|
|
|
|
<div className="p-8">
|
|
|
|
|
|
<div className="max-w-6xl mx-auto">
|
|
|
|
|
|
<div className="mb-6">
|
|
|
|
|
|
<Button variant="ghost" size="sm" asChild className="mb-2">
|
|
|
|
|
|
<Link to={`/admin/sports-seasons/${sportsSeason.id}/events/${event.id}`}>
|
|
|
|
|
|
<ArrowLeft className="mr-2 h-4 w-4" />
|
|
|
|
|
|
Back to Event
|
|
|
|
|
|
</Link>
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<h1 className="text-3xl font-bold">Playoff Bracket</h1>
|
|
|
|
|
|
<p className="text-muted-foreground mt-1">
|
|
|
|
|
|
{event.name} - {sportsSeason.sport.name} {sportsSeason.name}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
|
{actionData?.error && (
|
|
|
|
|
|
<div className="bg-destructive/15 text-destructive px-4 py-3 rounded-md text-sm">
|
|
|
|
|
|
{actionData.error}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{actionData?.success && (
|
|
|
|
|
|
<div className="bg-green-500/15 text-green-700 dark:text-green-400 px-4 py-3 rounded-md text-sm">
|
|
|
|
|
|
{actionData.success}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-02-14 22:30:12 -08:00
|
|
|
|
{/* Reprocess Eliminations - For existing brackets (non-group-stage) */}
|
|
|
|
|
|
{matches.length > 0 && !isGroupStageEvent && (
|
2025-11-21 22:05:50 -08:00
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>Reprocess Eliminations</CardTitle>
|
|
|
|
|
|
<CardDescription>
|
|
|
|
|
|
Mark participants not in this bracket as eliminated (for brackets created before automatic elimination tracking)
|
|
|
|
|
|
</CardDescription>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent>
|
|
|
|
|
|
<Form method="post">
|
|
|
|
|
|
<input type="hidden" name="intent" value="reprocess-eliminations" />
|
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
|
<div className="text-sm text-muted-foreground">
|
|
|
|
|
|
This will set finalPosition = 0 for all participants who are not in any playoff match,
|
|
|
|
|
|
allowing probability recalculation to set their odds to 0%.
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Button type="submit" variant="outline">
|
|
|
|
|
|
Reprocess Eliminations
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-02-14 22:30:12 -08:00
|
|
|
|
{/* ====== SETUP PHASE ====== */}
|
|
|
|
|
|
{showSetup && (
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>Generate Bracket</CardTitle>
|
|
|
|
|
|
<CardDescription>
|
|
|
|
|
|
Create the bracket structure for this playoff event
|
|
|
|
|
|
</CardDescription>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent>
|
|
|
|
|
|
<Form method="post" className="space-y-4">
|
2026-02-14 22:30:12 -08:00
|
|
|
|
{/* Intent depends on whether this is a group-stage template */}
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="hidden"
|
|
|
|
|
|
name="intent"
|
|
|
|
|
|
value={hasGroupStage ? "generate-groups" : "generate-bracket"}
|
|
|
|
|
|
/>
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
|
|
|
|
|
|
<div className="space-y-2">
|
2025-11-04 22:09:44 -08:00
|
|
|
|
<Label htmlFor="templateId">Bracket Template</Label>
|
|
|
|
|
|
<Select
|
|
|
|
|
|
name="templateId"
|
|
|
|
|
|
value={selectedTemplate}
|
|
|
|
|
|
onValueChange={handleTemplateChange}
|
|
|
|
|
|
required
|
|
|
|
|
|
>
|
|
|
|
|
|
<SelectTrigger id="templateId">
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
<SelectValue />
|
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
|
<SelectContent>
|
2025-11-04 22:09:44 -08:00
|
|
|
|
{templates.map((t) => (
|
|
|
|
|
|
<SelectItem key={t.id} value={t.id}>
|
|
|
|
|
|
{t.name} - {t.totalTeams} teams
|
|
|
|
|
|
</SelectItem>
|
|
|
|
|
|
))}
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
</SelectContent>
|
|
|
|
|
|
</Select>
|
2025-11-04 22:09:44 -08:00
|
|
|
|
{template && (
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
2026-02-14 22:30:12 -08:00
|
|
|
|
{template.groupStage ? (
|
|
|
|
|
|
<>
|
|
|
|
|
|
Groups: {template.groupStage.groupCount} groups of {template.groupStage.teamsPerGroup}
|
|
|
|
|
|
{" | "}Knockout: {template.rounds.map(r => r.name).join(" \u2192 ")}
|
|
|
|
|
|
</>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<>Rounds: {template.rounds.map(r => r.name).join(" \u2192 ")}</>
|
|
|
|
|
|
)}
|
2025-11-04 22:09:44 -08:00
|
|
|
|
</p>
|
|
|
|
|
|
)}
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-02-14 22:30:12 -08:00
|
|
|
|
{/* Group-stage template: show group assignments */}
|
|
|
|
|
|
{hasGroupStage && template?.groupStage && (
|
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
|
<Label>Assign Participants to Groups</Label>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
|
Assign {template.totalTeams} participants across {template.groupStage.groupCount} groups
|
|
|
|
|
|
({template.groupStage.teamsPerGroup} per group).
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
|
|
|
|
{template.groupStage.groupLabels.map((label, groupIndex) => (
|
|
|
|
|
|
<Card key={label} className="border-dashed">
|
|
|
|
|
|
<CardHeader className="py-3 px-4">
|
|
|
|
|
|
<CardTitle className="text-base">Group {label}</CardTitle>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="px-4 pb-4 space-y-2">
|
|
|
|
|
|
{[...Array(template.groupStage!.teamsPerGroup)].map((_, teamIndex) => {
|
|
|
|
|
|
const seedIndex = groupIndex * template.groupStage!.teamsPerGroup + teamIndex;
|
|
|
|
|
|
const availableParticipants = getAvailableParticipants(seedIndex);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div key={seedIndex}>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="hidden"
|
|
|
|
|
|
name={`participant${seedIndex}`}
|
|
|
|
|
|
value={selectedParticipants[seedIndex] || ""}
|
|
|
|
|
|
required
|
|
|
|
|
|
/>
|
|
|
|
|
|
<ParticipantSelector
|
|
|
|
|
|
participants={availableParticipants}
|
|
|
|
|
|
value={selectedParticipants[seedIndex] || ""}
|
|
|
|
|
|
onValueChange={(value) => handleParticipantChange(seedIndex, value)}
|
|
|
|
|
|
placeholder={`Team ${teamIndex + 1}...`}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Non-group-stage template: show seeded list */}
|
|
|
|
|
|
{!hasGroupStage && (
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
|
<Label>Select Participants (in order)</Label>
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
|
Select {template?.totalTeams || 8} participants for the bracket. Use search to quickly find participants.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
{[...Array(template?.totalTeams || 8)].map((_, i) => {
|
|
|
|
|
|
const availableParticipants = getAvailableParticipants(i);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div key={i} className="flex items-center gap-2">
|
|
|
|
|
|
<Label className="w-20 text-sm text-muted-foreground shrink-0">
|
|
|
|
|
|
Seed {i + 1}
|
|
|
|
|
|
</Label>
|
|
|
|
|
|
<div className="flex-1 min-w-0">
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="hidden"
|
|
|
|
|
|
name={`participant${i}`}
|
|
|
|
|
|
value={selectedParticipants[i] || ""}
|
|
|
|
|
|
required
|
|
|
|
|
|
/>
|
|
|
|
|
|
<ParticipantSelector
|
|
|
|
|
|
participants={availableParticipants}
|
|
|
|
|
|
value={selectedParticipants[i] || ""}
|
|
|
|
|
|
onValueChange={(value) => handleParticipantChange(i, value)}
|
|
|
|
|
|
placeholder={`Select seed ${i + 1}...`}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
2025-11-08 21:36:29 -08:00
|
|
|
|
</div>
|
2026-02-14 22:30:12 -08:00
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
|
|
|
|
|
|
<Button type="submit" className="w-full">
|
|
|
|
|
|
<Plus className="mr-2 h-4 w-4" />
|
2026-02-14 22:30:12 -08:00
|
|
|
|
{hasGroupStage ? "Generate Groups & Bracket" : "Generate Bracket"}
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
</Button>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-02-14 22:30:12 -08:00
|
|
|
|
{/* ====== GROUP STAGE MANAGEMENT (Phase 2) ====== */}
|
|
|
|
|
|
{isGroupStageEvent && !knockoutPopulated && (
|
|
|
|
|
|
<>
|
|
|
|
|
|
{/* Group Stage Summary */}
|
|
|
|
|
|
{groupStageStats && (
|
|
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>Group Stage</CardTitle>
|
|
|
|
|
|
<CardDescription>
|
|
|
|
|
|
Manage group stage eliminations. Mark teams as eliminated, then assign advancing teams to the knockout bracket.
|
|
|
|
|
|
</CardDescription>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent>
|
|
|
|
|
|
<div className="flex gap-4 text-sm">
|
|
|
|
|
|
<Badge variant="secondary">
|
|
|
|
|
|
{groupStageStats.total} total teams
|
|
|
|
|
|
</Badge>
|
|
|
|
|
|
<Badge variant="destructive">
|
|
|
|
|
|
{groupStageStats.eliminated} eliminated
|
|
|
|
|
|
</Badge>
|
|
|
|
|
|
<Badge variant="default">
|
|
|
|
|
|
{groupStageStats.advancing} advancing
|
|
|
|
|
|
</Badge>
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
</div>
|
2026-02-14 22:30:12 -08:00
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Group Cards */}
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
|
|
|
|
|
{tournamentGroups.map((group: any) => (
|
|
|
|
|
|
<Card key={group.id}>
|
|
|
|
|
|
<CardHeader className="py-3 px-4">
|
|
|
|
|
|
<CardTitle className="text-base">Group {group.groupName}</CardTitle>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="px-4 pb-4 space-y-2">
|
|
|
|
|
|
{(group.members || []).map((member: any) => (
|
|
|
|
|
|
<div
|
|
|
|
|
|
key={member.id}
|
|
|
|
|
|
className={`flex items-center justify-between gap-2 p-2 rounded-md border ${
|
|
|
|
|
|
member.eliminated
|
|
|
|
|
|
? "bg-destructive/10 border-destructive/20"
|
|
|
|
|
|
: "bg-background border-border"
|
|
|
|
|
|
}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span
|
|
|
|
|
|
className={`text-sm truncate ${
|
|
|
|
|
|
member.eliminated ? "line-through text-muted-foreground" : ""
|
|
|
|
|
|
}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
{member.participant?.name || "Unknown"}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<Form method="post" className="shrink-0">
|
|
|
|
|
|
<input type="hidden" name="intent" value="toggle-elimination" />
|
|
|
|
|
|
<input type="hidden" name="memberId" value={member.id} />
|
|
|
|
|
|
<Button
|
|
|
|
|
|
type="submit"
|
|
|
|
|
|
size="sm"
|
|
|
|
|
|
variant={member.eliminated ? "outline" : "destructive"}
|
|
|
|
|
|
className="h-7 text-xs"
|
|
|
|
|
|
>
|
|
|
|
|
|
{member.eliminated ? (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<Check className="h-3 w-3 mr-1" />
|
|
|
|
|
|
Reinstate
|
|
|
|
|
|
</>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<X className="h-3 w-3 mr-1" />
|
|
|
|
|
|
Eliminate
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Knockout Assignment Section */}
|
|
|
|
|
|
{groupStageStats && groupStageStats.advancing === 32 && (
|
|
|
|
|
|
<Card className="border-blue-500">
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>Assign Knockout Bracket</CardTitle>
|
|
|
|
|
|
<CardDescription>
|
|
|
|
|
|
32 teams are advancing. Assign them to the Round of 32 knockout bracket slots.
|
|
|
|
|
|
</CardDescription>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent>
|
|
|
|
|
|
<Form method="post" className="space-y-4">
|
|
|
|
|
|
<input type="hidden" name="intent" value="populate-knockout" />
|
|
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
|
|
|
{[...Array(16)].map((_, matchIndex) => {
|
|
|
|
|
|
const matchNum = matchIndex + 1;
|
|
|
|
|
|
const key1 = `match-${matchNum}-participant1Id`;
|
|
|
|
|
|
const key2 = `match-${matchNum}-participant2Id`;
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<Card key={matchNum} className="border-dashed">
|
|
|
|
|
|
<CardContent className="p-4 space-y-2">
|
|
|
|
|
|
<div className="text-sm font-semibold text-muted-foreground">
|
|
|
|
|
|
Match {matchNum}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="hidden"
|
|
|
|
|
|
name={key1}
|
|
|
|
|
|
value={knockoutAssignments[key1] || ""}
|
|
|
|
|
|
required
|
|
|
|
|
|
/>
|
|
|
|
|
|
<ParticipantSelector
|
|
|
|
|
|
participants={availableAdvancingMap[key1] || []}
|
|
|
|
|
|
value={knockoutAssignments[key1] || ""}
|
|
|
|
|
|
onValueChange={(value) =>
|
|
|
|
|
|
setKnockoutAssignments((prev) => ({ ...prev, [key1]: value }))
|
|
|
|
|
|
}
|
|
|
|
|
|
placeholder="Team 1..."
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div className="text-center text-xs text-muted-foreground">vs</div>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="hidden"
|
|
|
|
|
|
name={key2}
|
|
|
|
|
|
value={knockoutAssignments[key2] || ""}
|
|
|
|
|
|
required
|
|
|
|
|
|
/>
|
|
|
|
|
|
<ParticipantSelector
|
|
|
|
|
|
participants={availableAdvancingMap[key2] || []}
|
|
|
|
|
|
value={knockoutAssignments[key2] || ""}
|
|
|
|
|
|
onValueChange={(value) =>
|
|
|
|
|
|
setKnockoutAssignments((prev) => ({ ...prev, [key2]: value }))
|
|
|
|
|
|
}
|
|
|
|
|
|
placeholder="Team 2..."
|
|
|
|
|
|
/>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<Button type="submit" className="w-full">
|
|
|
|
|
|
Populate Knockout Bracket
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{groupStageStats && groupStageStats.advancing !== 32 && groupStageStats.eliminated > 0 && (
|
|
|
|
|
|
<Card>
|
|
|
|
|
|
<CardContent className="pt-6">
|
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
|
{groupStageStats.advancing} teams advancing (need exactly 32 to populate knockout bracket).
|
|
|
|
|
|
{groupStageStats.advancing > 32 && ` Eliminate ${groupStageStats.advancing - 32} more.`}
|
|
|
|
|
|
{groupStageStats.advancing < 32 && ` Reinstate ${32 - groupStageStats.advancing} teams or adjust eliminations.`}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</>
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
)}
|
2025-11-14 20:01:21 -08:00
|
|
|
|
|
2026-02-14 22:30:12 -08:00
|
|
|
|
{/* ====== KNOCKOUT BRACKET DISPLAY (Phase 3) ====== */}
|
|
|
|
|
|
{/* Show bracket rounds when: non-group event with matches, OR group event with knockout populated */}
|
|
|
|
|
|
{((matches.length > 0 && !isGroupStageEvent) || knockoutPopulated) && (
|
|
|
|
|
|
<>
|
|
|
|
|
|
{availableRounds.map((round: string) => (
|
|
|
|
|
|
<Card key={round}>
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>{round}</CardTitle>
|
|
|
|
|
|
<CardDescription>
|
|
|
|
|
|
{matchesByRound[round].length} {matchesByRound[round].length === 1 ? "match" : "matches"}
|
|
|
|
|
|
</CardDescription>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent>
|
|
|
|
|
|
<Table>
|
|
|
|
|
|
<TableHeader>
|
|
|
|
|
|
<TableRow>
|
|
|
|
|
|
<TableHead className="w-16">Match</TableHead>
|
|
|
|
|
|
<TableHead>Participant 1</TableHead>
|
|
|
|
|
|
<TableHead>Score</TableHead>
|
|
|
|
|
|
<TableHead className="w-24 text-center">vs</TableHead>
|
|
|
|
|
|
<TableHead>Score</TableHead>
|
|
|
|
|
|
<TableHead>Participant 2</TableHead>
|
|
|
|
|
|
<TableHead>Winner</TableHead>
|
|
|
|
|
|
<TableHead className="w-32">Actions</TableHead>
|
|
|
|
|
|
</TableRow>
|
|
|
|
|
|
</TableHeader>
|
|
|
|
|
|
<TableBody>
|
|
|
|
|
|
{matchesByRound[round].map((match) => (
|
|
|
|
|
|
<TableRow key={match.id}>
|
|
|
|
|
|
<TableCell className="font-semibold">
|
|
|
|
|
|
{match.matchNumber}
|
|
|
|
|
|
</TableCell>
|
|
|
|
|
|
<TableCell>
|
|
|
|
|
|
{match.participant1?.name || "TBD"}
|
|
|
|
|
|
</TableCell>
|
|
|
|
|
|
<TableCell>
|
|
|
|
|
|
{match.participant1Score ? parseFloat(match.participant1Score) : "-"}
|
|
|
|
|
|
</TableCell>
|
|
|
|
|
|
<TableCell className="text-center text-muted-foreground">
|
|
|
|
|
|
vs
|
|
|
|
|
|
</TableCell>
|
|
|
|
|
|
<TableCell>
|
|
|
|
|
|
{match.participant2Score ? parseFloat(match.participant2Score) : "-"}
|
|
|
|
|
|
</TableCell>
|
|
|
|
|
|
<TableCell>
|
|
|
|
|
|
{match.participant2?.name || "TBD"}
|
|
|
|
|
|
</TableCell>
|
|
|
|
|
|
<TableCell>
|
|
|
|
|
|
{match.winner?.name ? (
|
|
|
|
|
|
<div className="flex items-center gap-1">
|
|
|
|
|
|
<Trophy className="h-4 w-4 text-yellow-500" />
|
|
|
|
|
|
{match.winner.name}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
"-"
|
|
|
|
|
|
)}
|
|
|
|
|
|
</TableCell>
|
|
|
|
|
|
<TableCell>
|
|
|
|
|
|
{!match.isComplete && match.participant1Id && match.participant2Id ? (
|
|
|
|
|
|
<Select
|
|
|
|
|
|
value={selectedWinners[match.id] || ""}
|
|
|
|
|
|
onValueChange={(value) => handleWinnerChange(match.id, value)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<SelectTrigger className="h-8 w-full">
|
|
|
|
|
|
<SelectValue placeholder="Select winner" />
|
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
|
<SelectContent>
|
|
|
|
|
|
<SelectItem value={match.participant1Id}>
|
|
|
|
|
|
{match.participant1?.name}
|
|
|
|
|
|
</SelectItem>
|
|
|
|
|
|
<SelectItem value={match.participant2Id}>
|
|
|
|
|
|
{match.participant2?.name}
|
|
|
|
|
|
</SelectItem>
|
|
|
|
|
|
</SelectContent>
|
|
|
|
|
|
</Select>
|
|
|
|
|
|
) : match.isComplete ? (
|
|
|
|
|
|
<span className="text-sm text-muted-foreground">Complete</span>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<span className="text-sm text-muted-foreground">Waiting</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</TableCell>
|
|
|
|
|
|
</TableRow>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</TableBody>
|
|
|
|
|
|
</Table>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Batch Submit Winners */}
|
|
|
|
|
|
{getPendingWinnersInRound(round).length > 0 && (
|
|
|
|
|
|
<Form method="post" className="mt-4">
|
|
|
|
|
|
<input type="hidden" name="intent" value="set-round-winners" />
|
|
|
|
|
|
<input type="hidden" name="round" value={round} />
|
|
|
|
|
|
{getPendingWinnersInRound(round).map(([matchId, winnerId]) => (
|
|
|
|
|
|
<input key={matchId} type="hidden" name={`winner-${matchId}`} value={winnerId} />
|
|
|
|
|
|
))}
|
|
|
|
|
|
<Button type="submit" className="w-full">
|
|
|
|
|
|
Save {getPendingWinnersInRound(round).length} Winner{getPendingWinnersInRound(round).length > 1 ? 's' : ''} for {round}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
))}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Complete Round Button */}
|
|
|
|
|
|
{availableRounds.length > 0 && !event.isComplete && (
|
|
|
|
|
|
<Card>
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>Complete Round</CardTitle>
|
|
|
|
|
|
<CardDescription>
|
|
|
|
|
|
Finalize the current round and calculate placements
|
|
|
|
|
|
</CardDescription>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent>
|
|
|
|
|
|
<Form method="post">
|
|
|
|
|
|
<input type="hidden" name="intent" value="complete-round" />
|
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
|
<Label htmlFor="round">Round to Complete</Label>
|
|
|
|
|
|
<Select name="round" required>
|
|
|
|
|
|
<SelectTrigger id="round">
|
|
|
|
|
|
<SelectValue placeholder="Select round" />
|
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
|
<SelectContent>
|
|
|
|
|
|
{availableRounds.map((round: string) => (
|
|
|
|
|
|
<SelectItem key={round} value={round}>
|
|
|
|
|
|
{round}
|
|
|
|
|
|
</SelectItem>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</SelectContent>
|
|
|
|
|
|
</Select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Button type="submit">
|
|
|
|
|
|
Complete Round & Calculate Placements
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Finalize Bracket Button */}
|
|
|
|
|
|
{allMatchesComplete && !event.isComplete && (
|
|
|
|
|
|
<Card className="border-green-500 bg-green-50 dark:bg-green-950">
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle className="flex items-center gap-2">
|
|
|
|
|
|
<Trophy className="h-5 w-5 text-green-600" />
|
|
|
|
|
|
Finalize Bracket
|
|
|
|
|
|
</CardTitle>
|
|
|
|
|
|
<CardDescription>
|
|
|
|
|
|
All matches are complete! Process all rounds and assign final placements.
|
|
|
|
|
|
</CardDescription>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent>
|
|
|
|
|
|
<Form method="post">
|
|
|
|
|
|
<input type="hidden" name="intent" value="finalize-bracket" />
|
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
|
<div className="text-sm space-y-2">
|
|
|
|
|
|
<p className="font-medium">This will:</p>
|
|
|
|
|
|
<ul className="list-disc list-inside space-y-1 text-muted-foreground">
|
|
|
|
|
|
<li>Process all playoff rounds in order</li>
|
|
|
|
|
|
<li>Assign fantasy placements (1st-8th) based on bracket results</li>
|
|
|
|
|
|
<li>Assign 0 points to participants not in the bracket</li>
|
|
|
|
|
|
<li>Mark the event as complete</li>
|
|
|
|
|
|
<li>Recalculate all team standings</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Button type="submit" className="w-full bg-green-600 hover:bg-green-700">
|
|
|
|
|
|
Finalize Bracket & Update Standings
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</>
|
2025-11-14 20:01:21 -08:00
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Event Complete Badge */}
|
|
|
|
|
|
{event.isComplete && (
|
|
|
|
|
|
<Card className="border-blue-500 bg-blue-50 dark:bg-blue-950">
|
|
|
|
|
|
<CardContent className="pt-6">
|
|
|
|
|
|
<div className="flex items-center gap-2 text-blue-700 dark:text-blue-400">
|
|
|
|
|
|
<Trophy className="h-5 w-5" />
|
|
|
|
|
|
<span className="font-semibold">Event Complete</span>
|
|
|
|
|
|
<span className="text-sm text-muted-foreground ml-auto">
|
|
|
|
|
|
{event.completedAt && new Date(event.completedAt).toLocaleDateString()}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|