"use client"; import { useState, useEffect, useCallback, useMemo } from "react"; import { useParams, useRouter } from "next/navigation"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { TournamentForm } from "@/components/tournaments/tournament-form"; import { BracketView } from "@/components/tournaments/bracket-view"; import { InscriptionsList } from "@/components/tournaments/inscriptions-list"; import { MatchScoreDialog } from "@/components/tournaments/match-score-dialog"; import { cn, formatCurrency, formatDate } from "@/lib/utils"; interface Client { id: string; firstName: string; lastName: string; email: string | null; phone: string | null; level: string | null; } interface Inscription { id: string; clientId: string; partnerId: string | null; teamName: string | null; seedNumber: number | null; isPaid: boolean; paidAmount: number; registeredAt: string; client: Client; partner?: Client | null; } interface Match { id: string; round: number; position: number; status: string; team1Players: string[]; team2Players: string[]; team1Score: number[] | null; team2Score: number[] | null; winnerId: string | null; scheduledAt: string | null; court: { id: string; name: string; } | null; } interface Tournament { id: string; name: string; description: string | null; type: string; status: string; startDate: string; endDate: string | null; maxPlayers: number | null; entryFee: string | number; rules: string | null; isPublic: boolean; settings: { tournamentFormat?: string; category?: string | null; } | null; site: { id: string; name: string; slug: string; address: string | null; phone: string | null; email: string | null; }; inscriptions: Inscription[]; matches: Match[]; _count: { inscriptions: number; matches: number; }; } const tabs = [ { id: "overview", label: "Resumen" }, { id: "inscriptions", label: "Inscripciones" }, { id: "bracket", label: "Bracket" }, ]; const statusConfig: Record = { DRAFT: { label: "Borrador", className: "bg-gray-100 text-gray-700 border-gray-300", }, REGISTRATION_OPEN: { label: "Inscripciones Abiertas", className: "bg-green-100 text-green-700 border-green-300", }, REGISTRATION_CLOSED: { label: "Inscripciones Cerradas", className: "bg-yellow-100 text-yellow-700 border-yellow-300", }, IN_PROGRESS: { label: "En Progreso", className: "bg-blue-100 text-blue-700 border-blue-300", }, COMPLETED: { label: "Finalizado", className: "bg-purple-100 text-purple-700 border-purple-300", }, CANCELLED: { label: "Cancelado", className: "bg-red-100 text-red-700 border-red-300", }, }; const typeLabels: Record = { BRACKET: "Eliminacion Directa", AMERICANO: "Americano", MEXICANO: "Mexicano", ROUND_ROBIN: "Round Robin", LEAGUE: "Liga", }; export default function TournamentDetailPage() { const params = useParams(); const router = useRouter(); const tournamentId = params.id as string; const [tournament, setTournament] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [activeTab, setActiveTab] = useState("overview"); const [showEditForm, setShowEditForm] = useState(false); const [actionLoading, setActionLoading] = useState(null); const [selectedMatch, setSelectedMatch] = useState(null); // Build players map for bracket view const playersMap = useMemo(() => { const map = new Map(); if (tournament) { tournament.inscriptions.forEach((inscription) => { map.set(inscription.client.id, inscription.client); if (inscription.partner) { map.set(inscription.partner.id, inscription.partner); } }); } return map; }, [tournament]); const fetchTournament = useCallback(async () => { setLoading(true); setError(null); try { const response = await fetch(`/api/tournaments/${tournamentId}`); if (!response.ok) { if (response.status === 404) { throw new Error("Torneo no encontrado"); } throw new Error("Error al cargar el torneo"); } const data = await response.json(); setTournament(data); } catch (err) { setError(err instanceof Error ? err.message : "Error desconocido"); } finally { setLoading(false); } }, [tournamentId]); useEffect(() => { fetchTournament(); }, [fetchTournament]); const handleStatusChange = async (newStatus: string) => { if (!tournament) return; setActionLoading("status"); try { const response = await fetch(`/api/tournaments/${tournamentId}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ status: newStatus }), }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Error al actualizar estado"); } await fetchTournament(); } catch (err) { alert(err instanceof Error ? err.message : "Error desconocido"); } finally { setActionLoading(null); } }; const handleGenerateBracket = async () => { if (!tournament) return; if (tournament.inscriptions.length < 2) { alert("Se necesitan al menos 2 equipos para generar el bracket"); return; } if (!confirm("¿Generar el bracket? Esto iniciara el torneo y cerrara las inscripciones.")) { return; } setActionLoading("bracket"); try { const response = await fetch(`/api/tournaments/${tournamentId}/generate-bracket`, { method: "POST", }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Error al generar bracket"); } await fetchTournament(); setActiveTab("bracket"); } catch (err) { alert(err instanceof Error ? err.message : "Error desconocido"); } finally { setActionLoading(null); } }; const handleDelete = async () => { if (!tournament) return; if (tournament.status !== "DRAFT") { alert("Solo se pueden eliminar torneos en estado Borrador"); return; } if (!confirm("¿Estas seguro de eliminar este torneo? Esta accion no se puede deshacer.")) { return; } setActionLoading("delete"); try { const response = await fetch(`/api/tournaments/${tournamentId}`, { method: "DELETE", }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Error al eliminar torneo"); } router.push("/tournaments"); } catch (err) { alert(err instanceof Error ? err.message : "Error desconocido"); } finally { setActionLoading(null); } }; const handleUpdateTournament = async (data: { name: string; description: string; date: string; endDate: string; type: string; category: string; maxTeams: number; price: number; siteId: string; }) => { setActionLoading("edit"); try { const response = await fetch(`/api/tournaments/${tournamentId}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: data.name, description: data.description, date: new Date(data.date).toISOString(), endDate: data.endDate ? new Date(data.endDate).toISOString() : null, type: data.type, category: data.category || null, maxTeams: data.maxTeams, price: data.price, }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Error al actualizar torneo"); } setShowEditForm(false); await fetchTournament(); } catch (err) { throw err; } finally { setActionLoading(null); } }; const handleRemoveInscription = async (inscriptionId: string) => { try { const response = await fetch( `/api/tournaments/${tournamentId}/inscriptions/${inscriptionId}`, { method: "DELETE" } ); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Error al eliminar inscripcion"); } await fetchTournament(); } catch (err) { alert(err instanceof Error ? err.message : "Error desconocido"); } }; const handleTogglePaid = async (inscriptionId: string, isPaid: boolean) => { try { const response = await fetch( `/api/tournaments/${tournamentId}/inscriptions/${inscriptionId}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ isPaid }), } ); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Error al actualizar pago"); } await fetchTournament(); } catch (err) { alert(err instanceof Error ? err.message : "Error desconocido"); } }; const handleSaveMatchScore = async ( matchId: string, data: { score1: number[]; score2: number[]; winnerId: string; status: string; } ) => { const response = await fetch( `/api/tournaments/${tournamentId}/matches/${matchId}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), } ); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Error al guardar resultado"); } setSelectedMatch(null); await fetchTournament(); }; if (loading) { return (

Cargando torneo...

); } if (error) { return (

{error}

); } if (!tournament) return null; const status = statusConfig[tournament.status] || statusConfig.DRAFT; const typeLabel = typeLabels[tournament.type] || tournament.type; const entryFee = typeof tournament.entryFee === "string" ? parseFloat(tournament.entryFee) : tournament.entryFee; const canEdit = ["DRAFT", "REGISTRATION_OPEN"].includes(tournament.status); const canGenerateBracket = tournament.status === "REGISTRATION_OPEN" && tournament.inscriptions.length >= 2; const canOpenRegistration = tournament.status === "DRAFT"; const canDelete = tournament.status === "DRAFT"; return (
{/* Header */}

{tournament.name}

{status.label}
{tournament.description && (

{tournament.description}

)}
{/* Actions */}
{canEdit && ( )} {canOpenRegistration && ( )} {canGenerateBracket && ( )} {canDelete && ( )}
{/* Edit Form Modal */} {showEditForm && (
setShowEditForm(false)} isLoading={actionLoading === "edit"} mode="edit" />
)} {/* Match Score Dialog */} {selectedMatch && ( setSelectedMatch(null)} /> )} {/* Tabs */}
{tabs.map((tab) => ( ))}
{/* Tab Content */}
{/* Overview Tab */} {activeTab === "overview" && (
{/* Tournament Info */} Informacion del Torneo

Tipo

{typeLabel}

Categoria

{tournament.settings?.category || "Sin categoria"}

Fecha de Inicio

{formatDate(tournament.startDate)}

Fecha de Fin

{tournament.endDate ? formatDate(tournament.endDate) : "-"}

Precio Inscripcion

{entryFee > 0 ? formatCurrency(entryFee) : "Gratis"}

Maximo Equipos

{tournament.maxPlayers || "Sin limite"}

{/* Site Info */}

Sede

{tournament.site.name}

{tournament.site.address && (

{tournament.site.address}

)} {tournament.site.phone && (

{tournament.site.phone}

)}
{/* Stats */}

{tournament._count.inscriptions}

{tournament.maxPlayers ? `de ${tournament.maxPlayers} equipos` : "equipos inscritos"}

{tournament.maxPlayers && (
)} {tournament.matches.length > 0 && (

{tournament.matches.filter((m) => m.status === "COMPLETED").length}

de {tournament.matches.length} partidos jugados

)}
)} {/* Inscriptions Tab */} {activeTab === "inscriptions" && ( )} {/* Bracket Tab */} {activeTab === "bracket" && ( setSelectedMatch(match) : undefined } /> )}
); }