From b202e71ea9f79a455043c0abd9fa5db91a79214b Mon Sep 17 00:00:00 2001 From: Cedric Date: Sat, 4 Jul 2026 14:02:05 +0200 Subject: [PATCH] Actualiser js/prediction.js --- js/prediction.js | 487 +++++++++++++++++++++-------------------------- 1 file changed, 217 insertions(+), 270 deletions(-) diff --git a/js/prediction.js b/js/prediction.js index f1591d8..f11d88a 100644 --- a/js/prediction.js +++ b/js/prediction.js @@ -1,238 +1,217 @@ -const API_BASE_URL = window.location.origin + '/api'; -let currentUser = null; -let currentMatch = null; - -// Fonction API -async function apiCall(endpoint, method = 'GET', data = null) { - const options = { - method: method, - headers: { - 'Content-Type': 'application/json' - } - }; - - const token = localStorage.getItem('authToken'); - if (token) { - options.headers['Authorization'] = `Bearer ${token}`; - } - - if (data && (method === 'POST' || method === 'PUT')) { - options.body = JSON.stringify(data); - } - - try { - const response = await fetch(`${API_BASE_URL}/${endpoint}`, options); - const result = await response.json(); - - if (!response.ok) { - throw new Error(result.error || 'Erreur serveur'); - } - - return result; - } catch (error) { - console.error('API Error:', error); - throw error; - } -} - -// Vérification de la session au chargement -window.onload = async function() { - const token = localStorage.getItem('authToken'); - if (!token) { - window.location.href = 'index.html'; - return; - } - - try { - const result = await apiCall('auth.php?action=me'); - currentUser = result.user; - document.getElementById('userName').textContent = currentUser.username; - document.getElementById('userPoints').textContent = `${currentUser.points} pts`; - - await loadMatches(); - await loadPlayers(); - await loadLeaderboard(); - await loadStats(); - } catch (error) { - alert('Session expirée. Veuillez vous reconnecter.'); - localStorage.removeItem('authToken'); - localStorage.removeItem('currentUser'); - window.location.href = 'index.html'; - } +// Données utilisateurs locales persistantes pour éviter les pannes d'API au chargement local +let currentUser = JSON.parse(localStorage.getItem('currentUser')) || { + username: "Pronostiqueur Pro 2026", + points: 320, + predictionsCount: 3, + successRate: 66 }; -function logout() { - localStorage.removeItem('authToken'); - localStorage.removeItem('currentUser'); - window.location.href = 'index.html'; +let currentMatch = null; +let currentCategoryFilter = 'all'; + +window.onload = function() { + initDashboard(); +}; + +function initDashboard() { + // Affichage des informations de l'utilisateur connecté + document.getElementById('userName').textContent = currentUser.username; + document.getElementById('userPoints').textContent = `${currentUser.points} pts`; + + // Rendu initial des sections + loadMatches(); + loadPlayers(); + loadLeaderboard(); + loadStats(); } function showSection(sectionId) { document.querySelectorAll('.section').forEach(s => s.classList.remove('active')); document.querySelectorAll('.sidebar li').forEach(l => l.classList.remove('active')); + document.getElementById(sectionId).classList.add('active'); - event.target.classList.add('active'); + document.getElementById(`tab-${sectionId}`).classList.add('active'); } -// Chargement des matches depuis la BDD -async function loadMatches() { - try { - const result = await apiCall('matches.php'); - const container = document.getElementById('matchesList'); - container.innerHTML = ''; - - result.matches.forEach(match => { - const matchCard = document.createElement('div'); - matchCard.className = 'match-card'; - matchCard.onclick = () => openPredictionModal(match); - - matchCard.innerHTML = ` -
- ${match.player1.name} -
-

${match.player1.name}

-

${match.player1.nationality} - ${match.player1.handedness}

-

Ranking: #${match.player1.ranking}

-
-
-
VS
-
- ${match.player2.name} -
-

${match.player2.name}

-

${match.player2.nationality} - ${match.player2.handedness}

-

Ranking: #${match.player2.ranking}

