"use client" import { useState } from "react" import { useRouter } from "next/navigation" interface Player { id: number name: string currentElo: number } interface Team { id: number teamName: string | null player1: Player player2: Player } interface TeamsSectionProps { tournamentId: number participants: Player[] teamDurability: string partnerRotation: string allowByes: boolean } type TeamDurabilityOption = 'permanent' | 'variable' | 'per_round' type PartnerRotationOption = 'none' | 'minimize_repeat' | 'maximize_even' | 'elo_based' export default function TeamsSection({ tournamentId, participants, teamDurability: initialTeamDurability, partnerRotation: initialPartnerRotation, allowByes: initialAllowByes, }: TeamsSectionProps) { const router = useRouter() const [teams, setTeams] = useState([]) const [teamDurability, setTeamDurability] = useState(initialTeamDurability as TeamDurabilityOption) const [partnerRotation, setPartnerRotation] = useState(initialPartnerRotation as PartnerRotationOption) const [allowByes, setAllowByes] = useState(initialAllowByes) const [isGenerating, setIsGenerating] = useState(false) const [error, setError] = useState("") const [success, setSuccess] = useState("") // Manual team entry state const [manualTeamMode, setManualTeamMode] = useState(false) const [selectedPlayer1, setSelectedPlayer1] = useState(null) const [selectedPlayer2, setSelectedPlayer2] = useState(null) const [newTeamName, setNewTeamName] = useState("") const handleSaveConfig = async () => { setError("") setSuccess("") setIsGenerating(true) try { const response = await fetch(`/api/tournaments/${tournamentId}`, { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ teamDurability, partnerRotation, allowByes, }), }) if (!response.ok) { try { const errorData = await response.json() setError(errorData.error || "Failed to save configuration") } catch { setError(`Failed to save configuration: ${response.status} ${response.statusText}`) } return } setSuccess("Configuration saved successfully!") router.refresh() } catch (err) { if (err instanceof Error) { setError(err.message) } else { setError("An unknown error occurred") } } finally { setIsGenerating(false) } } const handleGenerateSchedule = async () => { if (participants.length < 2) { setError("At least 2 participants are required to generate a schedule") return } if (participants.length % 2 !== 0 && !allowByes) { setError("Odd number of participants. Enable 'Allow Byes' to proceed.") return } setError("") setSuccess("") setIsGenerating(true) try { const response = await fetch(`/api/tournaments/${tournamentId}/schedule`, { method: "POST", headers: { "Content-Type": "application/json", }, }) if (!response.ok) { try { const errorData = await response.json() setError(errorData.error || "Failed to generate schedule") } catch { setError(`Failed to generate schedule: ${response.status} ${response.statusText}`) } setIsGenerating(false) return } const data = await response.json() // Update teams from the generated schedule // Extract teams from round matchups const generatedTeams: Team[] = [] for (const round of data.rounds) { for (const matchup of round.bracketMatchups) { // Create unique keys based on player IDs const team1Key = `${matchup.player1P1.id}-${matchup.player1P2.id}` const team2Key = `${matchup.player2P1.id}-${matchup.player2P2.id}` // Add unique teams const team1 = { id: matchup.player1P1.id * 10000 + matchup.player1P2.id, teamName: `${matchup.player1P1.name} & ${matchup.player1P2.name}`, player1: matchup.player1P1, player2: matchup.player1P2, } const team2 = { id: matchup.player2P1.id * 10000 + matchup.player2P2.id, teamName: `${matchup.player2P1.name} & ${matchup.player2P2.name}`, player1: matchup.player2P1, player2: matchup.player2P2, } // Check if team already exists const existingTeam1 = generatedTeams.find( t => t.player1.id === team1.player1.id && t.player2.id === team1.player2.id ) if (!existingTeam1) generatedTeams.push(team1) const existingTeam2 = generatedTeams.find( t => t.player1.id === team2.player1.id && t.player2.id === team2.player2.id ) if (!existingTeam2) generatedTeams.push(team2) } } setTeams(generatedTeams) setSuccess(`Successfully generated ${data.roundsCreated} rounds with ${data.matchupsCreated} matchups!`) router.refresh() } catch (err) { if (err instanceof Error) { setError(err.message) } else { setError("An unknown error occurred") } } finally { setIsGenerating(false) } } const handleDeleteTeams = async () => { if (!confirm("Are you sure you want to delete the schedule? This will remove all rounds and matchups.")) { return } setError("") setSuccess("") setIsGenerating(true) try { // Delete schedule (which includes matchups/rounds) const response = await fetch(`/api/tournaments/${tournamentId}/schedule`, { method: "DELETE", }) if (!response.ok) { try { const errorData = await response.json() setError(errorData.error || "Failed to delete schedule") } catch { setError(`Failed to delete schedule: ${response.status} ${response.statusText}`) } return } setTeams([]) setSuccess("Schedule deleted successfully!") router.refresh() } catch (err) { if (err instanceof Error) { setError(err.message) } else { setError("An unknown error occurred") } } finally { setIsGenerating(false) } } // Handle adding a manual team const handleAddManualTeam = () => { if (!selectedPlayer1 || !selectedPlayer2) { setError("Please select two players for the team") return } if (selectedPlayer1 === selectedPlayer2) { setError("A player cannot be on a team with themselves") return } // Check if player is already in a team const player1InTeam = teams.some(t => t.player1.id === selectedPlayer1 || t.player2.id === selectedPlayer1) const player2InTeam = teams.some(t => t.player1.id === selectedPlayer2 || t.player2.id === selectedPlayer2) if (player1InTeam || player2InTeam) { setError("One or both players are already on a team") return } const player1 = participants.find(p => p.id === selectedPlayer1) const player2 = participants.find(p => p.id === selectedPlayer2) if (!player1 || !player2) { setError("Invalid player selection") return } const newTeam: Team = { id: player1.id * 10000 + player2.id, teamName: newTeamName || `${player1.name} & ${player2.name}`, player1, player2, } setTeams([...teams, newTeam]) setSelectedPlayer1(null) setSelectedPlayer2(null) setNewTeamName("") setError("") setSuccess("Team added!") // Clear success message after 2 seconds setTimeout(() => setSuccess(""), 2000) } // Handle removing a manual team const handleRemoveTeam = (teamId: number) => { setTeams(teams.filter(t => t.id !== teamId)) setSuccess("Team removed!") setTimeout(() => setSuccess(""), 2000) } // Handle saving manual teams const handleSaveManualTeams = async () => { if (teams.length === 0) { setError("Please add at least one team") return } setError("") setSuccess("") setIsGenerating(true) try { // For permanent teams with manual entry, we need to save the team list // This would require a new API endpoint or extending the tournament update const response = await fetch(`/api/tournaments/${tournamentId}`, { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ teamDurability: "permanent", manualTeams: teams.map(t => ({ player1Id: t.player1.id, player2Id: t.player2.id, teamName: t.teamName, })), }), }) if (!response.ok) { const errorData = await response.json() throw new Error(errorData.error || "Failed to save teams") } setSuccess("Teams saved successfully!") router.refresh() } catch (err) { if (err instanceof Error) { setError(err.message) } else { setError("An unknown error occurred") } } finally { setIsGenerating(false) } } return (

Matchups {teams.length > 0 && `(${teams.length})`}

{/* Configuration Panel */}

Team Configuration

{/* Team Durability */}

{teamDurability === 'permanent' ? 'Teams formed once and stay fixed throughout the tournament.' : teamDurability === 'variable' ? 'Fresh teams each round with partner rotation. Schedule is pre-planned.' : 'Teams formed based on results. Schedule progresses as rounds complete.'}

{/* Partner Rotation (for variable/per_round teams) */} {(teamDurability === 'variable' || teamDurability === 'per_round') && (
)} {/* Manual Team Entry Toggle (for permanent teams) */} {teamDurability === 'permanent' && (

Check this to manually create teams instead of auto-generating them.

)} {/* Allow Byes (for odd participant counts) */}

When enabled, one player will have a bye each round if there's an odd number of participants.

{/* Action Buttons */}
{/* Error/Success Messages */} {error && (
{error}
)} {success && (
{success}
)} {/* Manual Team Entry Form */} {manualTeamMode && teamDurability === 'permanent' && (

Manual Team Entry

setNewTeamName(e.target.value)} placeholder="e.g., The Aces" className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm" />
)} {/* Team Generation Controls */}
{!manualTeamMode && ( <> {teams.length > 0 && ( )} )} {manualTeamMode && teams.length > 0 && ( )}
{/* Teams Display */} {teams.length > 0 ? (
{teams.map((team) => (

{team.player1.name} + {team.player2.name}

{team.teamName || `Team ${team.id}`}

ELO: {team.player1.currentElo} + {team.player2.currentElo} = {team.player1.currentElo + team.player2.currentElo}

{manualTeamMode && ( )}
))}
) : (

{manualTeamMode ? "No teams created yet. Use the form above to add teams manually." : "No teams created yet. Configure options above and click Generate Schedule."}

)} {/* Participants Summary */}

Available Participants ({participants.length})

{participants.map((player) => (
{player.name} ({player.currentElo})
))}
) }