File size: 37,001 Bytes
ddd7255
 
 
 
 
013977a
840f62b
5af9065
013977a
5af9065
 
 
 
ddd7255
013977a
 
ddd7255
 
 
013977a
 
ddd7255
 
5af9065
013977a
5af9065
 
013977a
5af9065
 
 
ddd7255
013977a
ddd7255
 
013977a
 
5af9065
 
013977a
5af9065
 
 
013977a
 
1a9859c
5af9065
840f62b
5af9065
013977a
 
5af9065
 
013977a
 
 
 
ddd7255
5af9065
013977a
 
 
 
 
5af9065
 
 
013977a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5af9065
 
013977a
5af9065
 
 
 
013977a
5af9065
 
 
013977a
 
5af9065
 
 
 
 
 
 
013977a
 
5af9065
 
 
ddd7255
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LiftTrack - Firebase Edition (Debug)</title> <!-- Titre mis à jour -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>

    <!-- SDK Firebase (v8) -->
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-firestore.js"></script>

    <style>
        /* CSS Identique */
        :root { /* ... */ --bg-dark: #121212; --bg-card: #1e1e1e; --text-light: #e0e0e0; --accent: #4CAF50; --accent-dark: #3a8a3d; --danger: #f44336; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--bg-dark); color: var(--text-light); min-height: 100vh; padding-bottom: 80px; } .container { width: 100%; max-width: 800px; margin: 0 auto; padding: 1rem; } header { padding: 1rem 0; text-align: center; border-bottom: 1px solid #333; margin-bottom: 1rem; } h1, h2, h3 { color: var(--accent); } .btn { background-color: var(--accent); color: white; border: none; padding: 0.6rem 1.2rem; border-radius: 4px; cursor: pointer; font-weight: bold; transition: background-color 0.2s; } .btn:hover { background-color: var(--accent-dark); } .btn:disabled { background-color: #555; cursor: not-allowed; } .btn-outline { background-color: transparent; color: var(--accent); border: 1px solid var(--accent); } .btn-outline:disabled { color: #555; border-color: #555; } .btn-danger { background-color: var(--danger); } input, select, textarea { width: 100%; padding: 0.6rem; margin-bottom: 1rem; background-color: #2a2a2a; border: 1px solid #444; border-radius: 4px; color: var(--text-light); } input[type="checkbox"] { width: auto; margin-right: 0.5rem; vertical-align: middle; } .card { background-color: var(--bg-card); border-radius: 8px; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 5px rgba(0,0,0,0.2); } .form-group { margin-bottom: 1rem; } .form-row { display: flex; gap: 0.5rem; margin-bottom: 0.5rem; flex-wrap: wrap; } .form-row > * { flex: 1; margin-bottom: 0; min-width: 100px; } label { display: block; margin-bottom: 0.3rem; color: #bbb; font-size: 0.9rem; } .exercise { border-left: 3px solid var(--accent); padding-left: 1rem; margin-bottom: 1.5rem; display: none; } .exercise.active-exercise { display: block; animation: fadeIn 0.3s ease-in-out; } .exercise-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; gap: 0.5rem;} .exercise-header input {margin-bottom: 0;} .series-container { margin-left: 0.5rem; margin-top: 0.5rem; } .series { background-color: #252525; padding: 0.7rem; border-radius: 4px; margin-bottom: 0.5rem; } .nav-bottom { position: fixed; bottom: 0; left: 0; width: 100%; background-color: #1a1a1a; display: flex; justify-content: space-around; padding: 0.7rem 0; box-shadow: 0 -2px 10px rgba(0,0,0,0.3); z-index: 10; } .nav-item { text-align: center; color: #888; text-decoration: none; font-size: 0.85rem; transition: color 0.2s; padding: 0 0.5rem;} .nav-item.active { color: var(--accent); } .nav-icon { font-size: 1.4rem; margin-bottom: 0.2rem; } .workout-card { border-left: 3px solid var(--accent); cursor: pointer; transition: transform 0.2s; } .workout-card:hover { transform: translateX(5px); } .workout-header { display: flex; justify-content: space-between; align-items: flex-start; } .stat-card { text-align: center; padding: 1rem; } .stat-value { font-size: 1.8rem; color: var(--accent); font-weight: bold; } .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 1rem; } .hidden { display: none; } #login-page { display: block; } #main-app-content { display: none; } #app-container > div:not(.active) { display: none !important; } .flex-between { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem;} .badge { background-color: var(--accent); color: white; padding: 0.2rem 0.5rem; border-radius: 10px; font-size: 0.8rem; white-space: nowrap; } .spinner { border: 4px solid rgba(0, 0, 0, 0.1); width: 36px; height: 36px; border-radius: 50%; border-left-color: var(--accent); animation: spin 1s linear infinite; margin: 2rem auto; display: none; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .exercise-summary { margin: 0.3rem 0; padding: 0.3rem 0; border-bottom: 1px solid #333; font-size: 0.9rem;} .exercise-summary:last-child { border-bottom: none; } .satisfaction { display: flex; align-items: center; justify-content: center; flex-direction: column; margin-top: 1rem; } .satisfaction-value { font-size: 2rem; color: var(--accent); margin-top: 0.5rem; } .exercise-navigation { display: flex; justify-content: space-between; margin-top: 1rem; margin-bottom: 1rem; } #login-page .card { max-width: 400px; margin: 2rem auto; } #login-page h2 { text-align: center; margin-bottom: 1.5rem; } #login-error { color: var(--danger); text-align: center; margin-top: 0.5rem; font-size: 0.9rem; display: none; min-height: 1.2em; /* Pour éviter saut de layout */ } #login-form button { margin-top: 0.5rem;} .auth-switch { text-align: center; margin-top: 1.5rem; font-size: 0.9rem; } .auth-switch a { color: var(--accent); cursor: pointer; text-decoration: underline; } .user-info { text-align: right; margin-bottom: 1rem; font-size: 0.9rem; color: #bbb;} .user-info strong { color: var(--text-light); } .user-info button { margin-left: 0.5rem; padding: 0.2rem 0.5rem; font-size: 0.8rem; } @media (max-width: 600px) { .form-row { flex-direction: column; gap: 0; } .container { padding: 0.5rem; } h1 { font-size: 1.5rem; } .flex-between { flex-direction: column; align-items: stretch; } .flex-between > div { width: 100%; display: flex; justify-content: flex-end; margin-top: 0.5rem;} .user-info { text-align: center; margin-bottom: 0.5rem;} .user-info button { display: block; margin: 0.5rem auto 0;} .exercise-navigation button { padding: 0.5rem; font-size: 0.9rem;} } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
    </style>
</head>
<body>
    <!-- Structure HTML identique -->
     <div class="container"> <header> <h1>LiftTrack</h1> <p>Suivi de vos séances de musculation</p> </header> <div id="login-page"> <div class="card"> <h2 id="auth-title">Connexion</h2> <form id="login-form"> <div class="form-group"> <label for="auth-email">Email</label> <input type="email" id="auth-email" placeholder="[email protected]" required> </div> <div class="form-group"> <label for="auth-password">Mot de passe</label> <input type="password" id="auth-password" placeholder="********" required> </div> <p id="login-error"></p> <button type="submit" id="auth-action-btn" class="btn" style="width: 100%;">Se Connecter</button> </form> <div class="auth-switch"> <span id="auth-switch-text">Pas encore de compte ?</span> <a id="auth-switch-link">Inscrivez-vous ici</a> </div> </div> </div> <div id="main-app-content"> <div class="user-info"> Connecté: <strong id="current-user-display"></strong> <button id="logout-btn" class="btn btn-outline">Déconnexion</button> </div> <div id="app-container"> <div id="home-page" class="active"> <div class="flex-between"> <h2>Mes séances</h2> <button id="new-workout-btn" class="btn">Nouvelle séance</button> </div> <div id="workouts-list" class="workout-list" style="margin-top: 1rem;"> <div class="spinner hidden"></div> <p id="empty-workout-message" class="hidden" style="text-align: center; margin-top: 2rem;"> Aucune séance enregistrée. </p> </div> </div> <div id="new-workout-page"> <div class="flex-between"> <h2>Nouvelle séance <span id="current-exercise-indicator" style="font-size: 0.9rem; color: #ccc;"></span></h2> <div> <button id="cancel-new-workout-btn" class="btn btn-outline" style="margin-right: 0.5rem;">Annuler</button> <button id="save-workout-btn" class="btn">Enregistrer Séance</button> </div> </div> <div class="card"> <div class="form-group"> <label for="workout-name">Nom de la séance</label> <input type="text" id="workout-name" placeholder="Ex: Push, Legs, Full Body..."> </div> <div class="form-row"> <div class="form-group"> <label for="workout-date">Date</label> <input type="date" id="workout-date"> </div> <div class="form-group"> <label for="workout-duration">Durée (min)</label> <input type="number" id="workout-duration" min="1" placeholder="60"> </div> </div> </div> <h3 style="margin: 1rem 0;">Exercices</h3> <div class="exercise-navigation card"> <button id="prev-exercise-btn" class="btn btn-outline">< Précédent</button> <span style="align-self: center; color: #ccc;">Exercice Actif</span> <button id="next-exercise-btn" class="btn btn-outline">Suivant ></button> </div> <div id="exercises-container"> </div> <button id="add-exercise-btn" class="btn btn-outline" style="width: 100%; margin-top: 1rem;">+ Ajouter un Nouvel Exercice</button> <div class="card" style="margin-top: 2rem;"> <div class="form-group"> <label for="satisfaction">Niveau de satisfaction (1-100%)</label> <input type="range" id="satisfaction" min="1" max="100" value="75"> <div class="satisfaction"> <span>Satisfaction</span> <div class="satisfaction-value">75%</div> </div> </div> </div> </div> <div id="workout-details-page"> <div class="flex-between"> <h2 id="detail-workout-name">Détail Séance</h2> <button id="back-to-home" class="btn btn-outline">Retour</button> </div> <div class="card"> <div class="workout-details-info"> <div class="form-row"> <p><strong>Date:</strong> <span id="detail-date"></span></p> <p><strong>Durée:</strong> <span id="detail-duration"></span> min</p> </div> </div> </div> <div class="stats-grid" style="margin-top: 1rem;"> <div class="card stat-card"> <div class="stat-value" id="detail-tonnage">0</div> <div>Tonnage Total (kg)</div> </div> <div class="card stat-card"> <div class="stat-value" id="detail-satisfaction">0%</div> <div>Satisfaction</div> </div> <div class="card stat-card"> <div class="stat-value" id="detail-exercises-count">0</div> <div>Exercices</div> </div> </div> <h3 style="margin: 1.5rem 0 1rem;">Exercices Réalisés</h3> <div id="detail-exercises-container"> </div> <button id="delete-workout-btn" class="btn btn-danger" style="width: 100%; margin-top: 2rem;">Supprimer cette séance</button> </div> <div id="stats-page"> <h2>Statistiques</h2> <div class="stats-grid"> <div class="card stat-card"> <div class="stat-value" id="stats-workout-count">0</div> <div>Séances Totales</div> </div> <div class="card stat-card"> <div class="stat-value" id="stats-avg-tonnage">0</div> <div>Tonnage Moyen</div> </div> <div class="card stat-card"> <div class="stat-value" id="stats-avg-satisfaction">0%</div> <div>Satisfaction Moyenne</div> </div> </div> <h3 style="margin: 1.5rem 0 1rem;">Tendances Récentes</h3> <div class="card"> <p style="text-align: center; margin: 1rem 0; color: #888;"> (La section des tendances récentes n'est pas encore implémentée.) </p> </div> </div> </div> <nav class="nav-bottom"> <a href="#" class="nav-item active" data-page="home-page"> <div class="nav-icon">📋</div> <div>Séances</div> </a> <a href="#" class="nav-item" data-page="stats-page"> <div class="nav-icon">📊</div> <div>Stats</div> </a> </nav> </div>

    <script>
        // =============== AJOUT FIREBASE ===============
        const firebaseConfig = { apiKey: "AIzaSyAkWvrRyXgrC7zbTtoh_GppsHMrz2rF7WM", authDomain: "lifttrackapp.firebaseapp.com", projectId: "lifttrackapp", storageBucket: "lifttrackapp.appspot.com", messagingSenderId: "594426771796", appId: "1:594426771796:web:789bef037ca0016c54b0c1", measurementId: "G-MXLFK0H160" };
        firebase.initializeApp(firebaseConfig);
        const auth = firebase.auth();
        const db = firebase.firestore();
        console.log("Firebase Initialisé !");
        // =============== FIN AJOUT FIREBASE ===============

        // --- Variables d'État ---
        let workouts = []; let currentWorkoutId = null; let currentExerciseIndex = 0; let workoutExercisesForm = []; let currentFirebaseUser = null;

        // --- Éléments DOM ---
        const loginPage = document.getElementById('login-page'); const mainAppContent = document.getElementById('main-app-content'); const authEmailInput = document.getElementById('auth-email'); const authPasswordInput = document.getElementById('auth-password'); const loginForm = document.getElementById('login-form'); const authActionButton = document.getElementById('auth-action-btn'); const authSwitchLink = document.getElementById('auth-switch-link'); const authTitle = document.getElementById('auth-title'); const authSwitchText = document.getElementById('auth-switch-text'); const loginError = document.getElementById('login-error'); const currentUserDisplay = document.getElementById('current-user-display'); const logoutBtn = document.getElementById('logout-btn'); const spinner = document.querySelector('#workouts-list .spinner'); const appContainer = document.getElementById('app-container'); const navItems = document.querySelectorAll('.nav-item'); const newWorkoutBtn = document.getElementById('new-workout-btn'); const saveWorkoutBtn = document.getElementById('save-workout-btn'); const cancelNewWorkoutBtn = document.getElementById('cancel-new-workout-btn'); const addExerciseBtn = document.getElementById('add-exercise-btn'); const exercisesContainer = document.getElementById('exercises-container'); const workoutsList = document.getElementById('workouts-list'); const backToHomeBtn = document.getElementById('back-to-home'); const deleteWorkoutBtn = document.getElementById('delete-workout-btn'); const satisfactionRange = document.getElementById('satisfaction'); const satisfactionValue = document.querySelector('.satisfaction-value'); const emptyWorkoutMessage = document.getElementById('empty-workout-message'); const workoutDateInput = document.getElementById('workout-date'); const prevExerciseBtn = document.getElementById('prev-exercise-btn'); const nextExerciseBtn = document.getElementById('next-exercise-btn'); const currentExerciseIndicator = document.getElementById('current-exercise-indicator');
        let isLoginMode = true;

        // --- Initialisation & Auth State ---
        document.addEventListener('DOMContentLoaded', () => { initAuthListener(); initEventListeners(); });

        function initAuthListener() {
            auth.onAuthStateChanged(user => {
                console.log("Auth state changed. User:", user ? user.uid : 'null'); // DEBUG
                if (user) { currentFirebaseUser = user; showApp(); } else { currentFirebaseUser = null; workouts = []; renderWorkoutsList(); showLoginPage(); }
            });
        }

        // --- Gestion Affichage Login/App ---
        function showLoginPage() { console.log("Affichage: Page Login"); loginPage.style.display = 'block'; mainAppContent.style.display = 'none'; }
        function showApp() { if (!currentFirebaseUser) { console.log("showApp annulé: pas d'utilisateur"); return; } console.log("Affichage: App Principale"); loginPage.style.display = 'none'; mainAppContent.style.display = 'block'; currentUserDisplay.textContent = currentFirebaseUser.email; setTodayDate(); loadWorkouts(); showPage('home-page'); }

        // --- Authentification Firebase ---
        function handleAuthAction(event) { event.preventDefault(); const email = authEmailInput.value; const password = authPasswordInput.value; loginError.textContent = ''; if (!email || !password) { loginError.textContent = 'Email et mot de passe requis.'; return; } authActionButton.disabled = true; authActionButton.textContent = 'Chargement...'; if (isLoginMode) { console.log("Tentative de connexion..."); auth.signInWithEmailAndPassword(email, password) .catch((error) => { console.error("Erreur connexion:", error); loginError.textContent = getAuthErrorMessage(error); }) .finally(() => { authActionButton.disabled = false; authActionButton.textContent = 'Se Connecter'; }); } else { console.log("Tentative d'inscription..."); auth.createUserWithEmailAndPassword(email, password) .catch((error) => { console.error("Erreur inscription:", error); loginError.textContent = getAuthErrorMessage(error); }) .finally(() => { authActionButton.disabled = false; authSwitchMode(); authActionButton.textContent = 'S\'inscrire'; }); } }
        function handleLogout() { console.log("Tentative de déconnexion..."); auth.signOut().catch((error) => { console.error("Erreur déconnexion:", error); alert("Erreur déconnexion."); }); }
        function authSwitchMode() { isLoginMode = !isLoginMode; loginError.textContent = ''; if (isLoginMode) { authTitle.textContent = 'Connexion'; authActionButton.textContent = 'Se Connecter'; authSwitchText.textContent = 'Pas encore de compte ?'; authSwitchLink.textContent = 'Inscrivez-vous ici'; } else { authTitle.textContent = 'Inscription'; authActionButton.textContent = 'S\'inscrire'; authSwitchText.textContent = 'Déjà un compte ?'; authSwitchLink.textContent = 'Connectez-vous ici'; } }
        function getAuthErrorMessage(error) { /* ... (identique) ... */ switch (error.code) { case 'auth/invalid-email': return 'Format d\'email invalide.'; case 'auth/user-disabled': return 'Ce compte utilisateur a été désactivé.'; case 'auth/user-not-found': return 'Aucun utilisateur trouvé avec cet email.'; case 'auth/wrong-password': return 'Mot de passe incorrect.'; case 'auth/email-already-in-use': return 'Cet email est déjà utilisé par un autre compte.'; case 'auth/weak-password': return 'Le mot de passe est trop faible (minimum 6 caractères).'; case 'auth/operation-not-allowed': return 'Connexion par email/mot de passe non activée.'; default: return 'Une erreur est survenue. Veuillez réessayer.'; } }

        // --- Persistance Firestore ---
        function loadWorkouts() { /* ... (identique, avec logs) ... */ if (!currentFirebaseUser) { console.log("Chargement annulé: aucun utilisateur connecté."); workouts = []; renderWorkoutsList(); return; } const userId = currentFirebaseUser.uid; console.log(`Chargement des séances pour l'utilisateur ${userId}...`); if (spinner) spinner.classList.remove('hidden'); emptyWorkoutMessage.classList.add('hidden'); workoutsList.innerHTML = ''; workouts = []; db.collection('workouts') .where('userId', '==', userId) .orderBy('date', 'desc') .get() .then((querySnapshot) => { console.log(`Trouvé ${querySnapshot.size} séances dans Firestore.`); querySnapshot.forEach((doc) => { const workoutData = doc.data(); workoutData.firestoreId = doc.id; workouts.push(workoutData); }); renderWorkoutsList(); }) .catch((error) => { console.error("Erreur chargement Firestore: ", error); alert("Erreur chargement séances."); }) .finally(() => { if (spinner) spinner.classList.add('hidden'); }); }
        // SAVE WORKOUT EST IDENTIQUE À LA VERSION PRÉCÉDENTE (utilise Firestore)
        function saveWorkout() { if (!currentFirebaseUser) { alert("Vous devez être connecté pour enregistrer."); return; } const userId = currentFirebaseUser.uid; workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise')); const workoutName = document.getElementById('workout-name').value.trim(); const workoutDate = document.getElementById('workout-date').value; const workoutDuration = parseInt(document.getElementById('workout-duration').value) || 0; const satisfaction = parseInt(document.getElementById('satisfaction').value); if (!workoutName || !workoutDate || workoutDuration <= 0) { alert("Données séance invalides."); return; } const exerciseElements = workoutExercisesForm; const exercises = []; if (exerciseElements.length === 0) { alert("Ajoutez au moins un exercice."); return; } let validationError = null; exerciseElements.forEach((exerciseEl, index) => { if (validationError) return; const nameInput = exerciseEl.querySelector('.exercise-name'); const exerciseName = nameInput ? nameInput.value.trim() : ''; const isUnilateral = exerciseEl.querySelector('.unilateral-checkbox').checked; if (!exerciseName) { validationError = `Nommez l'exercice #${index + 1}.`; if(nameInput) nameInput.focus(); return; } const series = []; const seriesElements = exerciseEl.querySelectorAll('.series'); if (seriesElements.length === 0) { validationError = `Exercice "${exerciseName}" sans série.`; return; } seriesElements.forEach(seriesEl => { if (validationError) return; const repsInput = seriesEl.querySelector('.reps'); const weightInput = seriesEl.querySelector('.weight'); const reps = parseInt(repsInput.value) || 0; const weight = parseFloat(weightInput.value) || 0; const isDegressive = seriesEl.querySelector('.degressive-checkbox').checked; if (reps <= 0) { validationError = `Reps invalides pour "${exerciseName}".`; if(repsInput) repsInput.focus(); return; } if (weight < 0) { validationError = `Charge invalide pour "${exerciseName}".`; if(weightInput) weightInput.focus(); return; } series.push({ reps, weight, isDegressive }); }); if (!validationError) { exercises.push({ name: exerciseName, isUnilateral, series }); } }); if (validationError) { alert(validationError); return; } let totalTonnage = 0; exercises.forEach(ex => ex.series.forEach(s => totalTonnage += s.reps * s.weight * (ex.isUnilateral ? 2 : 1))); const workout = { id: currentWorkoutId || `workout-${Date.now()}`, userId: userId, name: workoutName, date: workoutDate, duration: workoutDuration, exercises: exercises, totalTonnage: totalTonnage, satisfaction: satisfaction }; console.log("Tentative sauvegarde séance:", workout); saveWorkoutBtn.disabled = true; saveWorkoutBtn.textContent = 'Sauvegarde...'; db.collection('workouts').doc(workout.id).set(workout) .then(() => { console.log("Séance sauvegardée Firestore:", workout.id); const existingIndex = workouts.findIndex(w => w.id === workout.id); if (existingIndex > -1) { workouts[existingIndex] = workout; } else { workouts.push(workout); } confetti({ particleCount: 150, spread: 90, origin: { y: 0.6 } }); showPage('home-page'); renderWorkoutsList(); }) .catch((error) => { console.error("Erreur sauvegarde Firestore: ", error); alert("Erreur sauvegarde séance."); }) .finally(() => { saveWorkoutBtn.disabled = false; saveWorkoutBtn.textContent = 'Enregistrer Séance'; }); }
        // DELETE WORKOUT EST IDENTIQUE À LA VERSION PRÉCÉDENTE (utilise Firestore)
        function deleteWorkout() { if (!currentFirebaseUser || !currentWorkoutId) return; const workoutToDelete = workouts.find(w => w.id === currentWorkoutId); if (!workoutToDelete) return; const confirmDelete = confirm(`Supprimer séance "${workoutToDelete.name}" du ${new Date(workoutToDelete.date).toLocaleDateString('fr-FR')} ?`); if (!confirmDelete) return; console.log("Tentative suppression séance:", currentWorkoutId); deleteWorkoutBtn.disabled = true; deleteWorkoutBtn.textContent = 'Suppression...'; db.collection('workouts').doc(currentWorkoutId).delete() .then(() => { console.log("Séance supprimée Firestore:", currentWorkoutId); workouts = workouts.filter(w => w.id !== currentWorkoutId); currentWorkoutId = null; showPage('home-page'); renderWorkoutsList(); }) .catch((error) => { console.error("Erreur suppression Firestore:", error); alert("Erreur suppression séance."); }) .finally(() => { deleteWorkoutBtn.disabled = false; deleteWorkoutBtn.textContent = 'Supprimer cette séance'; }); }

        // --- Écouteurs d'Événements (Setup Initial) ---
        function initEventListeners() {
            // Auth
            loginForm.addEventListener('submit', handleAuthAction);
            authSwitchLink.addEventListener('click', authSwitchMode);
            logoutBtn.addEventListener('click', handleLogout);

            // App Navigation & Actions
            navItems.forEach(item => { item.addEventListener('click', (e) => { e.preventDefault(); if (!currentFirebaseUser) return; const targetPageId = item.getAttribute('data-page'); showPage(targetPageId); /* ... MAJ nav active ... */ }); });

            // **AJOUT DES LOGS DANS LE LISTENER DU BOUTON**
            newWorkoutBtn.addEventListener('click', () => {
                console.log("Clic sur 'Nouvelle séance'"); // <<< LOG 1
                if (!currentFirebaseUser) {
                    console.error("'Nouvelle séance' bloqué: Utilisateur non connecté (currentFirebaseUser est null)"); // <<< LOG 2
                    alert("Veuillez vous reconnecter pour ajouter une séance."); // Message utilisateur
                    return;
                }
                try {
                    console.log("Utilisateur connecté, préparation formulaire..."); // <<< LOG 3
                    currentWorkoutId = null;
                    clearNewWorkoutForm(); // Cette fonction appelle addExercise et renderActiveExerciseForm
                    console.log("Formulaire nettoyé (clearNewWorkoutForm exécuté)."); // <<< LOG 4
                    showPage('new-workout-page'); // Cette fonction appelle triggerFlameAnimation et renderActiveExerciseForm
                    console.log("Affichage page nouvelle séance demandé (showPage exécuté)."); // <<< LOG 5
                } catch (error) {
                     console.error("Erreur dans le listener de 'Nouvelle séance':", error); // <<< LOG ERREUR
                     alert("Une erreur est survenue lors de l'ouverture du formulaire.");
                }
            });

            cancelNewWorkoutBtn.addEventListener('click', () => showPage('home-page'));
            saveWorkoutBtn.addEventListener('click', saveWorkout);
            addExerciseBtn.addEventListener('click', handleAddNewExercise);
            prevExerciseBtn.addEventListener('click', navigateExerciseForm.bind(null, -1));
            nextExerciseBtn.addEventListener('click', navigateExerciseForm.bind(null, 1));
            backToHomeBtn.addEventListener('click', () => showPage('home-page'));
            deleteWorkoutBtn.addEventListener('click', deleteWorkout);
            satisfactionRange.addEventListener('input', () => { satisfactionValue.textContent = `${satisfactionRange.value}%`; });
        }

        // --- Fonctions Utilitaires et d'Affichage (non modifiées) ---
        // (triggerFlameAnimation, handleAddNewExercise, addExercise, addSeries, navigateExerciseForm, renderActiveExerciseForm, updateExerciseNavButtons, clearNewWorkoutForm, renderWorkoutsList, displayWorkoutDetails, updateStats SONT IDENTIQUES)
         function triggerFlameAnimation() { const duration = 1 * 1000; const animationEnd = Date.now() + duration; const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 }; function randomInRange(min, max) { return Math.random() * (max - min) + min; } const interval = setInterval(function() { const timeLeft = animationEnd - Date.now(); if (timeLeft <= 0) { return clearInterval(interval); } const particleCount = 50 * (timeLeft / duration); confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.3, 0.7), y: Math.random() - 0.2 }, angle: randomInRange(240, 300), spread: randomInRange(50, 90), gravity: 0.5, drift: randomInRange(-1, 1), colors: ['#ff6f00', '#ff8f00', '#ffa000', '#ffcc00'] })); }, 250); }
        function handleAddNewExercise() { addExercise(true); }
        function addExercise(navigateToNew = false) { if (!currentFirebaseUser) return; const exerciseId = `exercise-${Date.now()}`; const exerciseDiv = document.createElement('div'); exerciseDiv.className = 'card exercise'; exerciseDiv.setAttribute('data-exercise-id', exerciseId); exerciseDiv.innerHTML = `<div class="exercise-header"> <input type="text" placeholder="Nom Exercice" class="exercise-name"> <button class="btn btn-danger remove-exercise" style="padding: 0.3rem 0.6rem; flex-shrink: 0;">×</button> </div> <div class="form-group" style="margin-top: 0.5rem; margin-bottom: 0.5rem;"> <label style="display: inline-flex; align-items: center; color: #bbb; font-size: 0.9rem;"> <input type="checkbox" class="unilateral-checkbox"> Unilatéral </label> </div> <div class="series-container"></div> <button class="btn btn-outline add-series" style="width: 100%; margin-top: 0.5rem; padding: 0.4rem;">+ Ajouter Série</button>`; exercisesContainer.appendChild(exerciseDiv); workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise')); const removeBtn = exerciseDiv.querySelector('.remove-exercise'); removeBtn.addEventListener('click', () => { const indexToRemove = workoutExercisesForm.indexOf(exerciseDiv); if (indexToRemove > -1) { exerciseDiv.remove(); workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise')); if (currentExerciseIndex >= indexToRemove) { currentExerciseIndex = Math.max(0, currentExerciseIndex - 1); } if (currentExerciseIndex >= workoutExercisesForm.length) { currentExerciseIndex = Math.max(0, workoutExercisesForm.length - 1); } renderActiveExerciseForm(); } }); const addSeriesBtn = exerciseDiv.querySelector('.add-series'); const seriesContainer = exerciseDiv.querySelector('.series-container'); addSeriesBtn.addEventListener('click', () => addSeries(seriesContainer)); addSeries(seriesContainer); if (navigateToNew) { currentExerciseIndex = workoutExercisesForm.length - 1; renderActiveExerciseForm(); } else { updateExerciseNavButtons(); } }
        function addSeries(container) { if (!currentFirebaseUser || !container) return; const seriesId = `series-${Date.now()}`; const seriesDiv = document.createElement('div'); seriesDiv.className = 'series'; seriesDiv.setAttribute('data-series-id', seriesId); seriesDiv.innerHTML = `<div class="form-row" style="align-items: flex-end; gap: 0.8rem;"> <div class="form-group" style="flex: 1.2;"> <label>Reps</label> <input type="number" class="reps" min="1" placeholder="10" style="padding: 0.4rem;"> </div> <div class="form-group" style="flex: 1.2;"> <label>Charge (kg)</label> <input type="number" class="weight" min="0" step="0.1" placeholder="20" style="padding: 0.4rem;"> </div> <div class="form-group" style="flex: 1; display: flex; align-items: center; padding-bottom: 0.6rem; min-width: 100px;"> <label style="display: inline-flex; align-items: center; color: #bbb; font-size: 0.8rem; margin-bottom: 0; white-space: nowrap;"> <input type="checkbox" class="degressive-checkbox" style="margin-right: 0.3rem;"> Dégressive </label> </div> <button class="btn btn-danger remove-series" style="padding: 0.3rem 0.6rem; margin-bottom: 0.6rem; flex-basis: 30px; flex-grow: 0; align-self: center;">×</button> </div>`; container.appendChild(seriesDiv); const removeBtn = seriesDiv.querySelector('.remove-series'); removeBtn.addEventListener('click', () => seriesDiv.remove()); }
        function navigateExerciseForm(direction) { workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise')); const newIndex = currentExerciseIndex + direction; if (newIndex >= 0 && newIndex < workoutExercisesForm.length) { currentExerciseIndex = newIndex; renderActiveExerciseForm(); } }
        function renderActiveExerciseForm() { workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise')); workoutExercisesForm.forEach(ex => ex.classList.remove('active-exercise')); if (currentExerciseIndex >= 0 && currentExerciseIndex < workoutExercisesForm.length) { workoutExercisesForm[currentExerciseIndex].classList.add('active-exercise'); } updateExerciseNavButtons(); }
        function updateExerciseNavButtons() { const totalExercises = workoutExercisesForm.length; if (totalExercises === 0) { currentExerciseIndicator.textContent = "(Aucun exercice)"; prevExerciseBtn.disabled = true; nextExerciseBtn.disabled = true; } else { currentExerciseIndicator.textContent = `(${currentExerciseIndex + 1}/${totalExercises})`; prevExerciseBtn.disabled = currentExerciseIndex === 0; nextExerciseBtn.disabled = currentExerciseIndex === totalExercises - 1; } }
        function clearNewWorkoutForm() { console.log("Début clearNewWorkoutForm"); if (!currentFirebaseUser) return; document.getElementById('workout-name').value = ''; document.getElementById('workout-duration').value = ''; setTodayDate(); exercisesContainer.innerHTML = ''; workoutExercisesForm = []; satisfactionRange.value = 75; satisfactionValue.textContent = '75%'; currentWorkoutId = null; currentExerciseIndex = 0; addExercise(false); console.log("Fin clearNewWorkoutForm (après addExercise)"); renderActiveExerciseForm(); }
        function setTodayDate() { if(workoutDateInput) { try { const today = new Date().toISOString().split('T')[0]; workoutDateInput.value = today; } catch (e) { console.error("Impossible définir date:", e); workoutDateInput.value = ''; } } }
        function renderWorkoutsList() { if (!currentFirebaseUser) { workoutsList.innerHTML = ''; emptyWorkoutMessage.classList.remove('hidden'); updateStats(); return; } workoutsList.innerHTML = ''; if (workouts.length === 0) { emptyWorkoutMessage.classList.remove('hidden'); } else { emptyWorkoutMessage.classList.add('hidden'); const sortedWorkouts = [...workouts].sort((a, b) => new Date(b.date) - new Date(a.date)); sortedWorkouts.forEach(workout => { const workoutDate = new Date(workout.date).toLocaleDateString('fr-FR', { year: 'numeric', month: 'short', day: 'numeric' }); const workoutDiv = document.createElement('div'); workoutDiv.className = 'card workout-card'; workoutDiv.setAttribute('data-workout-id', workout.id); workoutDiv.innerHTML = `<div class="workout-header"><h3 style="margin-bottom: 0.5rem;">${workout.name}</h3><div class="badge">${workoutDate}</div></div><div class="workout-details" style="font-size: 0.9rem; color: #ccc; margin-top: 0.5rem;"><span>${workout.duration} min</span> | <span>${workout.exercises.length} exo${workout.exercises.length > 1 ? 's' : ''}</span> | <span>${workout.totalTonnage.toFixed(1)} kg</span> | <span>${workout.satisfaction}%</span></div>`; workoutDiv.addEventListener('click', () => displayWorkoutDetails(workout.id)); workoutsList.appendChild(workoutDiv); }); } updateStats(); }
        function displayWorkoutDetails(workoutId) { if (!currentFirebaseUser) return; const workout = workouts.find(w => w.id === workoutId); if (!workout) { console.error("Séance non trouvée:", workoutId); showPage('home-page'); return; } document.getElementById('detail-workout-name').textContent = workout.name; document.getElementById('detail-date').textContent = new Date(workout.date).toLocaleDateString('fr-FR'); document.getElementById('detail-duration').textContent = workout.duration; document.getElementById('detail-tonnage').textContent = workout.totalTonnage.toFixed(1); document.getElementById('detail-satisfaction').textContent = `${workout.satisfaction}%`; document.getElementById('detail-exercises-count').textContent = workout.exercises.length; const detailExercisesContainer = document.getElementById('detail-exercises-container'); detailExercisesContainer.innerHTML = ''; workout.exercises.forEach((exercise) => { const exerciseDiv = document.createElement('div'); exerciseDiv.className = 'card detail-exercise-card'; let seriesHtml = ''; exercise.series.forEach((serie, sIndex) => { const degressiveLabel = serie.isDegressive ? ' <span class="badge" style="font-size: 0.7rem; background-color: var(--accent-dark);">Dégr.</span>' : ''; const weightFactor = exercise.isUnilateral ? 2 : 1; const seriesTonnage = serie.reps * serie.weight * weightFactor; seriesHtml += `<div class="exercise-summary"><div class="flex-between"><span>Série ${sIndex + 1}: ${serie.reps} reps × ${serie.weight} kg${degressiveLabel}</span><span style="color: #aaa;">(${seriesTonnage.toFixed(1)} kg)</span></div></div>`; }); const unilateralLabel = exercise.isUnilateral ? ' <span class="badge" style="font-size: 0.7rem;">Unilat.</span>' : ''; exerciseDiv.innerHTML = `<h3 style="font-size: 1.1rem; margin-bottom: 0.5rem;">${exercise.name}${unilateralLabel}</h3> <div class="series-summary-container"> ${seriesHtml} </div>`; detailExercisesContainer.appendChild(exerciseDiv); }); currentWorkoutId = workoutId; showPage('workout-details-page'); }
        function updateStats() { if (!currentFirebaseUser) return; const workoutCount = workouts.length; document.getElementById('stats-workout-count').textContent = workoutCount; if (workoutCount === 0) { document.getElementById('stats-avg-tonnage').textContent = '0'; document.getElementById('stats-avg-satisfaction').textContent = '0%'; return; } const totalTonnageAll = workouts.reduce((sum, workout) => sum + (workout.totalTonnage || 0), 0); const avgTonnage = totalTonnageAll / workoutCount; document.getElementById('stats-avg-tonnage').textContent = avgTonnage.toFixed(1); const totalSatisfaction = workouts.reduce((sum, workout) => sum + (workout.satisfaction || 0), 0); const avgSatisfaction = totalSatisfaction / workoutCount; document.getElementById('stats-avg-satisfaction').textContent = `${Math.round(avgSatisfaction)}%`; }

    </script>
</body>
</html>