Actualiser js/prediction.js
This commit is contained in:
+15
-53
@@ -1,11 +1,9 @@
|
|||||||
// Données utilisateurs locales persistantes pour éviter les pannes d'API au chargement local
|
|
||||||
let currentUser = JSON.parse(localStorage.getItem('currentUser')) || {
|
let currentUser = JSON.parse(localStorage.getItem('currentUser')) || {
|
||||||
username: "Pronostiqueur Pro 2026",
|
username: "Pronostiqueur Pro 2026",
|
||||||
points: 320,
|
points: 320,
|
||||||
predictionsCount: 3,
|
predictionsCount: 3,
|
||||||
successRate: 66
|
successRate: 66
|
||||||
};
|
};
|
||||||
|
|
||||||
let currentMatch = null;
|
let currentMatch = null;
|
||||||
let currentCategoryFilter = 'all';
|
let currentCategoryFilter = 'all';
|
||||||
|
|
||||||
@@ -14,11 +12,8 @@ window.onload = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function initDashboard() {
|
function initDashboard() {
|
||||||
// Affichage des informations de l'utilisateur connecté
|
|
||||||
document.getElementById('userName').textContent = currentUser.username;
|
document.getElementById('userName').textContent = currentUser.username;
|
||||||
document.getElementById('userPoints').textContent = `${currentUser.points} pts`;
|
document.getElementById('userPoints').textContent = `${currentUser.points} pts`;
|
||||||
|
|
||||||
// Rendu initial des sections
|
|
||||||
loadMatches();
|
loadMatches();
|
||||||
loadPlayers();
|
loadPlayers();
|
||||||
loadLeaderboard();
|
loadLeaderboard();
|
||||||
@@ -28,20 +23,16 @@ function initDashboard() {
|
|||||||
function showSection(sectionId) {
|
function showSection(sectionId) {
|
||||||
document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
|
document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
|
||||||
document.querySelectorAll('.sidebar li').forEach(l => l.classList.remove('active'));
|
document.querySelectorAll('.sidebar li').forEach(l => l.classList.remove('active'));
|
||||||
|
|
||||||
document.getElementById(sectionId).classList.add('active');
|
document.getElementById(sectionId).classList.add('active');
|
||||||
document.getElementById(`tab-${sectionId}`).classList.add('active');
|
document.getElementById(`tab-${sectionId}`).classList.add('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- FILTRES ET ENREGISTREMENT DES MATCHES ---
|
|
||||||
function filterMatchesCategory(category) {
|
function filterMatchesCategory(category) {
|
||||||
currentCategoryFilter = category;
|
currentCategoryFilter = category;
|
||||||
document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
|
document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
|
||||||
|
|
||||||
if (category === 'all') document.getElementById('btn-all-matches').classList.add('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 === 'Messieurs') document.getElementById('btn-mens-matches').classList.add('active');
|
||||||
if (category === 'Dames') document.getElementById('btn-womens-matches').classList.add('active');
|
if (category === 'Dames') document.getElementById('btn-womens-matches').classList.add('active');
|
||||||
|
|
||||||
loadMatches();
|
loadMatches();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,28 +40,23 @@ function loadMatches() {
|
|||||||
const container = document.getElementById('matchesList');
|
const container = document.getElementById('matchesList');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
|
|
||||||
const filteredMatches = tournamentMatches.filter(match => {
|
const filteredMatches = tournamentMatches.filter(match => {
|
||||||
return currentCategoryFilter === 'all' || match.gender === currentCategoryFilter;
|
return currentCategoryFilter === 'all' || match.gender === currentCategoryFilter;
|
||||||
});
|
});
|
||||||
|
|
||||||
filteredMatches.forEach(match => {
|
filteredMatches.forEach(match => {
|
||||||
const p1 = playersData[match.player1];
|
const p1 = playersData[match.player1];
|
||||||
const p2 = playersData[match.player2];
|
const p2 = playersData[match.player2];
|
||||||
if (!p1 || !p2) return;
|
if (!p1 || !p2) return;
|
||||||
|
|
||||||
const matchCard = document.createElement('div');
|
const matchCard = document.createElement('div');
|
||||||
matchCard.className = 'match-card';
|
matchCard.className = 'match-card';
|
||||||
matchCard.onclick = () => openPredictionModal(match);
|
matchCard.onclick = () => openPredictionModal(match);
|
||||||
|
|
||||||
const badgeColor = match.gender === 'Messieurs' ? '#e85d04' : '#0077b6';
|
const badgeColor = match.gender === 'Messieurs' ? '#e85d04' : '#0077b6';
|
||||||
|
|
||||||
matchCard.innerHTML = `
|
matchCard.innerHTML = `
|
||||||
<div class="player-info">
|
<div class="player-info">
|
||||||
<img src="${p1.photo}" alt="${p1.name}" class="player-photo">
|
<img src="${p1.photo}" alt="${p1.name}" class="player-photo">
|
||||||
<div class="player-details">
|
<div class="player-details">
|
||||||
<h3>${p1.name}</h3>
|
<h3>${p1.name}</h3>
|
||||||
<p>${p1.nationality} • ${p1.handedness}</p>
|
<p>${p1.nationality} — ${p1.handedness}</p>
|
||||||
<p>Classement : #${p1.ranking}</p>
|
<p>Classement : #${p1.ranking}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -79,7 +65,7 @@ function loadMatches() {
|
|||||||
<img src="${p2.photo}" alt="${p2.name}" class="player-photo">
|
<img src="${p2.photo}" alt="${p2.name}" class="player-photo">
|
||||||
<div class="player-details">
|
<div class="player-details">
|
||||||
<h3>${p2.name}</h3>
|
<h3>${p2.name}</h3>
|
||||||
<p>${p2.nationality} • ${p2.handedness}</p>
|
<p>${p2.nationality} — ${p2.handedness}</p>
|
||||||
<p>Classement : #${p2.ranking}</p>
|
<p>Classement : #${p2.ranking}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -87,14 +73,13 @@ function loadMatches() {
|
|||||||
<span class="round" style="background: ${badgeColor}">${match.round}</span>
|
<span class="round" style="background: ${badgeColor}">${match.round}</span>
|
||||||
<p class="date">${new Date(match.date).toLocaleDateString('fr-FR', {day: 'numeric', month: 'long'})}</p>
|
<p class="date">${new Date(match.date).toLocaleDateString('fr-FR', {day: 'numeric', month: 'long'})}</p>
|
||||||
<p style="font-size:0.8rem; color:#888;">${match.court}</p>
|
<p style="font-size:0.8rem; color:#888;">${match.court}</p>
|
||||||
${match.status === 'completed' ? `<p class="score" style="font-weight:bold; color:#28a745; margin-top:5px;">${match.score}</p>` : '<p style="color:#e85d04; font-size:0.85rem; font-weight:600;">👉 Pronostiquer</p>'}
|
${match.status === 'completed' ? `<p class="score" style="font-weight:bold; color:#28a745; margin-top:5px;">${match.score}</p>` : '<p style="color:#e85d04; font-size:0.85rem; font-weight:600;">⚡ Pronostiquer</p>'}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
container.appendChild(matchCard);
|
container.appendChild(matchCard);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MOTEUR DE RECHERCHE ET RENDU DES JOUEURS ---
|
|
||||||
function handlePlayerSearch() {
|
function handlePlayerSearch() {
|
||||||
loadPlayers();
|
loadPlayers();
|
||||||
}
|
}
|
||||||
@@ -103,38 +88,31 @@ function loadPlayers() {
|
|||||||
const container = document.getElementById('playersGrid');
|
const container = document.getElementById('playersGrid');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
|
|
||||||
const searchQuery = document.getElementById('playerSearch').value.toLowerCase();
|
const searchQuery = document.getElementById('playerSearch').value.toLowerCase();
|
||||||
const genderFilter = document.getElementById('genderFilter').value;
|
const genderFilter = document.getElementById('genderFilter').value;
|
||||||
|
|
||||||
Object.keys(playersData).forEach(key => {
|
Object.keys(playersData).forEach(key => {
|
||||||
const player = playersData[key];
|
const player = playersData[key];
|
||||||
|
|
||||||
// Validation des filtres de recherche croisés
|
|
||||||
const matchesSearch = player.name.toLowerCase().includes(searchQuery) || player.nationality.toLowerCase().includes(searchQuery);
|
const matchesSearch = player.name.toLowerCase().includes(searchQuery) || player.nationality.toLowerCase().includes(searchQuery);
|
||||||
const matchesGender = genderFilter === 'all' || player.gender === genderFilter;
|
const matchesGender = genderFilter === 'all' || player.gender === genderFilter;
|
||||||
|
|
||||||
if (matchesSearch && matchesGender) {
|
if (matchesSearch && matchesGender) {
|
||||||
const card = document.createElement('div');
|
const card = document.createElement('div');
|
||||||
card.className = 'player-card';
|
card.className = 'player-card';
|
||||||
|
|
||||||
const strengthsHtml = player.strengths.map(s => `<span class="tag strength">${s}</span>`).join('');
|
const strengthsHtml = player.strengths.map(s => `<span class="tag strength">${s}</span>`).join('');
|
||||||
const weaknessesHtml = player.weaknesses.map(w => `<span class="tag weakness">${w}</span>`).join('');
|
const weaknessesHtml = player.weaknesses.map(w => `<span class="tag weakness">${w}</span>`).join('');
|
||||||
const genderBadgeColor = player.gender === 'Messieurs' ? '#e85d04' : '#0077b6';
|
const genderBadgeColor = player.gender === 'Messieurs' ? '#e85d04' : '#0077b6';
|
||||||
|
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<div class="player-header" style="background: linear-gradient(135deg, ${genderBadgeColor}, #faedcd)">
|
<div class="player-header" style="background: linear-gradient(135deg, ${genderBadgeColor}, #faedcd)">
|
||||||
<span style="position:absolute; top:10px; right:10px; background:rgba(255,255,255,0.2); padding: 2px 8px; border-radius:10px; color:white; font-size:0.75rem; font-weight:bold;">${player.gender}</span>
|
<span style="position:absolute; top:10px; right:10px; background:rgba(255,255,255,0.2); padding: 2px 8px; border-radius:10px; color:white; font-size:0.75rem; font-weight:bold;">${player.gender}</span>
|
||||||
<img src="${player.photo}" alt="${player.name}">
|
<img src="${player.photo}" alt="${player.name}">
|
||||||
<h3>${player.name}</h3>
|
<h3>${player.name}</h3>
|
||||||
<p>#${player.ranking} Mondial • ${player.points} pts</p>
|
<p>#${player.ranking} Mondial — ${player.points} pts</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="player-body">
|
<div class="player-body">
|
||||||
<div class="stat-row"><span>🎂 Âge (en 2026)</span><strong>${player.age} ans</strong></div>
|
<div class="stat-row"><span>Âge (en 2026)</span><strong>${player.age} ans</strong></div>
|
||||||
<div class="stat-row"><span>📏 Taille</span><strong>${player.height}</strong></div>
|
<div class="stat-row"><span>📏 Taille</span><strong>${player.height}</strong></div>
|
||||||
<div class="stat-row"><span>🌍 Nationalité</span><strong>${player.nationality}</strong></div>
|
<div class="stat-row"><span>🌍 Nationalité</span><strong>${player.nationality}</strong></div>
|
||||||
<div class="stat-row"><span>🤝 Latéralité</span><strong>${player.handedness}</strong></div>
|
<div class="stat-row"><span>🎾 Latéralité</span><strong>${player.handedness}</strong></div>
|
||||||
<div class="stat-row"><span>📊 Efficacité Terre Battue</span><strong style="color:#e85d04">${(player.surfaceStats.clay.winRate * 100).toFixed(0)}%</strong></div>
|
<div class="stat-row"><span>🔥 Efficacité Terre Battue</span><strong style="color:#e85d04">${(player.surfaceStats.clay.winRate * 100).toFixed(0)}%</strong></div>
|
||||||
<div class="strengths"><h4>💪 Points forts</h4>${strengthsHtml}</div>
|
<div class="strengths"><h4>💪 Points forts</h4>${strengthsHtml}</div>
|
||||||
<div class="weaknesses" style="margin-top:10px;"><h4>⚠️ Points faibles</h4>${weaknessesHtml}</div>
|
<div class="weaknesses" style="margin-top:10px;"><h4>⚠️ Points faibles</h4>${weaknessesHtml}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -144,17 +122,13 @@ function loadPlayers() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MODAL & ANALYSE TACTIQUE DYNAMIQUE ---
|
|
||||||
function openPredictionModal(match) {
|
function openPredictionModal(match) {
|
||||||
if (match.status === 'completed') return;
|
if (match.status === 'completed') return;
|
||||||
currentMatch = match;
|
currentMatch = match;
|
||||||
|
|
||||||
const p1 = playersData[match.player1];
|
const p1 = playersData[match.player1];
|
||||||
const p2 = playersData[match.player2];
|
const p2 = playersData[match.player2];
|
||||||
|
|
||||||
const modal = document.getElementById('predictionModal');
|
const modal = document.getElementById('predictionModal');
|
||||||
const details = document.getElementById('matchDetails');
|
const details = document.getElementById('matchDetails');
|
||||||
|
|
||||||
details.innerHTML = `
|
details.innerHTML = `
|
||||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; margin-bottom: 1.5rem; text-align: center;">
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; margin-bottom: 1.5rem; text-align: center;">
|
||||||
<div>
|
<div>
|
||||||
@@ -170,47 +144,40 @@ function openPredictionModal(match) {
|
|||||||
</div>
|
</div>
|
||||||
<p style="text-align: center; font-weight: 600; color: #e85d04;">${match.round} — ${match.court}</p>
|
<p style="text-align: center; font-weight: 600; color: #e85d04;">${match.round} — ${match.court}</p>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Calcul des probabilités de réussite via l'algorithme croisé
|
|
||||||
const probs = calculateWinProbability(match.player1, match.player2);
|
const probs = calculateWinProbability(match.player1, match.player2);
|
||||||
document.getElementById('prob1').style.width = `${probs.player1}%`;
|
document.getElementById('prob1').style.width = `${probs.player1}%`;
|
||||||
document.getElementById('prob2').style.width = `${probs.player2}%`;
|
document.getElementById('prob2').style.width = `${probs.player2}%`;
|
||||||
document.getElementById('probText1').textContent = `${probs.player1}%`;
|
document.getElementById('probText1').textContent = `${probs.player1}%`;
|
||||||
document.getElementById('probText2').textContent = `${probs.player2}%`;
|
document.getElementById('probText2').textContent = `${probs.player2}%`;
|
||||||
|
|
||||||
document.getElementById('predictBtn1').textContent = `Miser sur ${p1.name}`;
|
document.getElementById('predictBtn1').textContent = `Miser sur ${p1.name}`;
|
||||||
document.getElementById('predictBtn2').textContent = `Miser sur ${p2.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 analysis = getMatchupAnalysis(match.player1, match.player2);
|
||||||
const analysisDiv = document.getElementById('matchupAnalysis');
|
const analysisDiv = document.getElementById('matchupAnalysis');
|
||||||
|
|
||||||
analysisDiv.innerHTML = `
|
analysisDiv.innerHTML = `
|
||||||
<h3 style="margin-bottom:10px; font-size:1.1rem; border-bottom:1px solid #ddd; padding-bottom:5px;">🔬 Analyse tactique personnalisée</h3>
|
<h3 style="margin-bottom:10px; font-size:1.1rem; border-bottom:1px solid #ddd; padding-bottom:5px;">📊 Analyse tactique personnalisée</h3>
|
||||||
<div class="analysis-grid" style="display:grid; grid-template-columns: 1fr 1fr; gap:1.5rem;">
|
<div class="analysis-grid" style="display:grid; grid-template-columns: 1fr 1fr; gap:1.5rem;">
|
||||||
<div class="advantage">
|
<div class="advantage">
|
||||||
<h4 style="color:#28a745;">👍 Avantages de ${p1.name}</h4>
|
<h4 style="color:#28a745;">✅ Avantages de ${p1.name}</h4>
|
||||||
<ul style="padding-left:15px; font-size:0.85rem; margin-top:5px;">
|
<ul style="padding-left:15px; font-size:0.85rem; margin-top:5px;">
|
||||||
${analysis.player1Advantages.map(a => `<li style="margin-bottom:4px;">${a}</li>`).join('')}
|
${analysis.player1Advantages.map(a => `<li style="margin-bottom:4px;">${a}</li>`).join('')}
|
||||||
</ul>
|
</ul>
|
||||||
<h4 style="color:#dc3545; margin-top:10px;">👎 Faiblesses exploitables</h4>
|
<h4 style="color:#dc3545; margin-top:10px;">⚠️ Faiblesses exploitables</h4>
|
||||||
<ul style="padding-left:15px; font-size:0.85rem; margin-top:5px; color:#555;">
|
<ul style="padding-left:15px; font-size:0.85rem; margin-top:5px; color:#555;">
|
||||||
${analysis.player1Disadvantages.map(d => `<li style="margin-bottom:4px;">${d}</li>`).join('')}
|
${analysis.player1Disadvantages.map(d => `<li style="margin-bottom:4px;">${d}</li>`).join('')}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="advantage">
|
<div class="advantage">
|
||||||
<h4 style="color:#28a745;">👍 Avantages de ${p2.name}</h4>
|
<h4 style="color:#28a745;">✅ Avantages de ${p2.name}</h4>
|
||||||
<ul style="padding-left:15px; font-size:0.85rem; margin-top:5px;">
|
<ul style="padding-left:15px; font-size:0.85rem; margin-top:5px;">
|
||||||
${analysis.player2Advantages.map(a => `<li style="margin-bottom:4px;">${a}</li>`).join('')}
|
${analysis.player2Advantages.map(a => `<li style="margin-bottom:4px;">${a}</li>`).join('')}
|
||||||
</ul>
|
</ul>
|
||||||
<h4 style="color:#dc3545; margin-top:10px;">👎 Faiblesses exploitables</h4>
|
<h4 style="color:#dc3545; margin-top:10px;">⚠️ Faiblesses exploitables</h4>
|
||||||
<ul style="padding-left:15px; font-size:0.85rem; margin-top:5px; color:#555;">
|
<ul style="padding-left:15px; font-size:0.85rem; margin-top:5px; color:#555;">
|
||||||
${analysis.player2Disadvantages.map(d => `<li style="margin-bottom:4px;">${d}</li>`).join('')}
|
${analysis.player2Disadvantages.map(d => `<li style="margin-bottom:4px;">${d}</li>`).join('')}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
modal.style.display = 'block';
|
modal.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,24 +189,20 @@ function closePredictionModal() {
|
|||||||
function makePrediction(playerNum) {
|
function makePrediction(playerNum) {
|
||||||
if (!currentMatch) return;
|
if (!currentMatch) return;
|
||||||
const selectedPlayer = playerNum === 1 ? playersData[currentMatch.player1] : playersData[currentMatch.player2];
|
const selectedPlayer = playerNum === 1 ? playersData[currentMatch.player1] : playersData[currentMatch.player2];
|
||||||
|
currentUser.points += 10;
|
||||||
currentUser.points += 10; // Gain de participation standard
|
|
||||||
currentUser.predictionsCount += 1;
|
currentUser.predictionsCount += 1;
|
||||||
|
|
||||||
localStorage.setItem('currentUser', JSON.stringify(currentUser));
|
localStorage.setItem('currentUser', JSON.stringify(currentUser));
|
||||||
initDashboard();
|
initDashboard();
|
||||||
|
|
||||||
alert(`🎯 Pronostic enregistré avec succès pour ${selectedPlayer.name} ! +10 points ajoutés.`);
|
alert(`🎯 Pronostic enregistré avec succès pour ${selectedPlayer.name} ! +10 points ajoutés.`);
|
||||||
closePredictionModal();
|
closePredictionModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- CLASSEMENT ET STATISTIQUES ---
|
|
||||||
function loadLeaderboard() {
|
function loadLeaderboard() {
|
||||||
const tbody = document.getElementById('leaderboardBody');
|
const tbody = document.getElementById('leaderboardBody');
|
||||||
if (!tbody) return;
|
if (!tbody) return;
|
||||||
tbody.innerHTML = `
|
tbody.innerHTML = `
|
||||||
<tr style="font-weight:bold; background:#faf3e0;">
|
<tr style="font-weight:bold; background:#faf3e0;">
|
||||||
<td>🥇 1</td><td>${currentUser.username} (Vous)</td><td>${currentUser.points}</td><td>${Math.round(currentUser.predictionsCount * (currentUser.successRate/100))}</td>
|
<td>🏆 1</td><td>${currentUser.username} (Vous)</td><td>${currentUser.points}</td><td>${Math.round(currentUser.predictionsCount * (currentUser.successRate/100))}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td>🥈 2</td><td>BabolatFan_26</td><td>290</td><td>5</td></tr>
|
<tr><td>🥈 2</td><td>BabolatFan_26</td><td>290</td><td>5</td></tr>
|
||||||
<tr><td>🥉 3</td><td>ClayCourtKing</td><td>240</td><td>4</td></tr>
|
<tr><td>🥉 3</td><td>ClayCourtKing</td><td>240</td><td>4</td></tr>
|
||||||
@@ -254,11 +217,10 @@ function loadStats() {
|
|||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
alert("Session clôturée.");
|
alert("Session fermée.");
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fermeture du modal au clic à l'extérieur
|
|
||||||
window.onclick = function(event) {
|
window.onclick = function(event) {
|
||||||
const modal = document.getElementById('predictionModal');
|
const modal = document.getElementById('predictionModal');
|
||||||
if (event.target === modal) closePredictionModal();
|
if (event.target === modal) closePredictionModal();
|
||||||
|
|||||||
Reference in New Issue
Block a user