tttt / index.html
KINGFAUS's picture
Add 3 files
3082151 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FIFA Tournament Pro</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Inter', sans-serif;
transition: all 0.3s ease;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
animation: fadeIn 0.3s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.toast {
position: fixed;
bottom: 20px;
right: 20px;
transform: translateY(100px);
opacity: 0;
transition: all 0.3s ease;
z-index: 1000;
}
.toast.show {
transform: translateY(0);
opacity: 1;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
z-index: 100;
justify-content: center;
align-items: center;
}
.modal.active {
display: flex;
animation: fadeIn 0.3s ease-out;
}
.modal-content {
background-color: white;
padding: 2rem;
border-radius: 0.5rem;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
}
.dark .modal-content {
background-color: #1f2937;
}
.match-card {
transition: all 0.2s ease;
}
.match-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.dark .match-card:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
}
.pronostic-correct {
background-color: #d1fae5 !important;
border-left: 4px solid #10b981;
}
.pronostic-incorrect {
background-color: #fee2e2 !important;
border-left: 4px solid #ef4444;
}
.phase-finale {
border-left: 4px solid #f59e0b;
}
.winner-card {
animation: pulse 2s infinite;
border: 2px solid #f59e0b;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.4); }
70% { box-shadow: 0 0 0 10px rgba(245, 158, 11, 0); }
100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); }
}
.goat-title {
background: linear-gradient(45deg, #f59e0b, #ef4444, #3b82f6);
background-size: 200% 200%;
animation: gradient 3s ease infinite;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
@keyframes gradient {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
}
::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
.dark ::-webkit-scrollbar-track {
background: #374151;
}
.dark ::-webkit-scrollbar-thumb {
background: #6b7280;
}
.dark ::-webkit-scrollbar-thumb:hover {
background: #9ca3af;
}
/* Hide scrollbar but keep functionality */
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
</style>
</head>
<body class="bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="flex justify-between items-center mb-8">
<div class="flex items-center gap-4">
<div class="w-12 h-12 bg-blue-500 rounded-lg flex items-center justify-center text-white">
<i class="fas fa-trophy text-xl"></i>
</div>
<h1 id="tournamentTitle" class="text-3xl font-bold bg-gradient-to-r from-blue-500 to-yellow-500 bg-clip-text text-transparent">
FIFA Tournament Pro
</h1>
</div>
<div class="flex items-center gap-4">
<div class="text-sm bg-gray-200 dark:bg-gray-700 px-3 py-1 rounded-lg">
<i class="fas fa-calendar-day mr-2"></i>
<span id="currentDate"></span>
</div>
<button id="themeToggle" class="w-10 h-10 rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center hover:bg-gray-300 dark:hover:bg-gray-600 transition">
<i class="fas fa-moon dark:hidden"></i>
<i class="fas fa-sun hidden dark:block"></i>
</button>
</div>
</header>
<!-- Navigation -->
<nav class="flex overflow-x-auto pb-2 mb-8 gap-2 scrollbar-hide">
<button class="tab-btn active px-4 py-2 rounded-lg font-medium bg-blue-500 text-white hover:bg-blue-600 transition" data-tab="dashboard">
<i class="fas fa-home mr-2"></i>Dashboard
</button>
<button class="tab-btn px-4 py-2 rounded-lg font-medium hover:bg-gray-200 dark:hover:bg-gray-700 transition" data-tab="players">
<i class="fas fa-users mr-2"></i>Joueurs
</button>
<button class="tab-btn px-4 py-2 rounded-lg font-medium hover:bg-gray-200 dark:hover:bg-gray-700 transition" data-tab="schedule">
<i class="fas fa-calendar-alt mr-2"></i>Calendrier
</button>
<button class="tab-btn px-4 py-2 rounded-lg font-medium hover:bg-gray-200 dark:hover:bg-gray-700 transition" data-tab="results">
<i class="fas fa-chart-bar mr-2"></i>Résultats
</button>
<button class="tab-btn px-4 py-2 rounded-lg font-medium hover:bg-gray-200 dark:hover:bg-gray-700 transition" data-tab="pronostics">
<i class="fas fa-binoculars mr-2"></i>Pronostics
</button>
<button class="tab-btn px-4 py-2 rounded-lg font-medium hover:bg-gray-200 dark:hover:bg-gray-700 transition" data-tab="settings">
<i class="fas fa-cog mr-2"></i>Paramètres
</button>
</nav>
<!-- Dashboard Tab -->
<div id="dashboard" class="tab-content active">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<!-- Tournament Stats -->
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow">
<h2 class="text-xl font-bold mb-4 flex items-center gap-2">
<i class="fas fa-chart-pie"></i> Statistiques
</h2>
<div class="grid grid-cols-2 gap-4">
<div class="bg-gray-100 dark:bg-gray-700 p-3 rounded-lg">
<div class="text-sm text-gray-500 dark:text-gray-400">
<i class="fas fa-users mr-1"></i> Joueurs
</div>
<div class="text-2xl font-bold" id="playerCount">0</div>
</div>
<div class="bg-gray-100 dark:bg-gray-700 p-3 rounded-lg">
<div class="text-sm text-gray-500 dark:text-gray-400">
<i class="fas fa-gamepad mr-1"></i> Matchs
</div>
<div class="text-2xl font-bold" id="matchCount">0</div>
</div>
<div class="bg-gray-100 dark:bg-gray-700 p-3 rounded-lg">
<div class="text-sm text-gray-500 dark:text-gray-400">
<i class="fas fa-check-circle mr-1"></i> Terminés
</div>
<div class="text-2xl font-bold" id="completedCount">0</div>
</div>
<div class="bg-gray-100 dark:bg-gray-700 p-3 rounded-lg">
<div class="text-sm text-gray-500 dark:text-gray-400">
<i class="fas fa-clock mr-1"></i> À venir
</div>
<div class="text-2xl font-bold" id="upcomingCount">0</div>
</div>
</div>
</div>
<!-- Next Match -->
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow">
<h2 class="text-xl font-bold mb-4 flex items-center gap-2">
<i class="fas fa-clock"></i> Prochain Match
</h2>
<div class="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg match-card" id="nextMatchCard">
<div class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-calendar-plus text-4xl mb-2"></i>
<p>Aucun match programmé</p>
</div>
</div>
</div>
<!-- Tournament Winner -->
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow" id="winnerCardContainer">
<h2 class="text-xl font-bold mb-4 flex items-center gap-2">
<i class="fas fa-trophy"></i> Champion en titre
</h2>
<div class="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg text-center" id="winnerCard">
<div class="py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-trophy text-4xl mb-2"></i>
<p>Aucun vainqueur encore</p>
</div>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow mb-6">
<h2 class="text-xl font-bold mb-4 flex items-center gap-2">
<i class="fas fa-bolt"></i> Actions Rapides
</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center justify-center gap-2 transition" data-tab-target="players">
<i class="fas fa-user-plus"></i> Ajouter Joueur
</button>
<button class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg flex items-center justify-center gap-2 transition" id="createMatchBtn">
<i class="fas fa-calendar-plus"></i> Créer Match
</button>
<button class="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-lg flex items-center justify-center gap-2 transition" data-tab-target="results">
<i class="fas fa-trophy"></i> Voir Classement
</button>
<button class="bg-yellow-500 hover:bg-yellow-600 text-white px-4 py-2 rounded-lg flex items-center justify-center gap-2 transition" id="generateTournamentBtn">
<i class="fas fa-random"></i> Générer Tournoi
</button>
</div>
</div>
<!-- Recent Results -->
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow">
<h2 class="text-xl font-bold mb-4 flex items-center gap-2">
<i class="fas fa-history"></i> Derniers Résultats
</h2>
<div class="space-y-3" id="recentResults">
<!-- Results will be added here -->
<div class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-info-circle text-4xl mb-2"></i>
<p>Aucun résultat récent</p>
</div>
</div>
</div>
</div>
<!-- Players Tab -->
<div id="players" class="tab-content">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Player Registration -->
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow">
<h2 class="text-xl font-bold mb-4 flex items-center gap-2">
<i class="fas fa-user-plus"></i> Inscription Joueur
</h2>
<form id="playerForm" class="space-y-4">
<input type="hidden" id="playerId">
<div>
<label class="block mb-1 font-medium">Nom complet</label>
<input type="text" id="playerName" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" required>
</div>
<div>
<label class="block mb-1 font-medium">Niveau (1-10)</label>
<input type="number" id="playerLevel" min="1" max="10" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" value="5">
</div>
<div>
<label class="block mb-1 font-medium">Équipe favorite</label>
<select id="playerTeam" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700">
<option value="">Aucune</option>
<option value="PSG">PSG</option>
<option value="Real Madrid">Real Madrid</option>
<option value="FC Barcelone">FC Barcelone</option>
<option value="Manchester City">Manchester City</option>
<option value="Bayern Munich">Bayern Munich</option>
<option value="Liverpool">Liverpool</option>
<option value="Juventus">Juventus</option>
<option value="Inter Milan">Inter Milan</option>
</select>
</div>
<div>
<label class="block mb-1 font-medium">Participation (€)</label>
<input type="number" id="playerParticipation" min="0" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" value="0">
</div>
<button type="submit" class="bg-blue-500 hover:bg-blue-600 text-white w-full py-2 rounded-lg flex items-center justify-center gap-2 transition">
<i class="fas fa-save"></i> Enregistrer
</button>
</form>
</div>
<!-- Players List -->
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow md:col-span-2">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold flex items-center gap-2">
<i class="fas fa-list"></i> Liste des Joueurs
</h2>
<div class="relative w-64">
<input type="text" id="playerSearch" placeholder="Rechercher un joueur..." class="w-full p-2 pl-8 border rounded-lg bg-white dark:bg-gray-700">
<i class="fas fa-search absolute left-2 top-3 text-gray-400"></i>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full">
<thead>
<tr class="border-b border-gray-200 dark:border-gray-700">
<th class="text-left py-3 px-4">Nom</th>
<th class="text-left py-3 px-4">Niveau</th>
<th class="text-left py-3 px-4">Équipe</th>
<th class="text-left py-3 px-4">Participation</th>
<th class="text-left py-3 px-4">Actions</th>
</tr>
</thead>
<tbody id="playersList">
<!-- Players will be added here -->
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Schedule Tab -->
<div id="schedule" class="tab-content">
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold flex items-center gap-2">
<i class="fas fa-calendar"></i> Calendrier des Matchs
</h2>
<button id="createNewMatchBtn" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg flex items-center gap-2 transition">
<i class="fas fa-plus"></i> Nouveau Match
</button>
</div>
<div class="mb-4 flex items-center gap-4">
<div class="flex-1">
<label class="block mb-1 font-medium">Filtrer par date</label>
<input type="date" id="dateFilter" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700">
</div>
<div class="flex-1">
<label class="block mb-1 font-medium">Filtrer par statut</label>
<select id="statusFilter" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700">
<option value="all">Tous</option>
<option value="upcoming">À venir</option>
<option value="completed">Terminés</option>
</select>
</div>
</div>
<div class="space-y-4" id="matchesList">
<!-- Matches will be added here -->
<div class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-calendar-plus text-4xl mb-2"></i>
<p>Aucun match programmé</p>
</div>
</div>
</div>
</div>
<!-- Results Tab -->
<div id="results" class="tab-content">
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow">
<h2 class="text-xl font-bold mb-4 flex items-center gap-2">
<i class="fas fa-trophy"></i> Classement des Joueurs
</h2>
<div class="overflow-x-auto">
<table class="min-w-full">
<thead>
<tr class="border-b border-gray-200 dark:border-gray-700">
<th class="text-left py-3 px-4">#</th>
<th class="text-left py-3 px-4">Joueur</th>
<th class="text-left py-3 px-4">Matchs</th>
<th class="text-left py-3 px-4">Victoires</th>
<th class="text-left py-3 px-4">Nuls</th>
<th class="text-left py-3 px-4">Défaites</th>
<th class="text-left py-3 px-4">Points</th>
</tr>
</thead>
<tbody id="rankingList">
<!-- Ranking will be added here -->
<tr>
<td colspan="7" class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-info-circle text-4xl mb-2"></i>
<p>Aucun résultat disponible</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Pronostics Tab -->
<div id="pronostics" class="tab-content">
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow">
<h2 class="text-xl font-bold mb-4 flex items-center gap-2">
<i class="fas fa-binoculars"></i> Mes Pronostics
</h2>
<div class="space-y-4" id="pronosticsList">
<!-- Pronostics will be added here -->
<div class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-info-circle text-4xl mb-2"></i>
<p>Aucun pronostic enregistré</p>
</div>
</div>
</div>
</div>
<!-- Settings Tab -->
<div id="settings" class="tab-content">
<div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow">
<h2 class="text-xl font-bold mb-4 flex items-center gap-2">
<i class="fas fa-cog"></i> Paramètres du Tournoi
</h2>
<form id="settingsForm" class="space-y-4">
<div>
<label class="block mb-1 font-medium">Nom du tournoi</label>
<input type="text" id="tournamentName" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" value="FIFA Tournament Pro">
</div>
<div>
<label class="block mb-1 font-medium">Type de tournoi</label>
<select id="tournamentType" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700">
<option value="league">Championnat</option>
<option value="knockout">Élimination directe</option>
<option value="groups">Groupes + Phase finale</option>
</select>
</div>
<div>
<label class="block mb-1 font-medium">Points pour une victoire</label>
<input type="number" id="winPoints" min="1" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" value="3">
</div>
<div>
<label class="block mb-1 font-medium">Points pour un nul</label>
<input type="number" id="drawPoints" min="0" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" value="1">
</div>
<div>
<label class="block mb-1 font-medium">Points pour une défaite</label>
<input type="number" id="lossPoints" min="0" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" value="0">
</div>
<button type="submit" class="bg-blue-500 hover:bg-blue-600 text-white w-full py-2 rounded-lg flex items-center justify-center gap-2 transition">
<i class="fas fa-save"></i> Enregistrer les paramètres
</button>
</form>
</div>
</div>
<!-- Create Match Modal -->
<div id="matchModal" class="modal">
<div class="modal-content">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold" id="matchModalTitle">Nouveau Match</h3>
<button id="closeMatchModal" class="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">
<i class="fas fa-times"></i>
</button>
</div>
<form id="matchForm" class="space-y-4">
<input type="hidden" id="matchId">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block mb-1 font-medium">Joueur 1</label>
<select id="player1" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" required>
<option value="">Sélectionner un joueur</option>
</select>
</div>
<div>
<label class="block mb-1 font-medium">Joueur 2</label>
<select id="player2" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" required>
<option value="">Sélectionner un joueur</option>
</select>
</div>
</div>
<div>
<label class="block mb-1 font-medium">Date et heure</label>
<input type="datetime-local" id="matchDateTime" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" required>
</div>
<div>
<label class="block mb-1 font-medium">Phase</label>
<select id="matchPhase" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700">
<option value="group">Groupe</option>
<option value="round16">8ème de finale</option>
<option value="quarter">Quart de finale</option>
<option value="semi">Demi-finale</option>
<option value="final">Finale</option>
</select>
</div>
<div id="scoreFields" class="hidden">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block mb-1 font-medium">Score Joueur 1</label>
<input type="number" id="score1" min="0" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" value="0">
</div>
<div>
<label class="block mb-1 font-medium">Score Joueur 2</label>
<input type="number" id="score2" min="0" class="w-full p-2 border rounded-lg bg-white dark:bg-gray-700" value="0">
</div>
</div>
</div>
<div class="flex justify-between pt-4">
<button type="button" id="toggleScoreFields" class="bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 px-4 py-2 rounded-lg transition">
<i class="fas fa-futbol mr-2"></i> Ajouter score
</button>
<button type="submit" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center gap-2 transition">
<i class="fas fa-save"></i> Enregistrer
</button>
</div>
</form>
</div>
</div>
<!-- Toast Notification -->
<div id="toast" class="toast bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg">
<div class="flex items-center">
<i class="fas fa-check-circle mr-2"></i>
<span id="toastMessage">Opération réussie</span>
</div>
</div>
</div>
<script>
// Data storage
let players = [];
let matches = [];
let tournamentSettings = {
name: "FIFA Tournament Pro",
type: "league",
winPoints: 3,
drawPoints: 1,
lossPoints: 0
};
// DOM Elements
const tabButtons = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');
const themeToggle = document.getElementById('themeToggle');
const currentDateElement = document.getElementById('currentDate');
const playerForm = document.getElementById('playerForm');
const playerIdInput = document.getElementById('playerId');
const playerNameInput = document.getElementById('playerName');
const playerLevelInput = document.getElementById('playerLevel');
const playerTeamInput = document.getElementById('playerTeam');
const playerParticipationInput = document.getElementById('playerParticipation');
const playersList = document.getElementById('playersList');
const playerSearch = document.getElementById('playerSearch');
const playerCountElement = document.getElementById('playerCount');
const matchCountElement = document.getElementById('matchCount');
const completedCountElement = document.getElementById('completedCount');
const upcomingCountElement = document.getElementById('upcomingCount');
const nextMatchCard = document.getElementById('nextMatchCard');
const winnerCard = document.getElementById('winnerCard');
const recentResults = document.getElementById('recentResults');
const createMatchBtn = document.getElementById('createMatchBtn');
const generateTournamentBtn = document.getElementById('generateTournamentBtn');
const matchModal = document.getElementById('matchModal');
const closeMatchModal = document.getElementById('closeMatchModal');
const matchForm = document.getElementById('matchForm');
const matchIdInput = document.getElementById('matchId');
const player1Select = document.getElementById('player1');
const player2Select = document.getElementById('player2');
const matchDateTimeInput = document.getElementById('matchDateTime');
const matchPhaseSelect = document.getElementById('matchPhase');
const scoreFields = document.getElementById('scoreFields');
const score1Input = document.getElementById('score1');
const score2Input = document.getElementById('score2');
const toggleScoreFields = document.getElementById('toggleScoreFields');
const matchesList = document.getElementById('matchesList');
const dateFilter = document.getElementById('dateFilter');
const statusFilter = document.getElementById('statusFilter');
const rankingList = document.getElementById('rankingList');
const pronosticsList = document.getElementById('pronosticsList');
const settingsForm = document.getElementById('settingsForm');
const tournamentNameInput = document.getElementById('tournamentName');
const tournamentTypeSelect = document.getElementById('tournamentType');
const winPointsInput = document.getElementById('winPoints');
const drawPointsInput = document.getElementById('drawPoints');
const lossPointsInput = document.getElementById('lossPoints');
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
const tournamentTitle = document.getElementById('tournamentTitle');
const createNewMatchBtn = document.getElementById('createNewMatchBtn');
// Initialize the app
function init() {
// Set current date
const now = new Date();
currentDateElement.textContent = now.toLocaleDateString('fr-FR', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
// Load data from localStorage if available
loadData();
// Setup event listeners
setupEventListeners();
// Render initial data
renderPlayers();
renderMatches();
updateStats();
updateNextMatch();
updateRecentResults();
updateRanking();
updateTournamentSettingsUI();
}
// Load data from localStorage
function loadData() {
const savedPlayers = localStorage.getItem('fifaPlayers');
const savedMatches = localStorage.getItem('fifaMatches');
const savedSettings = localStorage.getItem('fifaSettings');
if (savedPlayers) players = JSON.parse(savedPlayers);
if (savedMatches) matches = JSON.parse(savedMatches);
if (savedSettings) tournamentSettings = JSON.parse(savedSettings);
// Update tournament title
tournamentTitle.textContent = tournamentSettings.name;
tournamentTitle.classList.add('goat-title');
}
// Save data to localStorage
function saveData() {
localStorage.setItem('fifaPlayers', JSON.stringify(players));
localStorage.setItem('fifaMatches', JSON.stringify(matches));
localStorage.setItem('fifaSettings', JSON.stringify(tournamentSettings));
}
// Setup event listeners
function setupEventListeners() {
// Tab navigation
tabButtons.forEach(button => {
button.addEventListener('click', () => {
const tabId = button.getAttribute('data-tab');
switchTab(tabId);
});
});
// Quick action buttons that switch tabs
document.querySelectorAll('[data-tab-target]').forEach(button => {
button.addEventListener('click', () => {
const tabId = button.getAttribute('data-tab-target');
switchTab(tabId);
});
});
// Theme toggle
themeToggle.addEventListener('click', toggleTheme);
// Player form
playerForm.addEventListener('submit', handlePlayerFormSubmit);
// Player search
playerSearch.addEventListener('input', () => {
renderPlayers(playerSearch.value.toLowerCase());
});
// Create match button
createMatchBtn.addEventListener('click', openMatchModal);
createNewMatchBtn.addEventListener('click', openMatchModal);
// Match modal
closeMatchModal.addEventListener('click', closeMatchModalFunc);
matchForm.addEventListener('submit', handleMatchFormSubmit);
toggleScoreFields.addEventListener('click', toggleScoreFieldsFunc);
// Date filter
dateFilter.addEventListener('change', () => {
renderMatches();
});
// Status filter
statusFilter.addEventListener('change', () => {
renderMatches();
});
// Settings form
settingsForm.addEventListener('submit', handleSettingsFormSubmit);
// Generate tournament button
generateTournamentBtn.addEventListener('click', generateRandomTournament);
}
// Switch between tabs
function switchTab(tabId) {
// Update active tab button
tabButtons.forEach(button => {
button.classList.remove('active', 'bg-blue-500', 'text-white');
button.classList.add('hover:bg-gray-200', 'dark:hover:bg-gray-700');
if (button.getAttribute('data-tab') === tabId) {
button.classList.add('active', 'bg-blue-500', 'text-white');
button.classList.remove('hover:bg-gray-200', 'dark:hover:bg-gray-700');
}
});
// Update active tab content
tabContents.forEach(content => {
content.classList.remove('active');
if (content.id === tabId) {
content.classList.add('active');
// Refresh data when switching to certain tabs
if (tabId === 'players') {
renderPlayers();
} else if (tabId === 'schedule') {
renderMatches();
} else if (tabId === 'results') {
updateRanking();
}
}
});
}
// Toggle dark/light theme
function toggleTheme() {
document.documentElement.classList.toggle('dark');
localStorage.setItem('darkMode', document.documentElement.classList.contains('dark'));
}
// Check for saved theme preference
if (localStorage.getItem('darkMode') === 'true') {
document.documentElement.classList.add('dark');
}
// Handle player form submission
function handlePlayerFormSubmit(e) {
e.preventDefault();
const playerData = {
id: playerIdInput.value || Date.now().toString(),
name: playerNameInput.value,
level: parseInt(playerLevelInput.value),
team: playerTeamInput.value,
participation: parseFloat(playerParticipationInput.value) || 0,
matchesPlayed: 0,
wins: 0,
draws: 0,
losses: 0,
points: 0
};
if (playerIdInput.value) {
// Update existing player
const index = players.findIndex(p => p.id === playerIdInput.value);
if (index !== -1) {
// Preserve match stats
playerData.matchesPlayed = players[index].matchesPlayed;
playerData.wins = players[index].wins;
playerData.draws = players[index].draws;
playerData.losses = players[index].losses;
playerData.points = players[index].points;
players[index] = playerData;
showToast('Joueur mis à jour avec succès');
}
} else {
// Add new player
players.push(playerData);
showToast('Joueur ajouté avec succès');
}
// Reset form
playerForm.reset();
playerIdInput.value = '';
// Update UI and save data
renderPlayers();
updateStats();
saveData();
}
// Render players list
function renderPlayers(searchTerm = '') {
// Clear existing players
playersList.innerHTML = '';
// Filter players if search term exists
const filteredPlayers = searchTerm
? players.filter(player =>
player.name.toLowerCase().includes(searchTerm) ||
(player.team && player.team.toLowerCase().includes(searchTerm)))
: players;
if (filteredPlayers.length === 0) {
playersList.innerHTML = `
<tr>
<td colspan="5" class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-user-slash text-4xl mb-2"></i>
<p>Aucun joueur trouvé</p>
</td>
</tr>
`;
return;
}
// Populate players list
filteredPlayers.forEach(player => {
const row = document.createElement('tr');
row.className = 'border-b border-gray-200 dark:border-gray-700 hover:bg-gray-100 dark:hover:bg-gray-700';
row.innerHTML = `
<td class="py-3 px-4">${player.name}</td>
<td class="py-3 px-4">
<div class="flex items-center">
${renderLevelStars(player.level)}
</div>
</td>
<td class="py-3 px-4">${player.team || '-'}</td>
<td class="py-3 px-4">${player.participation.toFixed(2)} €</td>
<td class="py-3 px-4">
<button class="edit-player-btn mr-2 text-blue-500 hover:text-blue-700 dark:hover:text-blue-400" data-id="${player.id}">
<i class="fas fa-edit"></i>
</button>
<button class="delete-player-btn text-red-500 hover:text-red-700 dark:hover:text-red-400" data-id="${player.id}">
<i class="fas fa-trash"></i>
</button>
</td>
`;
playersList.appendChild(row);
});
// Add event listeners to edit and delete buttons
document.querySelectorAll('.edit-player-btn').forEach(button => {
button.addEventListener('click', () => editPlayer(button.getAttribute('data-id')));
});
document.querySelectorAll('.delete-player-btn').forEach(button => {
button.addEventListener('click', () => deletePlayer(button.getAttribute('data-id')));
});
// Update player select dropdowns in match modal
updatePlayerSelects();
}
// Render level stars
function renderLevelStars(level) {
let stars = '';
for (let i = 1; i <= 10; i++) {
stars += i <= level
? '<i class="fas fa-star text-yellow-500"></i>'
: '<i class="far fa-star text-yellow-500"></i>';
}
return stars;
}
// Edit player
function editPlayer(playerId) {
const player = players.find(p => p.id === playerId);
if (player) {
playerIdInput.value = player.id;
playerNameInput.value = player.name;
playerLevelInput.value = player.level;
playerTeamInput.value = player.team || '';
playerParticipationInput.value = player.participation;
// Scroll to form
document.getElementById('playerForm').scrollIntoView({ behavior: 'smooth' });
}
}
// Delete player
function deletePlayer(playerId) {
if (confirm('Êtes-vous sûr de vouloir supprimer ce joueur ?')) {
players = players.filter(p => p.id !== playerId);
// Also remove any matches involving this player
matches = matches.filter(m => m.player1Id !== playerId && m.player2Id !== playerId);
showToast('Joueur supprimé avec succès');
renderPlayers();
renderMatches();
updateStats();
updateNextMatch();
updateRecentResults();
updateRanking();
saveData();
}
}
// Update player select dropdowns
function updatePlayerSelects() {
// Clear existing options
player1Select.innerHTML = '<option value="">Sélectionner un joueur</option>';
player2Select.innerHTML = '<option value="">Sélectionner un joueur</option>';
// Add players
players.forEach(player => {
const option1 = document.createElement('option');
option1.value = player.id;
option1.textContent = player.name;
const option2 = document.createElement('option');
option2.value = player.id;
option2.textContent = player.name;
player1Select.appendChild(option1);
player2Select.appendChild(option2);
});
}
// Open match modal
function openMatchModal(matchId = null) {
// Reset form
matchForm.reset();
matchIdInput.value = '';
scoreFields.classList.add('hidden');
// If editing an existing match
if (matchId) {
const match = matches.find(m => m.id === matchId);
if (match) {
matchIdInput.value = match.id;
player1Select.value = match.player1Id;
player2Select.value = match.player2Id;
matchDateTimeInput.value = match.dateTime;
matchPhaseSelect.value = match.phase || 'group';
if (match.score1 !== undefined && match.score2 !== undefined) {
score1Input.value = match.score1;
score2Input.value = match.score2;
scoreFields.classList.remove('hidden');
toggleScoreFields.innerHTML = '<i class="fas fa-edit mr-2"></i> Modifier score';
}
document.getElementById('matchModalTitle').textContent = 'Modifier Match';
}
} else {
document.getElementById('matchModalTitle').textContent = 'Nouveau Match';
}
// Show modal
matchModal.classList.add('active');
}
// Close match modal
function closeMatchModalFunc() {
matchModal.classList.remove('active');
}
// Toggle score fields
function toggleScoreFieldsFunc() {
scoreFields.classList.toggle('hidden');
if (scoreFields.classList.contains('hidden')) {
toggleScoreFields.innerHTML = '<i class="fas fa-futbol mr-2"></i> Ajouter score';
} else {
toggleScoreFields.innerHTML = '<i class="fas fa-edit mr-2"></i> Modifier score';
}
}
// Handle match form submission
function handleMatchFormSubmit(e) {
e.preventDefault();
// Get selected players
const player1 = players.find(p => p.id === player1Select.value);
const player2 = players.find(p => p.id === player2Select.value);
if (!player1 || !player2) {
showToast('Veuillez sélectionner deux joueurs', 'error');
return;
}
if (player1.id === player2.id) {
showToast('Un joueur ne peut pas jouer contre lui-même', 'error');
return;
}
const matchData = {
id: matchIdInput.value || Date.now().toString(),
player1Id: player1.id,
player1Name: player1.name,
player2Id: player2.id,
player2Name: player2.name,
dateTime: matchDateTimeInput.value,
phase: matchPhaseSelect.value,
completed: scoreFields.classList.contains('hidden') ? false : true,
score1: scoreFields.classList.contains('hidden') ? undefined : parseInt(score1Input.value),
score2: scoreFields.classList.contains('hidden') ? undefined : parseInt(score2Input.value)
};
if (matchIdInput.value) {
// Update existing match
const index = matches.findIndex(m => m.id === matchIdInput.value);
if (index !== -1) {
matches[index] = matchData;
showToast('Match mis à jour avec succès');
}
} else {
// Add new match
matches.push(matchData);
showToast('Match ajouté avec succès');
}
// Close modal and update UI
closeMatchModalFunc();
renderMatches();
updateStats();
updateNextMatch();
updateRecentResults();
updateRanking();
saveData();
}
// Render matches list
function renderMatches() {
// Clear existing matches
matchesList.innerHTML = '';
// Filter matches
let filteredMatches = [...matches];
// Filter by date if selected
if (dateFilter.value) {
const selectedDate = new Date(dateFilter.value).toDateString();
filteredMatches = filteredMatches.filter(match => {
const matchDate = new Date(match.dateTime).toDateString();
return matchDate === selectedDate;
});
}
// Filter by status if selected
if (statusFilter.value !== 'all') {
filteredMatches = filteredMatches.filter(match => {
if (statusFilter.value === 'upcoming') return !match.completed;
if (statusFilter.value === 'completed') return match.completed;
});
}
// Sort matches by date (upcoming first)
filteredMatches.sort((a, b) => new Date(a.dateTime) - new Date(b.dateTime));
if (filteredMatches.length === 0) {
matchesList.innerHTML = `
<div class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-calendar-plus text-4xl mb-2"></i>
<p>Aucun match trouvé</p>
</div>
`;
return;
}
// Group matches by phase if tournament type is knockout
if (tournamentSettings.type === 'knockout' || tournamentSettings.type === 'groups') {
const phases = {
'group': 'Phase de groupes',
'round16': '8ème de finale',
'quarter': 'Quart de finale',
'semi': 'Demi-finale',
'final': 'Finale'
};
const groupedMatches = {};
filteredMatches.forEach(match => {
const phase = match.phase || 'group';
if (!groupedMatches[phase]) {
groupedMatches[phase] = [];
}
groupedMatches[phase].push(match);
});
// Render matches by phase
Object.keys(groupedMatches).forEach(phase => {
const phaseMatches = groupedMatches[phase];
const phaseHeader = document.createElement('div');
phaseHeader.className = 'mb-4';
phaseHeader.innerHTML = `
<h3 class="text-lg font-bold mb-2 ${phase !== 'group' ? 'text-yellow-600 dark:text-yellow-400' : ''}">
${phases[phase]}
</h3>
`;
matchesList.appendChild(phaseHeader);
phaseMatches.forEach(match => {
matchesList.appendChild(createMatchCard(match));
});
});
} else {
// Render all matches in a single list
filteredMatches.forEach(match => {
matchesList.appendChild(createMatchCard(match));
});
}
}
// Create match card element
function createMatchCard(match) {
const matchDate = new Date(match.dateTime);
const now = new Date();
const isPast = matchDate < now;
const card = document.createElement('div');
card.className = `bg-gray-100 dark:bg-gray-700 p-4 rounded-lg match-card ${match.phase && match.phase !== 'group' ? 'phase-finale' : ''}`;
// Header with date and actions
const header = document.createElement('div');
header.className = 'flex justify-between items-center mb-2';
header.innerHTML = `
<div class="text-sm font-medium ${isPast ? 'text-gray-500 dark:text-gray-400' : 'text-blue-600 dark:text-blue-400'}">
${matchDate.toLocaleString('fr-FR', {
weekday: 'short',
day: 'numeric',
month: 'short',
hour: '2-digit',
minute: '2-digit'
})}
</div>
<div>
<button class="edit-match-btn mr-2 text-blue-500 hover:text-blue-700 dark:hover:text-blue-400" data-id="${match.id}">
<i class="fas fa-edit"></i>
</button>
<button class="delete-match-btn text-red-500 hover:text-red-700 dark:hover:text-red-400" data-id="${match.id}">
<i class="fas fa-trash"></i>
</button>
</div>
`;
// Players and score
const content = document.createElement('div');
content.className = 'flex justify-between items-center';
if (match.completed) {
// Completed match
const player1 = players.find(p => p.id === match.player1Id);
const player2 = players.find(p => p.id === match.player2Id);
const player1Level = player1 ? player1.level : 5;
const player2Level = player2 ? player2.level : 5;
content.innerHTML = `
<div class="flex-1 text-right pr-4">
<div class="font-bold">${match.player1Name}</div>
<div class="text-sm">${renderLevelStars(player1Level)}</div>
</div>
<div class="text-center px-4">
<div class="text-2xl font-bold">
${match.score1} - ${match.score2}
</div>
<div class="text-xs ${match.score1 === match.score2 ? 'text-gray-500' : match.score1 > match.score2 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}">
${match.score1 === match.score2 ? 'Match nul' : match.score1 > match.score2 ? 'Victoire' : 'Défaite'}
</div>
</div>
<div class="flex-1 text-left pl-4">
<div class="font-bold">${match.player2Name}</div>
<div class="text-sm">${renderLevelStars(player2Level)}</div>
</div>
`;
} else {
// Upcoming match
content.innerHTML = `
<div class="flex-1 text-right pr-4">
<div class="font-bold">${match.player1Name}</div>
</div>
<div class="text-center px-4">
<div class="text-xl">VS</div>
</div>
<div class="flex-1 text-left pl-4">
<div class="font-bold">${match.player2Name}</div>
</div>
`;
}
card.appendChild(header);
card.appendChild(content);
// Add event listeners to edit and delete buttons
card.querySelector('.edit-match-btn').addEventListener('click', () => {
openMatchModal(card.querySelector('.edit-match-btn').getAttribute('data-id'));
});
card.querySelector('.delete-match-btn').addEventListener('click', () => {
deleteMatch(card.querySelector('.delete-match-btn').getAttribute('data-id'));
});
return card;
}
// Delete match
function deleteMatch(matchId) {
if (confirm('Êtes-vous sûr de vouloir supprimer ce match ?')) {
matches = matches.filter(m => m.id !== matchId);
showToast('Match supprimé avec succès');
renderMatches();
updateStats();
updateNextMatch();
updateRecentResults();
updateRanking();
saveData();
}
}
// Update stats
function updateStats() {
playerCountElement.textContent = players.length;
matchCountElement.textContent = matches.length;
const completedMatches = matches.filter(m => m.completed).length;
const upcomingMatches = matches.filter(m => !m.completed).length;
completedCountElement.textContent = completedMatches;
upcomingCountElement.textContent = upcomingMatches;
}
// Update next match
function updateNextMatch() {
const now = new Date();
const upcomingMatches = matches
.filter(m => !m.completed && new Date(m.dateTime) > now)
.sort((a, b) => new Date(a.dateTime) - new Date(b.dateTime));
if (upcomingMatches.length > 0) {
const nextMatch = upcomingMatches[0];
const matchDate = new Date(nextMatch.dateTime);
nextMatchCard.innerHTML = `
<div class="flex justify-between items-center mb-2">
<div class="text-sm font-medium text-blue-600 dark:text-blue-400">
${matchDate.toLocaleString('fr-FR', {
weekday: 'long',
day: 'numeric',
month: 'long',
hour: '2-digit',
minute: '2-digit'
})}
</div>
<div class="text-xs bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 px-2 py-1 rounded">
${nextMatch.phase === 'group' ? 'Groupe' :
nextMatch.phase === 'round16' ? '8ème de finale' :
nextMatch.phase === 'quarter' ? 'Quart de finale' :
nextMatch.phase === 'semi' ? 'Demi-finale' : 'Finale'}
</div>
</div>
<div class="flex justify-between items-center">
<div class="text-center flex-1">
<div class="font-bold">${nextMatch.player1Name}</div>
<div class="text-sm">VS</div>
<div class="font-bold">${nextMatch.player2Name}</div>
</div>
</div>
`;
} else {
nextMatchCard.innerHTML = `
<div class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-calendar-plus text-4xl mb-2"></i>
<p>Aucun match programmé</p>
</div>
`;
}
}
// Update recent results
function updateRecentResults() {
const now = new Date();
const completedMatches = matches
.filter(m => m.completed)
.sort((a, b) => new Date(b.dateTime) - new Date(a.dateTime))
.slice(0, 5);
recentResults.innerHTML = '';
if (completedMatches.length === 0) {
recentResults.innerHTML = `
<div class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-info-circle text-4xl mb-2"></i>
<p>Aucun résultat récent</p>
</div>
`;
return;
}
completedMatches.forEach(match => {
const matchDate = new Date(match.dateTime);
const player1 = players.find(p => p.id === match.player1Id);
const player2 = players.find(p => p.id === match.player2Id);
const player1Level = player1 ? player1.level : 5;
const player2Level = player2 ? player2.level : 5;
const resultItem = document.createElement('div');
resultItem.className = 'bg-gray-100 dark:bg-gray-700 p-3 rounded-lg';
resultItem.innerHTML = `
<div class="flex justify-between items-center mb-1">
<div class="text-sm text-gray-500 dark:text-gray-400">
${matchDate.toLocaleString('fr-FR', {
weekday: 'short',
day: 'numeric',
month: 'short',
hour: '2-digit',
minute: '2-digit'
})}
</div>
<div class="text-xs bg-gray-200 dark:bg-gray-600 px-2 py-1 rounded">
${match.phase === 'group' ? 'Groupe' :
match.phase === 'round16' ? '8ème de finale' :
match.phase === 'quarter' ? 'Quart de finale' :
match.phase === 'semi' ? 'Demi-finale' : 'Finale'}
</div>
</div>
<div class="flex justify-between items-center">
<div class="flex-1 text-right pr-4">
<div>${match.player1Name}</div>
<div class="text-xs">${renderLevelStars(player1Level)}</div>
</div>
<div class="text-center px-4">
<div class="text-xl font-bold ${match.score1 === match.score2 ? 'text-gray-500' : match.score1 > match.score2 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}">
${match.score1} - ${match.score2}
</div>
</div>
<div class="flex-1 text-left pl-4">
<div>${match.player2Name}</div>
<div class="text-xs">${renderLevelStars(player2Level)}</div>
</div>
</div>
`;
recentResults.appendChild(resultItem);
});
}
// Update ranking
function updateRanking() {
// Reset player stats
players.forEach(player => {
player.matchesPlayed = 0;
player.wins = 0;
player.draws = 0;
player.losses = 0;
player.points = 0;
});
// Calculate stats from completed matches
matches.filter(m => m.completed).forEach(match => {
const player1 = players.find(p => p.id === match.player1Id);
const player2 = players.find(p => p.id === match.player2Id);
if (player1 && player2) {
player1.matchesPlayed++;
player2.matchesPlayed++;
if (match.score1 > match.score2) {
player1.wins++;
player2.losses++;
player1.points += tournamentSettings.winPoints;
player2.points += tournamentSettings.lossPoints;
} else if (match.score1 < match.score2) {
player1.losses++;
player2.wins++;
player1.points += tournamentSettings.lossPoints;
player2.points += tournamentSettings.winPoints;
} else {
player1.draws++;
player2.draws++;
player1.points += tournamentSettings.drawPoints;
player2.points += tournamentSettings.drawPoints;
}
}
});
// Sort players by points (descending)
const sortedPlayers = [...players].sort((a, b) => b.points - a.points);
// Update ranking list
rankingList.innerHTML = '';
if (sortedPlayers.length === 0) {
rankingList.innerHTML = `
<tr>
<td colspan="7" class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-info-circle text-4xl mb-2"></i>
<p>Aucun résultat disponible</p>
</td>
</tr>
`;
return;
}
sortedPlayers.forEach((player, index) => {
const row = document.createElement('tr');
row.className = 'border-b border-gray-200 dark:border-gray-700 hover:bg-gray-100 dark:hover:bg-gray-700';
row.innerHTML = `
<td class="py-3 px-4">${index + 1}</td>
<td class="py-3 px-4 font-bold">${player.name}</td>
<td class="py-3 px-4">${player.matchesPlayed}</td>
<td class="py-3 px-4 text-green-600 dark:text-green-400">${player.wins}</td>
<td class="py-3 px-4 text-yellow-600 dark:text-yellow-400">${player.draws}</td>
<td class="py-3 px-4 text-red-600 dark:text-red-400">${player.losses}</td>
<td class="py-3 px-4 font-bold">${player.points}</td>
`;
rankingList.appendChild(row);
});
// Update winner card if there are completed matches
const hasCompletedMatches = matches.some(m => m.completed);
if (hasCompletedMatches && sortedPlayers.length > 0) {
const winner = sortedPlayers[0];
winnerCard.innerHTML = `
<div class="flex flex-col items-center">
<div class="w-16 h-16 bg-yellow-500 rounded-full flex items-center justify-center text-white mb-2">
<i class="fas fa-trophy text-2xl"></i>
</div>
<h3 class="text-lg font-bold">${winner.name}</h3>
<div class="text-sm">${winner.points} points</div>
<div class="text-xs mt-2">${winner.wins}V ${winner.draws}N ${winner.losses}D</div>
</div>
`;
winnerCard.classList.add('winner-card');
} else {
winnerCard.innerHTML = `
<div class="py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-trophy text-4xl mb-2"></i>
<p>Aucun vainqueur encore</p>
</div>
`;
winnerCard.classList.remove('winner-card');
}
}
// Handle settings form submission
function handleSettingsFormSubmit(e) {
e.preventDefault();
tournamentSettings = {
name: tournamentNameInput.value,
type: tournamentTypeSelect.value,
winPoints: parseInt(winPointsInput.value),
drawPoints: parseInt(drawPointsInput.value),
lossPoints: parseInt(lossPointsInput.value)
};
// Update tournament title
tournamentTitle.textContent = tournamentSettings.name;
showToast('Paramètres enregistrés avec succès');
saveData();
updateRanking();
}
// Update tournament settings UI
function updateTournamentSettingsUI() {
tournamentNameInput.value = tournamentSettings.name;
tournamentTypeSelect.value = tournamentSettings.type;
winPointsInput.value = tournamentSettings.winPoints;
drawPointsInput.value = tournamentSettings.drawPoints;
lossPointsInput.value = tournamentSettings.lossPoints;
}
// Generate random tournament
function generateRandomTournament() {
if (players.length < 4) {
showToast('Vous avez besoin d\'au moins 4 joueurs pour générer un tournoi', 'error');
return;
}
if (confirm('Générer un tournoi aléatoire ? Cela effacera tous les matchs existants.')) {
// Clear existing matches
matches = [];
// Create group stage matches if tournament type is groups
if (tournamentSettings.type === 'groups') {
// Split players into 2 groups
const shuffledPlayers = [...players].sort(() => Math.random() - 0.5);
const groupA = shuffledPlayers.slice(0, Math.ceil(players.length / 2));
const groupB = shuffledPlayers.slice(Math.ceil(players.length / 2));
// Create matches within each group
createRoundRobinMatches(groupA, 'group');
createRoundRobinMatches(groupB, 'group');
// Create knockout matches
const knockoutPhases = ['round16', 'quarter', 'semi', 'final'];
let nextPhaseMatches = [];
knockoutPhases.forEach(phase => {
if (nextPhaseMatches.length === 0) {
// First knockout phase (top 2 from each group)
const groupAWinners = [...groupA].sort((a, b) => b.level - a.level).slice(0, 2);
const groupBWinners = [...groupB].sort((a, b) => b.level - a.level).slice(0, 2);
const allWinners = [...groupAWinners, ...groupBWinners].sort(() => Math.random() - 0.5);
for (let i = 0; i < allWinners.length; i += 2) {
if (i + 1 < allWinners.length) {
nextPhaseMatches.push({
player1: allWinners[i],
player2: allWinners[i + 1]
});
}
}
} else {
// Subsequent knockout phases
const newMatches = [];
for (let i = 0; i < nextPhaseMatches.length; i += 2) {
if (i + 1 < nextPhaseMatches.length) {
newMatches.push({
player1: nextPhaseMatches[i].player1, // Simulate winner
player2: nextPhaseMatches[i + 1].player1 // Simulate winner
});
}
}
nextPhaseMatches = newMatches;
}
// Add matches for this phase
nextPhaseMatches.forEach((match, index) => {
const matchDate = new Date();
matchDate.setDate(matchDate.getDate() + 7 * (knockoutPhases.indexOf(phase) + 1));
matches.push({
id: Date.now().toString() + index,
player1Id: match.player1.id,
player1Name: match.player1.name,
player2Id: match.player2.id,
player2Name: match.player2.name,
dateTime: matchDate.toISOString(),
phase: phase,
completed: false
});
});
});
} else if (tournamentSettings.type === 'knockout') {
// Create knockout tournament
const shuffledPlayers = [...players].sort(() => Math.random() - 0.5);
let currentRound = [...shuffledPlayers];
let phase = 'round16';
// Determine appropriate phase based on player count
if (players.length <= 2) {
phase = 'final';
} else if (players.length <= 4) {
phase = 'semi';
} else if (players.length <= 8) {
phase = 'quarter';
}
while (currentRound.length > 1) {
const nextRound = [];
const matchesThisRound = [];
for (let i = 0; i < currentRound.length; i += 2) {
if (i + 1 < currentRound.length) {
const player1 = currentRound[i];
const player2 = currentRound[i + 1];
const matchDate = new Date();
matchDate.setDate(matchDate.getDate() + 7 * matchesThisRound.length);
matches.push({
id: Date.now().toString() + i,
player1Id: player1.id,
player1Name: player1.name,
player2Id: player2.id,
player2Name: player2.name,
dateTime: matchDate.toISOString(),
phase: phase,
completed: false
});
matchesThisRound.push({
player1: player1,
player2: player2
});
// Simulate winner for next round (higher level player)
nextRound.push(player1.level >= player2.level ? player1 : player2);
} else {
// Odd number of players - bye to next round
nextRound.push(currentRound[i]);
}
}
currentRound = nextRound;
// Update phase for next round
if (phase === 'round16') phase = 'quarter';
else if (phase === 'quarter') phase = 'semi';
else if (phase === 'semi') phase = 'final';
}
} else {
// Create league tournament (round robin)
createRoundRobinMatches(players, 'group');
}
showToast('Tournoi généré avec succès');
renderMatches();
updateStats();
updateNextMatch();
saveData();
}
}
// Create round robin matches for a group of players
function createRoundRobinMatches(groupPlayers, phase) {
// Create all possible pairings
for (let i = 0; i < groupPlayers.length; i++) {
for (let j = i + 1; j < groupPlayers.length; j++) {
const player1 = groupPlayers[i];
const player2 = groupPlayers[j];
const matchDate = new Date();
matchDate.setDate(matchDate.getDate() + i + j);
matches.push({
id: Date.now().toString() + i + j,
player1Id: player1.id,
player1Name: player1.name,
player2Id: player2.id,
player2Name: player2.name,
dateTime: matchDate.toISOString(),
phase: phase,
completed: false
});
}
}
}
// Show toast notification
function showToast(message, type = 'success') {
toastMessage.textContent = message;
// Set color based on type
if (type === 'success') {
toast.className = 'toast bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg';
} else if (type === 'error') {
toast.className = 'toast bg-red-500 text-white px-6 py-3 rounded-lg shadow-lg';
} else {
toast.className = 'toast bg-blue-500 text-white px-6 py-3 rounded-lg shadow-lg';
}
// Show toast
toast.classList.add('show');
// Hide after 3 seconds
setTimeout(() => {
toast.classList.remove('show');
</html>