File size: 50,180 Bytes
ddd7255
 
 
 
 
26da13c
840f62b
5af9065
 
 
ddd7255
26da13c
 
 
 
 
 
 
ddd7255
 
 
26da13c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33ac953
26da13c
 
013977a
26da13c
5af9065
ddd7255
aec3430
7e54a3e
26da13c
 
 
 
 
 
013977a
5af9065
ee1053c
26da13c
ee1053c
f3abe96
26da13c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f3abe96
33ac953
 
aec3430
 
 
 
26da13c
aec3430
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ee1053c
f3abe96
ee1053c
 
 
f3abe96
33ac953
26da13c
 
41ebeb8
 
ddd7255
26da13c
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LiftTrack - Stats par Type</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>
    <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, sauf peut-être quelques ajustements mineurs pour la nouvelle section stats */
        :root { /* ... */ --bg-dark: #121212; --bg-card: #1e1e1e; --text-light: #e0e0e0; --accent: #4CAF50; --accent-dark: #3a8a3d; --danger: #f44336; --info: #2196F3; } * { 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); } .btn-info { background-color: var(--info); } 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; margin-left: 5px; } .badge.type-badge { background-color: var(--info); } .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; } #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; } #workout-types-list li { display: flex; justify-content: space-between; align-items: center; background-color: #2a2a2a; padding: 0.5rem 0.8rem; margin-bottom: 0.5rem; border-radius: 4px; border-left: 3px solid var(--info);} #add-type-form { display: flex; gap: 0.5rem; align-items: flex-end;} #add-type-form input { margin-bottom: 0; flex-grow: 1;} #add-type-form button { flex-shrink: 0; } #select-workout-type-page .card { text-align: center; } #select-workout-type-page .btn { margin-top: 1rem; } #select-workout-type { margin-bottom: 1rem;}
        .type-trend-card h4 { color: var(--info); border-bottom: 1px solid #444; padding-bottom: 0.5rem; margin-bottom: 0.8rem;}
        .type-trend-card ul { list-style: none; padding: 0; font-size: 0.9rem; }
        .type-trend-card li { margin-bottom: 0.4rem; color: #ccc; display: flex; justify-content: space-between; }
        .type-trend-card li span:first-child { color: #aaa; 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;} #add-type-form { flex-direction: column; align-items: stretch;} } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
    </style>
</head>
<body>
    <!-- HTML Body (structure externe identique) -->
    <div class="container">
        <header> <h1>LiftTrack</h1> <p>Suivi et Analyse de Séances</p> </header>
        <div id="login-page"> <!-- ... Login Form ... --> <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">
                <!-- Page Accueil -->
                <div id="home-page" class="active"> <div class="flex-between"> <h2>Mes séances</h2> <div> <button id="manage-types-btn" class="btn btn-outline" style="margin-right: 0.5rem;">Gérer Types</button> <button id="new-workout-btn" class="btn">Nouvelle séance</button> </div> </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>
                <!-- Page Gérer Types -->
                <div id="manage-types-page"> <div class="flex-between"> <h2>Gérer les Types</h2> <button class="btn btn-outline back-to-home-btn">Retour</button> </div> <div class="card"> <h3>Types Existants</h3> <ul id="workout-types-list" style="list-style: none; padding: 0; margin-top: 1rem;"> <li class="hidden" id="empty-types-message">Aucun type défini.</li> </ul> <div class="spinner hidden" id="types-spinner"></div> </div> <div class="card"> <h3>Ajouter un Type</h3> <form id="add-type-form"> <input type="text" id="new-type-name" placeholder="Nom (ex: Dos, Jambes)" required> <button type="submit" class="btn">Ajouter</button> </form> <p id="add-type-error" style="color: var(--danger); font-size: 0.9rem; margin-top: 0.5rem;"></p> </div> </div>
                <!-- Page Sélection Type -->
                <div id="select-workout-type-page"> <div class="flex-between"> <h2>Démarrer Séance</h2> <button class="btn btn-outline back-to-home-btn">Annuler</button> </div> <div class="card"> <h3>Type Prédéfini</h3> <select id="select-workout-type"> <option value="">-- Sélectionner --</option> </select> <button id="start-structured-workout-btn" class="btn" disabled>Démarrer Structurée</button> </div> <div class="card"> <h3>Séance Libre</h3> <button id="start-free-workout-btn" class="btn btn-info">Démarrer Libre</button> </div> </div>
                 <!-- Page Nouvelle Séance -->
                <div id="new-workout-page"> <div class="flex-between"> <h2>Nouvelle séance <span id="workout-type-indicator" class="badge type-badge hidden"></span> <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</button> </div> </div> <div class="card"> <div class="form-group"> <label for="workout-name">Nom Séance (optionnel)</label> <input type="text" id="workout-name" placeholder="Ex: Push Intense..."> </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 Exercice</button> <div class="card" style="margin-top: 2rem;"> <div class="form-group"> <label for="satisfaction">Satisfaction (1-100%)</label> <input type="range" id="satisfaction" min="1" max="100" value="75"> <div class="satisfaction"> <span></span> <div class="satisfaction-value">75%</div> </div> </div> </div> </div>
                <!-- Page Détail Séance -->
                <div id="workout-details-page"> <div class="flex-between"> <h2>Détail Séance <span id="detail-workout-type" class="badge type-badge hidden"></span></h2> <button class="btn btn-outline back-to-home-btn">Retour</button> </div> <div class="card"> <div class="workout-details-info"> <p><strong>Nom:</strong> <span id="detail-workout-name"></span></p> <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 (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</button> </div>
                <!-- Page Statistiques (Modifiée) -->
                <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 Moy.</div> </div> </div>
                     <h3 style="margin: 1.5rem 0 1rem;">Tendances par Type de Séance</h3>
                     <!-- Conteneur pour afficher les tendances -->
                     <div id="type-trends-container">
                         <p id="no-trends-message" style="text-align: center; color: #888;" class="hidden">
                             Pas assez de données pour afficher les tendances par type. Enregistrez plus de séances structurées.
                         </p>
                         <div class="spinner hidden" id="trends-spinner"></div>
                         <!-- Les cartes de tendance seront ajoutées ici par JS -->
                     </div>
                </div>
            </div>
            <!-- Menu Navigation Bas -->
            <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>
        // Firebase Init (Identique)
        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" };
        let app, auth, db; try { app = firebase.initializeApp(firebaseConfig); auth = firebase.auth(); db = firebase.firestore(); console.log("Firebase Initialisé !"); } catch (e) { console.error("Erreur Init Firebase:", e); alert("Erreur connexion DB."); }

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

        // --- Éléments DOM ---
        // (Déclarations identiques)
        const loginPage=document.getElementById('login-page'), mainAppContent=document.getElementById('main-app-content'), authEmailInput=document.getElementById('auth-email'), authPasswordInput=document.getElementById('auth-password'), loginForm=document.getElementById('login-form'), authActionButton=document.getElementById('auth-action-btn'), authSwitchLink=document.getElementById('auth-switch-link'), authTitle=document.getElementById('auth-title'), authSwitchText=document.getElementById('auth-switch-text'), loginError=document.getElementById('login-error'), currentUserDisplay=document.getElementById('current-user-display'), logoutBtn=document.getElementById('logout-btn'), spinner=document.querySelector('#workouts-list .spinner'), appContainer=document.getElementById('app-container'), navItems=document.querySelectorAll('.nav-item'), newWorkoutBtn=document.getElementById('new-workout-btn'), saveWorkoutBtn=document.getElementById('save-workout-btn'), cancelNewWorkoutBtn=document.getElementById('cancel-new-workout-btn'), addExerciseBtn=document.getElementById('add-exercise-btn'), exercisesContainer=document.getElementById('exercises-container'), workoutsList=document.getElementById('workouts-list'), backToHomeBtns=document.querySelectorAll('.back-to-home-btn'), deleteWorkoutBtn=document.getElementById('delete-workout-btn'), satisfactionRange=document.getElementById('satisfaction'), satisfactionValue=document.querySelector('.satisfaction-value'), emptyWorkoutMessage=document.getElementById('empty-workout-message'), workoutDateInput=document.getElementById('workout-date'), prevExerciseBtn=document.getElementById('prev-exercise-btn'), nextExerciseBtn=document.getElementById('next-exercise-btn'), currentExerciseIndicator=document.getElementById('current-exercise-indicator'), workoutTypeIndicator=document.getElementById('workout-type-indicator'), detailWorkoutType=document.getElementById('detail-workout-type'), manageTypesBtn=document.getElementById('manage-types-btn'), manageTypesPage=document.getElementById('manage-types-page'), workoutTypesList=document.getElementById('workout-types-list'), emptyTypesMessage=document.getElementById('empty-types-message'), typesSpinner=document.getElementById('types-spinner'), addTypeForm=document.getElementById('add-type-form'), newTypeNameInput=document.getElementById('new-type-name'), addTypeError=document.getElementById('add-type-error'), selectWorkoutTypePage=document.getElementById('select-workout-type-page'), selectWorkoutTypeDropdown=document.getElementById('select-workout-type'), startStructuredWorkoutBtn=document.getElementById('start-structured-workout-btn'), startFreeWorkoutBtn=document.getElementById('start-free-workout-btn');
        const typeTrendsContainer = document.getElementById('type-trends-container'); // Pour Stats
        const noTrendsMessage = document.getElementById('no-trends-message');
        const trendsSpinner = document.getElementById('trends-spinner');
        let isLoginMode = true;

        // ===========================================
        // --- Définition Fonctions ---
        // ===========================================

        function initAuthListener() { /* ... */ if (!auth) return; auth.onAuthStateChanged(user => { console.log("Auth state:", user ? user.uid : 'null'); if (user) { currentFirebaseUser = user; showApp(); } else { currentFirebaseUser = null; workouts = []; userWorkoutTypes = []; renderWorkoutsList(); renderWorkoutTypesList(); showLoginPage(); } }); }
        function showLoginPage() { /* ... */ if(loginPage) loginPage.style.display = 'block'; if(mainAppContent) mainAppContent.style.display = 'none'; }
        function showApp() { /* ... */ if (!currentFirebaseUser || !mainAppContent) return; console.log("Affichage App"); if(loginPage) loginPage.style.display = 'none'; mainAppContent.style.display = 'block'; if(currentUserDisplay) currentUserDisplay.textContent = currentFirebaseUser.email; setTodayDate(); loadWorkouts(); loadWorkoutTypes(); showPage('home-page'); }
        function handleAuthAction(event) { /* ... */ if(!auth) return; event.preventDefault(); const email = authEmailInput.value; const password = authPasswordInput.value; loginError.textContent = ''; if (!email || !password) { loginError.textContent = 'Email/Pass requis.'; return; } authActionButton.disabled = true; authActionButton.textContent = 'Chargement...'; if (isLoginMode) { auth.signInWithEmailAndPassword(email, password).catch(handleAuthError).finally(() => { authActionButton.disabled = false; authActionButton.textContent = 'Se Connecter'; }); } else { auth.createUserWithEmailAndPassword(email, password).catch(handleAuthError).finally(() => { authActionButton.disabled = false; authSwitchMode(); authActionButton.textContent = 'S\'inscrire'; }); } }
        function handleLogout() { /* ... */ if(!auth) return; console.log("Déconnexion..."); auth.signOut().catch(handleAuthError); }
        function authSwitchMode() { /* ... */ isLoginMode = !isLoginMode; loginError.textContent = ''; authTitle.textContent=isLoginMode?'Connexion':'Inscription'; authActionButton.textContent=isLoginMode?'Se Connecter':'S\'inscrire'; authSwitchText.textContent=isLoginMode?'Pas de compte ?':'Déjà un compte ?'; authSwitchLink.textContent=isLoginMode?'Inscrivez-vous':'Connectez-vous'; }
        function handleAuthError(error) { /* ... */ console.error("Erreur Auth:", error); loginError.textContent = getAuthErrorMessage(error); }
        function getAuthErrorMessage(error) { /* ... */ switch (error.code) { case 'auth/invalid-email': return 'Email invalide.'; case 'auth/user-disabled': return 'Compte désactivé.'; case 'auth/user-not-found': return 'Utilisateur inconnu.'; case 'auth/wrong-password': return 'Mot de passe incorrect.'; case 'auth/email-already-in-use': return 'Email déjà utilisé.'; case 'auth/weak-password': return 'Mot de passe trop faible.'; default: return 'Erreur authentification.'; } }
        function loadWorkoutTypes() { /* ... */ if (!currentFirebaseUser || !db) return; const userId = currentFirebaseUser.uid; console.log("Chargement types..."); userWorkoutTypes = []; if (typesSpinner) typesSpinner.classList.remove('hidden'); db.collection('workoutTypes').where('userId', '==', userId).orderBy('name').get().then(snapshot => { snapshot.forEach(doc => userWorkoutTypes.push({ id: doc.id, ...doc.data() })); console.log("Types chargés:", userWorkoutTypes); renderWorkoutTypesList(); populateWorkoutTypeSelector(); }).catch(handleFirestoreError).finally(() => { if (typesSpinner) typesSpinner.classList.add('hidden'); }); }
        function renderWorkoutTypesList() { /* ... */ if (!workoutTypesList) return; workoutTypesList.innerHTML = ''; if (userWorkoutTypes.length === 0) { if(emptyTypesMessage) emptyTypesMessage.classList.remove('hidden'); } else { if(emptyTypesMessage) emptyTypesMessage.classList.add('hidden'); userWorkoutTypes.forEach(type => { const li = document.createElement('li'); li.textContent = type.name; workoutTypesList.appendChild(li); }); } }
        function handleAddWorkoutType(event) { /* ... */ event.preventDefault(); if (!currentFirebaseUser || !newTypeNameInput || !db) return; const typeName = newTypeNameInput.value.trim(); addTypeError.textContent = ''; if (!typeName) { addTypeError.textContent = "Nom vide."; return; } if (userWorkoutTypes.some(t => t.name.toLowerCase() === typeName.toLowerCase())) { addTypeError.textContent = "Type existe déjà."; return; } console.log("Ajout type:", typeName); const typeData = { userId: currentFirebaseUser.uid, name: typeName }; db.collection('workoutTypes').add(typeData).then(() => { console.log("Type ajouté"); newTypeNameInput.value = ''; loadWorkoutTypes(); }).catch(handleFirestoreError); }
        function populateWorkoutTypeSelector() { /* ... */ if (!selectWorkoutTypeDropdown) return; selectWorkoutTypeDropdown.innerHTML = '<option value="">-- Sélectionner --</option>'; userWorkoutTypes.forEach(type => { const option = document.createElement('option'); option.value = type.name; option.textContent = type.name; selectWorkoutTypeDropdown.appendChild(option); }); updateStartStructuredBtnState(); }
        function updateStartStructuredBtnState() { /* ... */ if (!selectWorkoutTypeDropdown || !startStructuredWorkoutBtn) return; startStructuredWorkoutBtn.disabled = !selectWorkoutTypeDropdown.value; }
        function loadWorkouts() { /* ... */ if (!currentFirebaseUser || !db) { console.log("Chargement séances annulé."); workouts = []; renderWorkoutsList(); showPage('home-page'); return; } const userId = currentFirebaseUser.uid; console.log(`Chargement séances ${userId}...`); if (spinner) spinner.classList.remove('hidden'); if(emptyWorkoutMessage) emptyWorkoutMessage.classList.add('hidden'); if(workoutsList) workoutsList.innerHTML = ''; workouts = []; db.collection('workouts').where('userId', '==', userId).orderBy('date', 'desc').get().then((querySnapshot) => { console.log(`${querySnapshot.size} séances trouvées.`); querySnapshot.forEach((doc) => { const workoutData = doc.data(); workoutData.firestoreId = doc.id; workouts.push(workoutData); }); renderWorkoutsList(); /* showPage est appelé depuis renderWorkoutsList ou updateStats maintenant */ updateStats(); // Mettre à jour les stats après chargement }).catch(handleFirestoreError).finally(() => { if (spinner) spinner.classList.add('hidden'); }); }
        function saveWorkout() { /* ... */ if (!currentFirebaseUser || !db) { alert("Non connecté."); return; } const userId = currentFirebaseUser.uid; workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise')); const workoutNameInput = document.getElementById('workout-name'); const workoutName = workoutNameInput ? workoutNameInput.value.trim() : ''; const workoutDate = workoutDateInput.value; const workoutDuration = parseInt(document.getElementById('workout-duration').value) || 0; const satisfaction = parseInt(satisfactionRange.value); if (!selectedWorkoutTypeName) { alert("Type séance non défini."); return; } if (!workoutDate || workoutDuration <= 0) { alert("Données invalides."); return; } const exerciseElements = workoutExercisesForm; const exercises = []; if (exerciseElements.length === 0) { alert("Ajoutez exercices."); return; } let validationError = null; /* ... Validation ... */ 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 exo #${index + 1}.`; if(nameInput) nameInput.focus(); return; } const series = []; const seriesElements = exerciseEl.querySelectorAll('.series'); if (seriesElements.length === 0) { validationError = `"${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: "${exerciseName}".`; if(repsInput) repsInput.focus(); return; } if (weight < 0) { validationError = `Charge invalide: "${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 finalWorkoutName = workoutName || selectedWorkoutTypeName; const workout = { id: currentWorkoutId || `workout-${Date.now()}`, userId: userId, workoutTypeName: selectedWorkoutTypeName, name: finalWorkoutName, date: workoutDate, duration: workoutDuration, exercises: exercises, totalTonnage: totalTonnage, satisfaction: satisfaction }; console.log("Sauvegarde:", workout); saveWorkoutBtn.disabled = true; saveWorkoutBtn.textContent = 'Sauvegarde...'; db.collection('workouts').doc(workout.id).set(workout).then(() => { console.log("Sauvegardé:", 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(handleFirestoreError).finally(() => { saveWorkoutBtn.disabled = false; saveWorkoutBtn.textContent = 'Enregistrer Séance'; }); }
        function deleteWorkout() { /* ... */ if (!currentFirebaseUser || !currentWorkoutId || !db) return; const workoutToDelete = workouts.find(w => w.id === currentWorkoutId); if (!workoutToDelete) return; const confirmDelete = confirm(`Supprimer "${workoutToDelete.name}"?`); if (!confirmDelete) return; console.log("Suppression:", currentWorkoutId); deleteWorkoutBtn.disabled = true; deleteWorkoutBtn.textContent = 'Suppression...'; db.collection('workouts').doc(currentWorkoutId).delete().then(() => { console.log("Supprimé:", currentWorkoutId); workouts = workouts.filter(w => w.id !== currentWorkoutId); currentWorkoutId = null; showPage('home-page'); renderWorkoutsList(); }).catch(handleFirestoreError).finally(() => { deleteWorkoutBtn.disabled = false; deleteWorkoutBtn.textContent = 'Supprimer'; }); }
        function setTodayDate() { /* ... */ if(workoutDateInput) try { workoutDateInput.value = new Date().toISOString().split('T')[0]; } catch(e){ console.error("Erreur date:", e); }}
        function showPage(pageId) { /* ... */ console.log(`Affichage page: ${pageId}`); if (!currentFirebaseUser && pageId !== 'login-page') { showLoginPage(); return; } document.querySelectorAll('#app-container > div').forEach(page => page.classList.remove('active')); const pageToShow = document.getElementById(pageId); if (pageToShow) { pageToShow.classList.add('active'); if (pageId === 'new-workout-page') { triggerFlameAnimation(); renderActiveExerciseForm(); updateWorkoutTypeIndicator(); } if (pageId === 'manage-types-page') { loadWorkoutTypes(); } if (pageId === 'select-workout-type-page') { populateWorkoutTypeSelector(); } if (pageId === 'stats-page') { updateStats(); /* Recalculer les stats quand on affiche la page */ } } else { console.error(`Page ID "${pageId}" non trouvée.`); document.getElementById('home-page').classList.add('active'); pageId = 'home-page'; } navItems.forEach(item => { item.classList.remove('active'); }); const activeNavItem = document.querySelector(`.nav-item[data-page="${pageId === 'stats-page' ? 'stats-page' : 'home-page'}"]`); if(activeNavItem) activeNavItem.classList.add('active'); }
        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(typeName = "Libre") { /* ... */ console.log("Nettoyage form pour type:", typeName); if (!currentFirebaseUser) return; selectedWorkoutTypeName = typeName; const workoutNameInput = document.getElementById('workout-name'); if(workoutNameInput) workoutNameInput.value = (typeName === "Libre" ? "" : typeName); if(workoutDateInput) setTodayDate(); if(document.getElementById('workout-duration')) document.getElementById('workout-duration').value = ''; if(exercisesContainer) exercisesContainer.innerHTML = ''; workoutExercisesForm = []; if(satisfactionRange) satisfactionRange.value = 75; if(satisfactionValue) satisfactionValue.textContent = '75%'; currentWorkoutId = null; currentExerciseIndex = 0; addExercise(false); updateWorkoutTypeIndicator(); renderActiveExerciseForm(); }
        function updateWorkoutTypeIndicator() { /* ... */ if (!workoutTypeIndicator) return; if (selectedWorkoutTypeName && selectedWorkoutTypeName !== "Libre") { workoutTypeIndicator.textContent = selectedWorkoutTypeName; workoutTypeIndicator.classList.remove('hidden'); } else { workoutTypeIndicator.classList.add('hidden'); } }
        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); const typeBadge = workout.workoutTypeName && workout.workoutTypeName !== "Libre" ? `<span class="badge type-badge">${workout.workoutTypeName}</span>` : ''; workoutDiv.innerHTML = `<div class="workout-header"><h3 style="margin-bottom: 0.5rem;">${workout.name} ${typeBadge}</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) { showPage('home-page'); return; } if(detailWorkoutType) { if (workout.workoutTypeName && workout.workoutTypeName !== "Libre") { detailWorkoutType.textContent = workout.workoutTypeName; detailWorkoutType.classList.remove('hidden'); } else detailWorkoutType.classList.add('hidden'); } if(document.getElementById('detail-workout-name')) document.getElementById('detail-workout-name').textContent = workout.name; if(document.getElementById('detail-date')) document.getElementById('detail-date').textContent = new Date(workout.date).toLocaleDateString('fr-FR'); if(document.getElementById('detail-duration')) document.getElementById('detail-duration').textContent = workout.duration; if(document.getElementById('detail-tonnage')) document.getElementById('detail-tonnage').textContent = workout.totalTonnage.toFixed(1); if(document.getElementById('detail-satisfaction')) document.getElementById('detail-satisfaction').textContent = `${workout.satisfaction}%`; if(document.getElementById('detail-exercises-count')) document.getElementById('detail-exercises-count').textContent = workout.exercises.length; const detailExercisesContainer = document.getElementById('detail-exercises-container'); if(detailExercisesContainer) { 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'); }

        // MODIFIÉ pour calculer et rendre les tendances par type
        function updateStats() {
            if (!currentFirebaseUser) return;
            const workoutCount = workouts.length;
            const statsWorkoutCountEl = document.getElementById('stats-workout-count');
            const statsAvgTonnageEl = document.getElementById('stats-avg-tonnage');
            const statsAvgSatisfactionEl = document.getElementById('stats-avg-satisfaction');

            // Calcul stats globales (inchangé)
            if (statsWorkoutCountEl) statsWorkoutCountEl.textContent = workoutCount;
            if (workoutCount === 0) {
                if(statsAvgTonnageEl) statsAvgTonnageEl.textContent = '0';
                if(statsAvgSatisfactionEl) statsAvgSatisfactionEl.textContent = '0%';
                renderTypeTrends({}); // Afficher message "pas de données" pour tendances
                return;
            }
            const totalTonnageAll = workouts.reduce((sum, workout) => sum + (workout.totalTonnage || 0), 0);
            const avgTonnage = totalTonnageAll / workoutCount;
            if(statsAvgTonnageEl) statsAvgTonnageEl.textContent = avgTonnage.toFixed(1);
            const totalSatisfaction = workouts.reduce((sum, workout) => sum + (workout.satisfaction || 0), 0);
            const avgSatisfaction = totalSatisfaction / workoutCount;
             if(statsAvgSatisfactionEl) statsAvgSatisfactionEl.textContent = `${Math.round(avgSatisfaction)}%`;

            // --- Calcul Tendances par Type ---
            console.log("Calcul des tendances par type...");
            const trendsData = {};
            // 1. Filtrer les séances structurées
            const structuredWorkouts = workouts.filter(w => w.workoutTypeName && w.workoutTypeName !== "Libre");

            // 2. Grouper par type
            const groupedByType = structuredWorkouts.reduce((acc, workout) => {
                const type = workout.workoutTypeName;
                if (!acc[type]) {
                    acc[type] = [];
                }
                acc[type].push(workout);
                return acc;
            }, {});
            console.log("Séances groupées par type:", groupedByType);

            // 3. Pour chaque type, extraire les 3 dernières séances (tonnage)
            for (const typeName in groupedByType) {
                // Trier les séances de ce type par date (plus récentes d'abord)
                const sessionsOfType = groupedByType[typeName].sort((a, b) => new Date(b.date) - new Date(a.date));
                // Prendre les 3 premières (ou moins si pas assez)
                const lastSessions = sessionsOfType.slice(0, 3).map(s => ({
                     date: s.date, // Garder la date
                     tonnage: s.totalTonnage // Garder le tonnage
                 }));
                 // Inverser pour affichage chronologique (optionnel mais plus logique)
                 trendsData[typeName] = lastSessions.reverse();
            }
            console.log("Données de tendance calculées:", trendsData);

            // 4. Rendre les tendances
            renderTypeTrends(trendsData);
        }

         // NOUVELLE fonction pour afficher les tendances
         function renderTypeTrends(trends) {
             if (!typeTrendsContainer || !noTrendsMessage) return;

             typeTrendsContainer.innerHTML = ''; // Vider le conteneur
             const trendTypes = Object.keys(trends);

             if (trendTypes.length === 0) {
                 noTrendsMessage.classList.remove('hidden');
             } else {
                 noTrendsMessage.classList.add('hidden');
                 trendTypes.sort().forEach(typeName => { // Trier les types alphabétiquement
                     const typeData = trends[typeName];
                     if (typeData.length === 0) return; // Ne pas afficher si pas de données pour ce type

                     const card = document.createElement('div');
                     card.className = 'card type-trend-card';

                     let listItems = '';
                     typeData.forEach(session => {
                         const formattedDate = new Date(session.date).toLocaleDateString('fr-FR', { day: '2-digit', month: 'short' });
                         listItems += `<li><span>${formattedDate}</span> <strong>${session.tonnage.toFixed(1)} kg</strong></li>`;
                     });

                     card.innerHTML = `
                         <h4>${typeName} (Dernières Séances)</h4>
                         <ul>${listItems}</ul>
                     `;
                     typeTrendsContainer.appendChild(card);
                 });
             }
         }

        function handleFirestoreError(error) { console.error("Erreur Firestore:", error); alert("Erreur base de données."); }

        // --- ÉCOUTEURS D'ÉVÉNEMENTS (Attachés ici) ---
        function initEventListeners() {
             console.log("initEventListeners: Attachement...");
             if (loginForm) loginForm.addEventListener('submit', handleAuthAction); else console.error("!loginForm");
             if (authSwitchLink) authSwitchLink.addEventListener('click', authSwitchMode); else console.error("!authSwitchLink");
             if (logoutBtn) logoutBtn.addEventListener('click', handleLogout); else console.error("!logoutBtn");
             navItems.forEach((item, index) => { if(item) item.addEventListener('click', (e) => { e.preventDefault(); if (!currentFirebaseUser) return; const targetPageId = item.getAttribute('data-page'); showPage(targetPageId); }); else console.error(`!navItem #${index}`); });
             if (newWorkoutBtn) newWorkoutBtn.addEventListener('click', () => { if (!currentFirebaseUser) return; showPage('select-workout-type-page'); }); else console.error("!newWorkoutBtn");
             if (manageTypesBtn) manageTypesBtn.addEventListener('click', () => showPage('manage-types-page')); else console.error("!manageTypesBtn");
             if (addTypeForm) addTypeForm.addEventListener('submit', handleAddWorkoutType); else console.error("!addTypeForm");
             if (selectWorkoutTypeDropdown) selectWorkoutTypeDropdown.addEventListener('change', updateStartStructuredBtnState); else console.error("!selectWorkoutTypeDropdown");
             if (startStructuredWorkoutBtn) startStructuredWorkoutBtn.addEventListener('click', () => { if(selectWorkoutTypeDropdown) { const type = selectWorkoutTypeDropdown.value; if(type) { clearNewWorkoutForm(type); showPage('new-workout-page'); } } }); else console.error("!startStructuredWorkoutBtn");
             if (startFreeWorkoutBtn) startFreeWorkoutBtn.addEventListener('click', () => { clearNewWorkoutForm("Libre"); showPage('new-workout-page'); }); else console.error("!startFreeWorkoutBtn");
             backToHomeBtns.forEach(btn => { if(btn) btn.addEventListener('click', () => showPage('home-page')); else console.error("!backToHomeBtn"); });
             if (cancelNewWorkoutBtn) cancelNewWorkoutBtn.addEventListener('click', () => showPage('home-page')); else console.error("!cancelNewWorkoutBtn");
             if (saveWorkoutBtn) saveWorkoutBtn.addEventListener('click', saveWorkout); else console.error("!saveWorkoutBtn");
             if (addExerciseBtn) addExerciseBtn.addEventListener('click', handleAddNewExercise); else console.error("!addExerciseBtn");
             if (prevExerciseBtn) prevExerciseBtn.addEventListener('click', navigateExerciseForm.bind(null, -1)); else console.error("!prevExerciseBtn");
             if (nextExerciseBtn) nextExerciseBtn.addEventListener('click', navigateExerciseForm.bind(null, 1)); else console.error("!nextExerciseBtn");
             if (deleteWorkoutBtn) deleteWorkoutBtn.addEventListener('click', deleteWorkout); else console.error("!deleteWorkoutBtn");
             if (satisfactionRange) satisfactionRange.addEventListener('input', () => { if(satisfactionValue) satisfactionValue.textContent = `${satisfactionRange.value}%`; }); else console.error("!satisfactionRange");
             console.log("initEventListeners: Fin attachement.");
         }

        // ==================================================
        // --- FIN DES DÉFINITIONS DE FONCTIONS ---
        // ==================================================

        // --- INITIALISATION ---
        if (auth) { initAuthListener(); } else { console.error("Firebase Auth non prêt!"); }
        initEventListeners();

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