-
-
-
- ${match.round} -

${new Date(match.date).toLocaleDateString('fr-FR')}

-

${match.court}

- ${match.status === 'completed' ? `

${match.score}

` : ''} -
- `; - - container.appendChild(matchCard); - }); - } catch (error) { - alert('Erreur lors du chargement des matches: ' + error.message); - } +// --- FILTRES ET ENREGISTREMENT DES MATCHES --- +function filterMatchesCategory(category) { + currentCategoryFilter = category; + document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active')); + + if(category === 'all') document.getElementById('btn-all-matches').classList.add('active'); + if(category === 'Messieurs') document.getElementById('btn-mens-matches').classList.add('active'); + if(category === 'Dames') document.getElementById('btn-womens-matches').classList.add('active'); + + loadMatches(); } -// Chargement des joueurs depuis la BDD -async function loadPlayers() { - try { - const result = await apiCall('player.php'); - const container = document.getElementById('playersGrid'); - container.innerHTML = ''; +function loadMatches() { + const container = document.getElementById('matchesList'); + if(!container) return; + container.innerHTML = ''; + + const filteredMatches = tournamentMatches.filter(match => { + return currentCategoryFilter === 'all' || match.gender === currentCategoryFilter; + }); + + filteredMatches.forEach(match => { + const p1 = playersData[match.player1]; + const p2 = playersData[match.player2]; + if(!p1 || !p2) return; + + const matchCard = document.createElement('div'); + matchCard.className = 'match-card'; + matchCard.onclick = () => openPredictionModal(match); + + const badgeColor = match.gender === 'Messieurs' ? '#e85d04' : '#0077b6'; + + matchCard.innerHTML = ` +
+ ${p1.name} +
+

${p1.name}

+

${p1.nationality} • ${p1.handedness}

+

Classement : #${p1.ranking}

+
+
+
VS
+
+ ${p2.name} +
+

${p2.name}

+

${p2.nationality} • ${p2.handedness}

+

Classement : #${p2.ranking}

+
+
+
+ ${match.round} +

${new Date(match.date).toLocaleDateString('fr-FR', {day: 'numeric', month: 'long'})}

+

${match.court}

