import { useState, useEffect } from "react"; import { TournamentList } from "./components/TournamentList"; import { TournamentSetup } from "./components/TournamentSetup"; import { TournamentHeader } from "./components/TournamentHeader"; import { ParticipantList } from "./components/ParticipantList"; import { ParticipantRegistration } from "./components/ParticipantRegistration"; import { RoundPairings } from "./components/RoundPairings"; import { Standings } from "./components/Standings"; import { FinalStandings } from "./components/FinalStandings"; import { AuthForm } from "./components/AuthForm"; import { Button } from "./components/ui/button"; import { Card } from "./components/ui/card"; import { List, Home, LogOut, Trophy } from "lucide-react"; import { getUserProfile, signOut, onAuthStateChange, type UserProfile } from "./utils/auth"; import * as api from "./utils/api"; import type { PlayerAction } from "./components/PlayerActionsMenu"; interface Tournoi { id : chaîne de caractères ; nom : chaîne de caractères ; totalRounds : nombre ; tour actuel : nombre ; joueurs : chaîne[] ; système de points : chaîne de caractères ; région : chaîne de caractères ; adresse : chaîne de caractères ; logo ?: chaîne de caractères ; crééPar ?: chaîne de caractères ; crééParRôle ?: chaîne ; statut : « en attente » | « actif » | « terminé » ; tours : Tableau<{ roundNumber : nombre ; appariements : Tableau<{ tableau : nombre ; joueurs : chaîne[] ; résultats : chaîne[] | null ; }>; }>; } type ViewMode = "list" | "create" | "view" | "login"; export default function App() { const [utilisateur, setUser] = useState (nul); const [authLoading, setAuthLoading] = useState(true); const [viewMode, setViewMode] = useState ("liste"); const [tournoi, setTournoi] = utiliser l'état (nul); const [selectedRound, setSelectedRound] = useState(1); const [showStandings, setShowStandings] = useState(false); const [chargement, setLoading] = useState(false); const [erreur, setErreur] = utiliserÉtat (nul); const [participantRefreshTrigger, setParticipantRefreshTrigger] = useState(0); utiliserEffect(() => { // Vérifier l'état d'authentification initial vérifierUtilisateur(); // Surveiller les changements d'authentification const { data: authListener } = onAuthStateChange(() => { vérifierUtilisateur(); }); retourner () => { authListener?.subscription.unsubscribe(); }; }, []); const checkUser = async () => { essayer { const profil = await getUserProfile(); définirUtilisateur(profil); } attraper (erreur) { console.error("Erreur lors de la vérification de l'utilisateur :", err); définirUtilisateur(null); } enfin { définirAuthLoading(false); } }; const handleSignOut = async () => { essayer { attendre la déconnexion(); définirUtilisateur(null); définirTournoi(null); définirViewMode("liste"); } attraper (erreur) { console.error("Erreur lors de la déconnexion :", err); } }; const currentRoundData = tournament?.rounds.find( (r) => r.roundNumber === selectedRound, ); const handleCreateTournament = async (data: { nom : chaîne de caractères ; totalRounds : nombre ; joueurs : chaîne[] ; système de points : chaîne de caractères ; région : chaîne de caractères ; adresse : chaîne de caractères ; logo ?: chaîne de caractères ; }) => { essayer { définirChargement(true); définirErreur(null); console.log("Création du tournoi avec les données :", data); const userContext = utilisateur ? { user_id: user.id, role: user.role } : indéfini ; const résultat = await api.createTournament( données, contexte utilisateur, ); console.log("Tournoi créé avec succès :", résultat); définirTournoi(résultat.tournoi); définirSelectedRound(1); définirViewMode("vue"); } catch (err: any) { console.error("Échec de la création du tournoi :", err); définirErreur( err.message || "Impossible de créer le tournoi. Veuillez réessayer." ); } enfin { définirChargement(false); } }; const handleDeleteTournament = async ( tournoiId : chaîne de caractères, ) => { si ( !confirmer( « Êtes-vous sûr de vouloir supprimer ce tournoi ? Cette action est irréversible. » ) ) { retour; } essayer { définirChargement(true); définirErreur(null); const userContext = utilisateur ? { user_id: user.id, role: user.role } : indéfini ; attendre api.deleteTournament(tournamentId, userContext); gérerRetourÀLaListe(); } catch (err: any) { console.error("Échec de la suppression du tournoi :", err); définirErreur( err.message || "Échec de la suppression du tournoi. Veuillez réessayer." ); } enfin { définirChargement(false); } }; const handleStartTournament = async () => { si (!tournoi) retourner; essayer { définirChargement(true); définirErreur(null); const userContext = utilisateur ? { user_id: user.id, role: user.role } : indéfini ; const updatedTournament = await api.startTournament( tournoi.id, contexte utilisateur, ); définirTournoi(tournoimisàjour); } catch (err: any) { console.error("Échec du démarrage du tournoi :", err); définirErreur( err.message || "Impossible de démarrer le tournoi. Veuillez réessayer." ); } enfin { définirChargement(false); } }; const handleSelectTournament = ( tournoi sélectionné : Tournoi, ) => { définirTournoi(tournoi sélectionné); définirTourSélectionné(tournoiSélectionné.tournoiActuel); afficherLesPoints(false); définirViewMode("vue"); }; const handleBackToList = () => { définirViewMode("liste"); définirTournoi(null); définirSelectedRound(1); afficherLesPoints(false); définirErreur(null); }; const handleCreateNew = () => { définirViewMode("créer"); définirTournoi(null); définirSelectedRound(1); afficherLesPoints(false); définirErreur(null); }; const handleSetPairings = async ( nombre rond : nombre, appariements : n'importe quel[], ) => { si (!tournoi) retourner; essayer { définirChargement(true); const updatedTournament = await api.setPairings( tournoi.id, nombre rond, appariements, ); définirTournoi(tournoimisàjour); } attraper (erreur) { console.error("Échec de la configuration des appariements :", err); setError("Échec de la configuration des appariements. Veuillez réessayer."); } enfin { définirChargement(false); } }; const handleUpdateResults = async ( roundNumber : nombre, tableNumber: numéro, résultats : chaîne[], ) => { si (!tournoi) retourner; essayer { définirChargement(true); const updatedTournament = await api.updateTableResults( tournoi.id, nombre rond, numéro_de_table, résultats, ); définirTournoi(tournoimisàjour); } attraper (erreur) { console.error("Échec de la mise à jour des résultats :", err); setError("Échec de la mise à jour des résultats. Veuillez réessayer."); } enfin { définirChargement(false); } }; const handleConfirmResults = async () => { si (!tournoi) retourner; essayer { définirChargement(true); définirErreur(null); const userContext = utilisateur ? { user_id: user.id, role: user.role } : indéfini ; const updatedTournament = await api.confirmRoundResults( tournoi.id, sélectionnéRound, contexte utilisateur, ); définirTournoi(tournoimisàjour); // Passer au tour suivant s'il a été généré si (updatedTournament.currentRound > selectedRound) { définirTourSélectionné(tournoimis.tournoiactuel); setShowStandings(false); // Afficher le nouveau tour, pas le classement } alert('Résultats confirmés ! Les appariements du prochain tour ont été générés.'); } catch (err: any) { console.error("Échec de la confirmation des résultats :", err); // Afficher un message d'erreur convivial const errorMsg = err.message || "Échec de la confirmation des résultats. Veuillez réessayer."; alerte(`❌ ${errorMsg}`); définirErreur(messageErreur); } enfin { définirChargement(false); } }; const handlePlayerAction = async (tableNumber: number, playerIndex: number, action: PlayerAction) => { si (!tournoi) retourner; si (action.type === 'move') { // Échanger les joueurs entre les tables/sièges essayer { définirChargement(true); const userContext = user ? { user_id: user.id, role: user.role } : undefined; const updatedTournament = await api.swapPlayers( tournoi.id, sélectionnéRound, numéro_de_table, index du joueur, action.toTable, action.toSeat, contexte utilisateur ); définirTournoi(tournoimisàjour); } catch (err: any) { console.error('Échec du changement de joueur :', err); setError(err.message || 'Échec du changement de joueur. Veuillez réessayer.'); } enfin { définirChargement(false); } } autre { // Gérer les autres actions (banc, au revoir, abandonné) console.log('Action du joueur :', { tableNumber, playerIndex, action }); // À FAIRE : Implémenter d’autres actions } }; const handleParticipantRegistered = () => { // Incrémenter le déclencheur d'actualisation pour forcer le rechargement de ParticipantList définirParticipantRefreshTrigger(précédent => précédent + 1); }; // État de chargement si (authLoading) { retour (

Chargement...

); } const peutCréerTournoi = utilisateur && (utilisateur.rôle === "à" || utilisateur.rôle === "admin"); const peutSupprimerTournoi = (donnéesTournoi: Tournoi) => { si (!utilisateur) retourner faux ; si (user.role === "admin") retourner vrai ; si ( user.role === "à" && tournamentData.createdBy === user.id ) renvoyer vrai ; renvoyer faux ; }; const canEditResults = user && user.role !== "participant"; // Vérifier si l'utilisateur actuel est le créateur du tournoi et s'il peut le modifier const canEditTournament = utilisateur && tournoi && ( user.role === "admin" || (user.role === "to" && tournament.createdBy === user.id) ); // Vue de la liste des tournois si (viewMode === "liste") { retour (
{utilisateur ? ( <>

Connecté en tant que :{" "} {user.email} {user.role.toUpperCase()}

> ) : ( className="ml-auto bg-red-600 hover:bg-red-700" > Connexion / Inscription )}
définirViewMode("connexion" comme n'importe quel) } peutCréer={!!peutCréerTournoi || !utilisateur} userRole={user?.role} userId={user?.id} />
); } // Vue de connexion si (viewMode === "login") { retour (
{ vérifierUtilisateur(); gérerRetourÀLaListe(); }} />
); } // Créer une vue de tournoi si (viewMode === "create") { si (!utilisateur) { définirViewMode("connexion"); renvoyer null ; } si (!canCreateTournament) { retour (