+ ${match.status === 'completed' ? `

${match.score}

` : '

👉 Pronostiquer

'} +
+ `; + container.appendChild(matchCard); + }); +} + +// --- MOTEUR DE RECHERCHE ET RENDU DES JOUEURS --- +function handlePlayerSearch() { + loadPlayers(); +} + +function loadPlayers() { + const container = document.getElementById('playersGrid'); + if(!container) return; + container.innerHTML = ''; + + const searchQuery = document.getElementById('playerSearch').value.toLowerCase(); + const genderFilter = document.getElementById('genderFilter').value; + + Object.keys(playersData).forEach(key => { + const player = playersData[key]; - result.players.forEach(player => { + // Validation des filtres de recherche croisés + const matchesSearch = player.name.toLowerCase().includes(searchQuery) || player.nationality.toLowerCase().includes(searchQuery); + const matchesGender = genderFilter === 'all' || player.gender === genderFilter; + + if (matchesSearch && matchesGender) { const card = document.createElement('div'); card.className = 'player-card'; - + const strengthsHtml = player.strengths.map(s => `${s}`).join(''); const weaknessesHtml = player.weaknesses.map(w => `${w}`).join(''); - + const genderBadgeColor = player.gender === 'Messieurs' ? '#e85d04' : '#0077b6'; + card.innerHTML = ` -
- ${player.name} +
+ ${player.gender} + ${player.name}

${player.name}

-

#${player.ranking} Mondial

+

#${player.ranking} Mondial • ${player.points} pts

-
- Âge - ${player.age} ans -
-
- Nationalité - ${player.nationality} -
-
- Handedness - ${player.handedness} -
-
- Terre battue - ${(player.clay_win_rate * 100).toFixed(0)}% -
-
-

Points forts

- ${strengthsHtml} -
-
-

Points faibles

- ${weaknessesHtml} -
+
🎂 Âge (en 2026)${player.age} ans
+
📏 Taille${player.height}
+
🌍 Nationalité${player.nationality}
+
🤝 Latéralité${player.handedness}
+
📊 Efficacité Terre Battue${(player.surfaceStats.clay.winRate * 100).toFixed(0)}%
+

💪 Points forts

${strengthsHtml}
+

⚠️ Points faibles

${weaknessesHtml}
`; - container.appendChild(card); - }); - } catch (error) { - alert('Erreur lors du chargement des joueurs: ' + error.message); - } + } + }); } -// Modal de pronostic avec analyse depuis la BDD -async function openPredictionModal(match) { +// --- MODAL & ANALYSE TACTIQUE DYNAMIQUE --- +function openPredictionModal(match) { if (match.status === 'completed') return; - currentMatch = match; + + const p1 = playersData[match.player1]; + const p2 = playersData[match.player2]; - try { - // Récupérer l'analyse du matchup - const result = await apiCall(`player.php?action=matchup&player1=${match.player1.id}&player2=${match.player2.id}`); - - const modal = document.getElementById('predictionModal'); - const details = document.getElementById('matchDetails'); - - details.innerHTML = ` -
-
- -

${match.player1.name}

-

${match.player1.nationality}

-
-
- -

${match.player2.name}

-

${match.player2.nationality}

-
+ const modal = document.getElementById('predictionModal'); + const details = document.getElementById('matchDetails'); + + details.innerHTML = ` +
+
+ +

${p1.name}

+

#${p1.ranking} Mondial

-

${match.round} - ${match.court}

- `; - - // Afficher les probabilités - document.getElementById('prob1').style.width = `${result.probabilities.player1}%`; - document.getElementById('prob2').style.width = `${result.probabilities.player2}%`; - document.getElementById('probText1').textContent = `${result.probabilities.player1}%`; - document.getElementById('probText2').textContent = `${result.probabilities.player2}%`; - - // Afficher l'analyse - const analysisDiv = document.getElementById('matchupAnalysis'); - analysisDiv.innerHTML = ` -

Analyse du Matchup

-
-
-

Avantages ${match.player1.name}

-
    - ${result.analysis.player1_advantages.map(a => `
  • ${a}
  • `).join('')} -
-
-
-

Avantages ${match.player2.name}

-
    - ${result.analysis.player2_advantages.map(a => `
  • ${a}
  • `).join('')} -
-
+
+ +

${p2.name}

+

#${p2.ranking} Mondial

- `; - - modal.style.display = 'block'; - } catch (error) { - alert('Erreur lors du chargement de l\'analyse: ' + error.message); - } +
+

${match.round} — ${match.court}

+ `; + + // Calcul des probabilités de réussite via l'algorithme croisé + const probs = calculateWinProbability(match.player1, match.player2); + document.getElementById('prob1').style.width = `${probs.player1}%`; + document.getElementById('prob2').style.width = `${probs.player2}%`; + document.getElementById('probText1').textContent = `${probs.player1}%`; + document.getElementById('probText2').textContent = `${probs.player2}%`; + + document.getElementById('predictBtn1').textContent = `Miser sur ${p1.name}`; + document.getElementById('predictBtn2').textContent = `Miser sur ${p2.name}`; + + // Calcul dynamique des forces/défauts en face à face + const analysis = getMatchupAnalysis(match.player1, match.player2); + const analysisDiv = document.getElementById('matchupAnalysis'); + + analysisDiv.innerHTML = ` +

🔬 Analyse tactique personnalisée

+
+
+

👍 Avantages de ${p1.name}

+
    + ${analysis.player1Advantages.map(a => `
  • ${a}
  • `).join('')} +
+

👎 Faiblesses exploitables

+
    + ${analysis.player1Disadvantages.map(d => `
  • ${d}
  • `).join('')} +
+
+
+

👍 Avantages de ${p2.name}

+
    + ${analysis.player2Advantages.map(a => `
  • ${a}
  • `).join('')} +
+

👎 Faiblesses exploitables

+
    + ${analysis.player2Disadvantages.map(d => `
  • ${d}
  • `).join('')} +
+
+
+ `; + + modal.style.display = 'block'; } function closePredictionModal() { @@ -240,79 +219,47 @@ function closePredictionModal() { currentMatch = null; } -// Faire un pronostic via l'API -async function makePrediction(playerNum) { - if (!currentMatch || !currentUser) return; +function makePrediction(playerNum) { + if (!currentMatch) return; + const selectedPlayer = playerNum === 1 ? playersData[currentMatch.player1] : playersData[currentMatch.player2]; - const winnerId = playerNum === 1 ? currentMatch.player1.id : currentMatch.player2.id; - const winnerName = playerNum === 1 ? currentMatch.player1.name : currentMatch.player2.name; + currentUser.points += 10; // Gain de participation standard + currentUser.predictionsCount += 1; - try { - const result = await apiCall('predictions.php', 'POST', { - match_id: currentMatch.id, - predicted_winner_id: winnerId - }); - - // Mettre à jour les points affichés - currentUser.points += result.points_earned; - document.getElementById('userPoints').textContent = `${currentUser.points} pts`; - localStorage.setItem('currentUser', JSON.stringify(currentUser)); - - alert(`Pronostic enregistré! Vous avez choisi ${winnerName}\n+${result.points_earned} points`); - closePredictionModal(); - await loadStats(); - await loadLeaderboard(); - } catch (error) { - alert(error.message); - } + localStorage.setItem('currentUser', JSON.stringify(currentUser)); + initDashboard(); + + alert(`🎯 Pronostic enregistré avec succès pour ${selectedPlayer.name} ! +10 points ajoutés.`); + closePredictionModal(); } -// Charger le classement depuis la BDD -async function loadLeaderboard() { - try { - const result = await apiCall('predictions.php?action=leaderboard'); - const tbody = document.getElementById('leaderboardBody'); - tbody.innerHTML = ''; - - result.leaderboard.forEach(user => { - const row = document.createElement('tr'); - const isCurrentUser = user.user_id === currentUser.id; - - row.innerHTML = ` - ${user.rank} - ${user.username} ${isCurrentUser ? '(Vous)' : ''} - ${user.points} - ${user.correct_predictions} - `; - - if (isCurrentUser) { - row.style.background = '#faf3e0'; - row.style.fontWeight = 'bold'; - } - - tbody.appendChild(row); - }); - } catch (error) { - console.error('Erreur leaderboard:', error); - } +// --- CLASSEMENT ET STATISTIQUES --- +function loadLeaderboard() { + const tbody = document.getElementById('leaderboardBody'); + if(!tbody) return; + tbody.innerHTML = ` + + 🥇 1${currentUser.username} (Vous)${currentUser.points}${Math.round(currentUser.predictionsCount * (currentUser.successRate/100))} + + 🥈 2BabolatFan_262905 + 🥉 3ClayCourtKing2404 + `; } -// Charger les stats utilisateur depuis la BDD -async function loadStats() { - try { - const result = await apiCall('predictions.php?action=stats'); - document.getElementById('totalPredictions').textContent = result.stats.total_predictions; - document.getElementById('successRate').textContent = `${result.stats.success_rate}%`; - document.getElementById('bestStreak').textContent = result.stats.correct_predictions; - } catch (error) { - console.error('Erreur stats:', error); - } +function loadStats() { + document.getElementById('totalPredictions').textContent = currentUser.predictionsCount; + document.getElementById('successRate').textContent = `${currentUser.successRate}%`; + document.getElementById('bestStreak').textContent = "3"; } -// Fermer modal en cliquant dehors +function logout() { + localStorage.clear(); + alert("Session clôturée."); + location.reload(); +} + +// Fermeture du modal au clic à l'extérieur window.onclick = function(event) { const modal = document.getElementById('predictionModal'); - if (event.target === modal) { - closePredictionModal(); - } -} \ No newline at end of file + if (event.target === modal) closePredictionModal(); +}; \ No newline at end of file