Vous n'êtes pas autorisé à créer des tournois.

); } retour (
{utilisateur && ( )}
{erreur && (
{erreur}
)}
); } // Vue du tournoi si (!tournoi) { retour (

Tournoi introuvable.

); } // Vérifier si le tournoi est terminé (tous les tours existent ET le dernier tour a tous ses résultats) const isTournamentComplete = tournament.status === "active" && tournament.rounds.length === tournament.totalRounds && tournoi.tournoiActuel === tournoi.totalTours && (() => { // Obtenez le dernier tour const lastRound = tournament.rounds[tournament.rounds.length - 1]; si (!lastRound) retourner faux ; // Vérifier si toutes les tables non-BYE du dernier tour ont des résultats retourner lastRound.pairings.every(p => p.results !== null || p.players.some(player => player === 'BYE') ); })(); // Afficher le classement final si le tournoi est terminé si (isTournamentComplete) { retour ( ); } retour (
{peutCréerTournoi && ( )} {tournoi && peutSupprimerTournoi(tournoi) && ( )}
{utilisateur ? ( ) : ( )}
{erreur && (
{erreur}
)}
{/* Contenu du tournoi */} {tournament.status === "en attente" ? (
) : ( <> {/* Navigation circulaire */}
{/* Boutons ronds */} {Array.from({ length: tournament.totalRounds }, (_, i) => i + 1).map((roundNum) => ( ))} {/* Bouton Classement - Masqué pour les tournois ELO (le classement final s'affiche une fois le tournoi terminé) */} {tournament.pointSystem !== "ELO" && ( )}
{/* Contenu - afficher le classement ou les appariements des tours */} {afficher les classements ? ( ) : ( currentRoundData && ( gérerRésultatsDeMiseÀJour( sélectionnéRound, numéro_de_table, résultats, ) : non défini } onSetPairings={ peutModifierTournoi ? (appariements) => gérerSetPairings( sélectionnéRound, appariements, ) : non défini } onConfirmResults={ peutModifierTournoi ? gérerConfirmerLesRésultats : non défini } onPlayerAction={ peutModifierTournoi ? handlePlayerAction : non défini } tournoiId={tournoi.id} nom_du_tournoi={nom.du_tournoi} pointSystem={tournament.pointSystem} /> ) )} > )}
); }