BitDown commited on
Commit
1bef68b
·
verified ·
1 Parent(s): d0a3ba3

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +14 -687
index.html CHANGED
@@ -1,101 +1,6 @@
1
- <!DOCTYPE html>
2
- <html lang="fr">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>LiftTrack - Suivi Musculation Multi-Utilisateurs</title>
7
- <style>
8
- /* --- Styles existants (raccourcis pour la lisibilité) --- */
9
- :root {
10
- --bg-dark: #121212;
11
- --bg-card: #1e1e1e;
12
- --text-light: #e0e0e0;
13
- --accent: #4CAF50;
14
- --accent-dark: #3a8a3d;
15
- --danger: #f44336;
16
- }
17
- * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
18
- body { background-color: var(--bg-dark); color: var(--text-light); min-height: 100vh; padding-bottom: 80px; }
19
- .container { width: 100%; max-width: 800px; margin: 0 auto; padding: 1rem; }
20
- header { padding: 1rem 0; text-align: center; border-bottom: 1px solid #333; margin-bottom: 1rem; }
21
- h1, h2, h3 { color: var(--accent); }
22
- .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; }
23
- .btn:hover { background-color: var(--accent-dark); }
24
- .btn-outline { background-color: transparent; color: var(--accent); border: 1px solid var(--accent); }
25
- .btn-danger { background-color: var(--danger); }
26
- 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); }
27
- input[type="checkbox"] { width: auto; margin-right: 0.5rem; }
28
- .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); }
29
- .form-group { margin-bottom: 1rem; }
30
- .form-row { display: flex; gap: 0.5rem; margin-bottom: 0.5rem; }
31
- .form-row > * { flex: 1; margin-bottom: 0; }
32
- label { display: block; margin-bottom: 0.3rem; color: #bbb; }
33
- .exercise { border-left: 3px solid var(--accent); padding-left: 1rem; margin-bottom: 1.5rem; }
34
- .exercise-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; }
35
- .series-container { margin-left: 0.5rem; margin-top: 0.5rem; }
36
- .series { background-color: #252525; padding: 0.7rem; border-radius: 4px; margin-bottom: 0.5rem; }
37
- .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); }
38
- .nav-item { text-align: center; color: #888; text-decoration: none; font-size: 0.85rem; transition: color 0.2s; }
39
- .nav-item.active { color: var(--accent); }
40
- .nav-icon { font-size: 1.4rem; margin-bottom: 0.2rem; }
41
- .workout-card { border-left: 3px solid var(--accent); cursor: pointer; transition: transform 0.2s; }
42
- .workout-card:hover { transform: translateX(5px); }
43
- .workout-header { display: flex; justify-content: space-between; }
44
- .stat-card { text-align: center; padding: 1rem; }
45
- .stat-value { font-size: 1.8rem; color: var(--accent); font-weight: bold; }
46
- .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 1rem; }
47
- .hidden { display: none; }
48
- #app-container > div:not(.active) { display: none; } /* Hide inactive pages */
49
- #login-page { display: block; } /* Show login initially */
50
- #main-app-content { display: none; } /* Hide main app initially */
51
- .flex-between { display: flex; justify-content: space-between; align-items: center; }
52
- .badge { background-color: var(--accent); color: white; padding: 0.2rem 0.5rem; border-radius: 10px; font-size: 0.8rem; }
53
- .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; }
54
- @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
55
- .exercise-summary { margin: 0.3rem 0; padding: 0.3rem 0; border-bottom: 1px solid #333; }
56
- .satisfaction { display: flex; align-items: center; justify-content: center; flex-direction: column; margin-top: 1rem; }
57
- .satisfaction-value { font-size: 2rem; color: var(--accent); margin-top: 0.5rem; }
58
- @media (max-width: 600px) { .form-row { flex-direction: column; gap: 0; } .container { padding: 0.5rem; } h1 { font-size: 1.5rem; } }
59
- /* Styles pour la page de connexion */
60
- #login-page .card { max-width: 400px; margin: 2rem auto; }
61
- #login-page h2 { text-align: center; margin-bottom: 1.5rem; }
62
- #login-error { color: var(--danger); text-align: center; margin-top: 1rem; display: none; }
63
- .user-info { text-align: right; margin-bottom: 1rem; font-size: 0.9rem; color: #bbb;}
64
- .user-info button { margin-left: 0.5rem; padding: 0.2rem 0.5rem; font-size: 0.8rem; }
65
- </style>
66
- </head>
67
- <body>
68
- <div class="container">
69
- <header>
70
- <h1>LiftTrack</h1>
71
- <p>Suivi de vos séances de musculation</p>
72
- </header>
73
-
74
- <!-- Écran de Connexion -->
75
- <div id="login-page">
76
- <div class="card">
77
- <h2>Accès Utilisateur</h2>
78
- <div class="form-group">
79
- <label for="username">Nom d'utilisateur</label>
80
- <input type="text" id="username" placeholder="Entrez votre nom ou pseudo">
81
- </div>
82
- <button id="login-btn" class="btn" style="width: 100%;">Accéder / Créer</button>
83
- <p id="login-error">Nom d'utilisateur invalide.</p>
84
- <p style="font-size: 0.8rem; color: #888; text-align: center; margin-top: 1rem;">
85
- Entrez un nom pour accéder à vos données ou créer un nouvel espace si le nom n'existe pas.
86
- </p>
87
- </div>
88
- </div>
89
-
90
- <!-- Contenu Principal de l'Application (initiallement caché) -->
91
- <div id="main-app-content">
92
- <div class="user-info">
93
- Connecté en tant que: <strong id="current-user-display"></strong>
94
- <button id="logout-btn" class="btn btn-outline">Changer d'utilisateur</button>
95
- </div>
96
-
97
  <div id="app-container">
98
  <!-- Page Accueil / Liste Séances -->
 
99
  <div id="home-page" class="active">
100
  <div class="flex-between">
101
  <h2>Mes séances</h2>
@@ -110,7 +15,8 @@
110
  </div>
111
 
112
  <!-- Page Nouvelle Séance -->
113
- <div id="new-workout-page" class="hidden">
 
114
  <div class="flex-between">
115
  <h2>Nouvelle séance</h2>
116
  <div> <!-- Conteneur pour les boutons -->
@@ -118,7 +24,8 @@
118
  <button id="save-workout-btn" class="btn">Enregistrer</button>
119
  </div>
120
  </div>
121
- <div class="card">
 
122
  <div class="form-group">
123
  <label for="workout-name">Nom de la séance</label>
124
  <input type="text" id="workout-name" placeholder="Ex: Push, Legs, Full Body...">
@@ -150,12 +57,14 @@
150
  </div>
151
 
152
  <!-- Page Détail Séance -->
153
- <div id="workout-details-page" class="hidden">
 
154
  <div class="flex-between">
155
  <h2 id="detail-workout-name">Détail Séance</h2>
156
  <button id="back-to-home" class="btn btn-outline">Retour</button>
157
  </div>
158
- <div class="card">
 
159
  <div class="workout-details-info">
160
  <div class="form-row">
161
  <p><strong>Date:</strong> <span id="detail-date"></span></p>
@@ -183,9 +92,11 @@
183
  </div>
184
 
185
  <!-- Page Statistiques -->
186
- <div id="stats-page" class="hidden">
 
187
  <h2>Statistiques</h2>
188
- <div class="stats-grid">
 
189
  <div class="card stat-card">
190
  <div class="stat-value" id="stats-workout-count">0</div>
191
  <div>Séances Totales</div>
@@ -206,588 +117,4 @@
206
  </p>
207
  </div>
208
  </div>
209
- </div>
210
-
211
- <!-- Menu Navigation Bas -->
212
- <nav class="nav-bottom">
213
- <a href="#" class="nav-item active" data-page="home-page">
214
- <div class="nav-icon">📋</div>
215
- <div>Séances</div>
216
- </a>
217
- <a href="#" class="nav-item" data-page="stats-page">
218
- <div class="nav-icon">📊</div>
219
- <div>Stats</div>
220
- </a>
221
- </nav>
222
- </div>
223
- </div>
224
-
225
- <script>
226
- // --- State Variables ---
227
- let workouts = []; // Workouts for the current user
228
- let currentUser = null; // Stores the logged-in username
229
- let currentWorkoutId = null; // For editing/deleting specific workout
230
-
231
- // --- DOM Elements ---
232
- const loginPage = document.getElementById('login-page');
233
- const mainAppContent = document.getElementById('main-app-content');
234
- const usernameInput = document.getElementById('username');
235
- const loginBtn = document.getElementById('login-btn');
236
- const loginError = document.getElementById('login-error');
237
- const currentUserDisplay = document.getElementById('current-user-display');
238
- const logoutBtn = document.getElementById('logout-btn');
239
-
240
- const appContainer = document.getElementById('app-container');
241
- const navItems = document.querySelectorAll('.nav-item');
242
- const newWorkoutBtn = document.getElementById('new-workout-btn');
243
- const saveWorkoutBtn = document.getElementById('save-workout-btn');
244
- const cancelNewWorkoutBtn = document.getElementById('cancel-new-workout-btn'); // Added cancel button
245
- const addExerciseBtn = document.getElementById('add-exercise-btn');
246
- const exercisesContainer = document.getElementById('exercises-container');
247
- const workoutsList = document.getElementById('workouts-list');
248
- const backToHomeBtn = document.getElementById('back-to-home');
249
- const deleteWorkoutBtn = document.getElementById('delete-workout-btn');
250
- const satisfactionRange = document.getElementById('satisfaction');
251
- const satisfactionValue = document.querySelector('.satisfaction-value');
252
- const emptyWorkoutMessage = document.getElementById('empty-workout-message');
253
- const workoutDateInput = document.getElementById('workout-date'); // For setting date
254
-
255
-
256
- // --- Initialization ---
257
- document.addEventListener('DOMContentLoaded', () => {
258
- // Check if a user was previously logged in (in this browser session)
259
- // Note: Using sessionStorage means they need to "log in" each time they open the tab/browser.
260
- // You could use localStorage here too for longer persistence, but it's less secure if the computer is shared.
261
- const rememberedUser = sessionStorage.getItem('liftTrackCurrentUser');
262
- if (rememberedUser) {
263
- loginUser(rememberedUser);
264
- } else {
265
- showLoginPage();
266
- }
267
- initEventListeners();
268
- // Set today's date only if the main app is potentially visible
269
- if (currentUser) {
270
- setTodayDate();
271
- }
272
- });
273
-
274
- // --- Authentication Functions ---
275
-
276
- function showLoginPage() {
277
- loginPage.style.display = 'block';
278
- mainAppContent.style.display = 'none';
279
- loginError.style.display = 'none'; // Hide error on show
280
- usernameInput.value = ''; // Clear input
281
- }
282
-
283
- function showApp() {
284
- loginPage.style.display = 'none';
285
- mainAppContent.style.display = 'block';
286
- currentUserDisplay.textContent = currentUser;
287
- setTodayDate(); // Set date when app becomes visible
288
- loadWorkouts(); // Load data for the current user
289
- renderWorkoutsList(); // Display workouts
290
- showPage('home-page'); // Default to home page
291
- updateStats(); // Update stats for the logged-in user
292
- }
293
-
294
- function handleLogin() {
295
- const username = usernameInput.value.trim();
296
- if (username) {
297
- loginUser(username);
298
- } else {
299
- loginError.textContent = "Veuillez entrer un nom d'utilisateur.";
300
- loginError.style.display = 'block';
301
- }
302
- }
303
-
304
- function loginUser(username) {
305
- currentUser = username;
306
- sessionStorage.setItem('liftTrackCurrentUser', currentUser); // Remember user for the session
307
- showApp();
308
- }
309
-
310
- function handleLogout() {
311
- currentUser = null;
312
- sessionStorage.removeItem('liftTrackCurrentUser'); // Forget user
313
- workouts = []; // Clear current workout data from memory
314
- showLoginPage();
315
- }
316
-
317
- // --- Data Persistence Functions (User-Specific) ---
318
-
319
- function getStorageKey() {
320
- if (!currentUser) return null; // Should not happen if logged in
321
- // IMPORTANT: Make the key safe for localStorage (no weird chars)
322
- const safeUsername = currentUser.replace(/[^a-zA-Z0-9_-]/g, '_');
323
- return `liftTrackData_${safeUsername}`;
324
- }
325
-
326
- function loadWorkouts() {
327
- const storageKey = getStorageKey();
328
- if (!storageKey) {
329
- workouts = [];
330
- return;
331
- }
332
- const savedData = localStorage.getItem(storageKey);
333
- workouts = savedData ? JSON.parse(savedData) : [];
334
- console.log(`Loaded ${workouts.length} workouts for user ${currentUser}`);
335
- }
336
-
337
- function saveWorkouts() {
338
- const storageKey = getStorageKey();
339
- if (!storageKey) {
340
- console.error("Cannot save, no user logged in.");
341
- return;
342
- }
343
- localStorage.setItem(storageKey, JSON.stringify(workouts));
344
- console.log(`Saved ${workouts.length} workouts for user ${currentUser}`);
345
- }
346
-
347
- // --- Event Listeners ---
348
- function initEventListeners() {
349
- loginBtn.addEventListener('click', handleLogin);
350
- logoutBtn.addEventListener('click', handleLogout);
351
-
352
- // Prevent form submission if username input is focused and Enter is pressed
353
- usernameInput.addEventListener('keypress', (e) => {
354
- if (e.key === 'Enter') {
355
- e.preventDefault(); // Stop default form submission behavior
356
- handleLogin(); // Trigger login logic
357
- }
358
- });
359
-
360
- // Navigation (unchanged logic, just needs to be inside init)
361
- navItems.forEach(item => {
362
- item.addEventListener('click', (e) => {
363
- e.preventDefault();
364
- if (!currentUser) return; // Don't navigate if not logged in
365
- const targetPage = item.getAttribute('data-page');
366
- showPage(targetPage); // Use the existing showPage function
367
- if (targetPage === 'stats-page') {
368
- updateStats();
369
- }
370
- });
371
- });
372
-
373
- // New Workout Button (unchanged logic)
374
- newWorkoutBtn.addEventListener('click', () => {
375
- if (!currentUser) return;
376
- showPage('new-workout-page');
377
- clearNewWorkoutForm();
378
- currentWorkoutId = null; // Ensure it's a new workout
379
- });
380
-
381
- // Cancel New Workout Button
382
- cancelNewWorkoutBtn.addEventListener('click', () => {
383
- showPage('home-page'); // Go back home without saving
384
- });
385
-
386
- // Save Workout Button (logic moved to saveWorkout function)
387
- saveWorkoutBtn.addEventListener('click', saveWorkout);
388
-
389
- // Add Exercise Button (logic moved to addExercise function)
390
- addExerciseBtn.addEventListener('click', addExercise);
391
-
392
- // Back to Home Button (unchanged logic)
393
- backToHomeBtn.addEventListener('click', () => {
394
- showPage('home-page');
395
- });
396
-
397
- // Delete Workout Button (logic moved to deleteWorkout function)
398
- deleteWorkoutBtn.addEventListener('click', deleteWorkout);
399
-
400
- // Satisfaction Slider (unchanged logic)
401
- satisfactionRange.addEventListener('input', () => {
402
- satisfactionValue.textContent = `${satisfactionRange.value}%`;
403
- });
404
- }
405
-
406
- // --- Core App Logic (Mostly Unchanged, ensure they run only when logged in) ---
407
-
408
- function setTodayDate() {
409
- // Check if the element exists before setting the value
410
- if(workoutDateInput) {
411
- const today = new Date().toISOString().split('T')[0];
412
- workoutDateInput.value = today;
413
- }
414
- }
415
-
416
- function showPage(pageId) {
417
- // Only change pages if a user is logged in
418
- if (!currentUser) {
419
- showLoginPage(); // Redirect to login if somehow called without user
420
- return;
421
- }
422
-
423
- document.querySelectorAll('#app-container > div').forEach(page => {
424
- page.classList.remove('active'); // Use classList for better practice
425
- });
426
- const pageToShow = document.getElementById(pageId);
427
- if (pageToShow) {
428
- pageToShow.classList.add('active');
429
- } else {
430
- console.error(`Page with ID ${pageId} not found.`);
431
- // Optionally default to home page if target not found
432
- document.getElementById('home-page').classList.add('active');
433
- pageId = 'home-page'; // Update pageId for nav highlighting
434
- }
435
-
436
-
437
- // Update nav highlighting
438
- navItems.forEach(item => {
439
- if (item.getAttribute('data-page') === pageId) {
440
- item.classList.add('active');
441
- } else {
442
- item.classList.remove('active');
443
- }
444
- });
445
- }
446
-
447
-
448
- function addExercise() {
449
- // Check if user is logged in before allowing interaction
450
- if (!currentUser) return;
451
-
452
- const exerciseId = `exercise-${Date.now()}`;
453
- const exerciseDiv = document.createElement('div');
454
- exerciseDiv.className = 'card exercise'; // Added 'card' class for consistency
455
- exerciseDiv.setAttribute('data-exercise-id', exerciseId);
456
-
457
- exerciseDiv.innerHTML = `
458
- <div class="exercise-header">
459
- <input type="text" placeholder="Nom Exercice" class="exercise-name" style="margin-bottom: 0;"> <!-- Remove margin-bottom -->
460
- <button class="btn btn-danger remove-exercise" style="padding: 0.3rem 0.6rem; margin-left: 0.5rem;">×</button> <!-- Use × for 'x' -->
461
- </div>
462
- <div class="form-group" style="margin-top: 0.5rem; margin-bottom: 0.5rem;"> <!-- Reduced margin -->
463
- <label style="display: inline-flex; align-items: center; color: #bbb; font-size: 0.9rem;">
464
- <input type="checkbox" class="unilateral-checkbox" style="margin-bottom: 0; margin-right: 0.3rem;"> Unilatéral
465
- </label>
466
- </div>
467
- <div class="series-container">
468
- <!-- Series added here -->
469
- </div>
470
- <button class="btn btn-outline add-series" style="width: 100%; margin-top: 0.5rem; padding: 0.4rem;">+ Ajouter Série</button>
471
- `;
472
-
473
- exercisesContainer.appendChild(exerciseDiv);
474
-
475
- // Add event listeners for remove/add series (ensure context is correct)
476
- const removeBtn = exerciseDiv.querySelector('.remove-exercise');
477
- removeBtn.addEventListener('click', () => exerciseDiv.remove());
478
-
479
- const addSeriesBtn = exerciseDiv.querySelector('.add-series');
480
- const seriesContainer = exerciseDiv.querySelector('.series-container'); // Get container specific to this exercise
481
- addSeriesBtn.addEventListener('click', () => addSeries(seriesContainer)); // Pass the correct container
482
-
483
- // Add the first series automatically
484
- addSeries(seriesContainer);
485
- }
486
-
487
- function addSeries(container) {
488
- // Check user login
489
- if (!currentUser) return;
490
-
491
- const seriesId = `series-${Date.now()}`;
492
- const seriesDiv = document.createElement('div');
493
- seriesDiv.className = 'series'; // Keep original class
494
- seriesDiv.setAttribute('data-series-id', seriesId);
495
-
496
- seriesDiv.innerHTML = `
497
- <div class="form-row" style="align-items: flex-end;"> <!-- Align items bottom -->
498
- <div class="form-group" style="flex: 1.5;"> <!-- More space for reps -->
499
- <label style="font-size: 0.8rem;">Reps</label>
500
- <input type="number" class="reps" min="1" placeholder="10" style="padding: 0.4rem;">
501
- </div>
502
- <div class="form-group" style="flex: 1.5;"> <!-- More space for weight -->
503
- <label style="font-size: 0.8rem;">Charge (kg)</label>
504
- <input type="number" class="weight" min="0" step="0.1" placeholder="20" style="padding: 0.4rem;">
505
- </div>
506
- <div class="form-group" style="flex: 1; display: flex; align-items: center; padding-bottom: 0.6rem;"> <!-- Align checkbox -->
507
- <label style="display: inline-flex; align-items: center; color: #bbb; font-size: 0.8rem; margin-bottom: 0;">
508
- <input type="checkbox" class="degressive-checkbox" style="margin-bottom: 0; margin-right: 0.3rem;"> Dégressive
509
- </label>
510
- </div>
511
- <button class="btn btn-danger remove-series" style="padding: 0.3rem 0.6rem; margin-bottom: 0.6rem; flex: 0.5;">×</button>
512
- </div>
513
- `;
514
-
515
- container.appendChild(seriesDiv);
516
-
517
- // Add remove listener for this specific series
518
- const removeBtn = seriesDiv.querySelector('.remove-series');
519
- removeBtn.addEventListener('click', () => seriesDiv.remove());
520
- }
521
-
522
-
523
- function saveWorkout() {
524
- // Check user login
525
- if (!currentUser) return;
526
-
527
- // Retrieve base data (unchanged)
528
- const workoutName = document.getElementById('workout-name').value.trim();
529
- const workoutDate = document.getElementById('workout-date').value;
530
- const workoutDuration = parseInt(document.getElementById('workout-duration').value) || 0;
531
- const satisfaction = parseInt(document.getElementById('satisfaction').value);
532
-
533
- // Validation (unchanged)
534
- if (!workoutName) { alert("Nom de séance requis."); return; }
535
- if (!workoutDate) { alert("Date requise."); return; }
536
- if (workoutDuration <= 0) { alert("Durée invalide."); return; }
537
-
538
- // Retrieve exercises (unchanged logic)
539
- const exercises = [];
540
- const exerciseElements = exercisesContainer.querySelectorAll('.exercise');
541
-
542
- if (exerciseElements.length === 0) { alert("Ajoutez au moins un exercice."); return; }
543
-
544
- let validationFailed = false; // Flag to stop processing if an error occurs
545
- exerciseElements.forEach(exerciseEl => {
546
- if (validationFailed) return; // Stop if previous exercise had an error
547
-
548
- const exerciseName = exerciseEl.querySelector('.exercise-name').value.trim();
549
- const isUnilateral = exerciseEl.querySelector('.unilateral-checkbox').checked;
550
-
551
- if (!exerciseName) {
552
- alert("Nom requis pour chaque exercice.");
553
- validationFailed = true;
554
- return;
555
- }
556
-
557
- const series = [];
558
- const seriesElements = exerciseEl.querySelectorAll('.series');
559
-
560
- if (seriesElements.length === 0) {
561
- alert(`Ajoutez au moins une série à l'exercice "${exerciseName}".`);
562
- validationFailed = true;
563
- return;
564
- }
565
-
566
- seriesElements.forEach(seriesEl => {
567
- if (validationFailed) return;
568
-
569
- const reps = parseInt(seriesEl.querySelector('.reps').value) || 0;
570
- const weight = parseFloat(seriesEl.querySelector('.weight').value) || 0;
571
- const isDegressive = seriesEl.querySelector('.degressive-checkbox').checked;
572
-
573
- if (reps <= 0) {
574
- alert(`Nombre de répétitions valide requis pour "${exerciseName}".`);
575
- validationFailed = true;
576
- return;
577
- }
578
- // Allow weight 0 (bodyweight, etc.) but maybe validate if needed
579
- // if (weight < 0) { alert(`Charge valide requise pour "${exerciseName}".`); return; }
580
-
581
- series.push({ reps, weight, isDegressive });
582
- });
583
- if (!validationFailed) {
584
- exercises.push({ name: exerciseName, isUnilateral, series });
585
- }
586
- });
587
-
588
- // Stop if validation failed during exercise/series loop
589
- if (validationFailed) return;
590
-
591
-
592
- // Calculate total tonnage (unchanged logic)
593
- let totalTonnage = 0;
594
- exercises.forEach(exercise => {
595
- exercise.series.forEach(serie => {
596
- const weightFactor = exercise.isUnilateral ? 2 : 1;
597
- totalTonnage += serie.reps * serie.weight * weightFactor;
598
- });
599
- });
600
-
601
- // Create workout object (unchanged logic)
602
- const workout = {
603
- id: currentWorkoutId || `workout-${Date.now()}`, // Use existing ID if editing
604
- name: workoutName,
605
- date: workoutDate,
606
- duration: workoutDuration,
607
- exercises,
608
- totalTonnage,
609
- satisfaction
610
- };
611
-
612
- // Add or update workout in the user's list
613
- const existingIndex = workouts.findIndex(w => w.id === workout.id);
614
- if (existingIndex > -1) {
615
- workouts[existingIndex] = workout; // Update
616
- } else {
617
- workouts.push(workout); // Add new
618
- }
619
-
620
- // Save data for the current user
621
- saveWorkouts();
622
-
623
- // Go back to home page and refresh list
624
- showPage('home-page');
625
- renderWorkoutsList();
626
- }
627
-
628
- function renderWorkoutsList() {
629
- // Check login
630
- if (!currentUser) {
631
- workoutsList.innerHTML = ''; // Clear list if somehow called logged out
632
- emptyWorkoutMessage.classList.remove('hidden');
633
- return;
634
- }
635
-
636
- workoutsList.innerHTML = ''; // Clear previous list
637
-
638
- if (workouts.length === 0) {
639
- emptyWorkoutMessage.classList.remove('hidden');
640
- return; // Stop if no workouts
641
- }
642
-
643
- emptyWorkoutMessage.classList.add('hidden');
644
-
645
- // Sort workouts by date (most recent first) (unchanged)
646
- const sortedWorkouts = [...workouts].sort((a, b) => new Date(b.date) - new Date(a.date));
647
-
648
- // Generate HTML for each workout card (unchanged, but uses user's `workouts` array)
649
- sortedWorkouts.forEach(workout => {
650
- const workoutDate = new Date(workout.date).toLocaleDateString('fr-FR');
651
- const workoutDiv = document.createElement('div');
652
- workoutDiv.className = 'card workout-card'; // Use class for styling/selection
653
- workoutDiv.setAttribute('data-workout-id', workout.id);
654
-
655
- workoutDiv.innerHTML = `
656
- <div class="workout-header">
657
- <h3>${workout.name}</h3>
658
- <div class="badge">${workoutDate}</div>
659
- </div>
660
- <div class="workout-details" style="margin-top: 0.5rem; font-size: 0.9rem; color: #ccc;">
661
- <p><strong>Durée:</strong> ${workout.duration} min | <strong>Exercices:</strong> ${workout.exercises.length}</p>
662
- <p><strong>Tonnage:</strong> ${workout.totalTonnage.toFixed(1)} kg | <strong>Satisfaction:</strong> ${workout.satisfaction}%</p>
663
- </div>
664
- `;
665
-
666
- // Add listener to show details on click
667
- workoutDiv.addEventListener('click', () => displayWorkoutDetails(workout.id));
668
-
669
- workoutsList.appendChild(workoutDiv);
670
- });
671
-
672
- updateStats(); // Update stats after rendering list
673
- }
674
-
675
- function displayWorkoutDetails(workoutId) {
676
- // Check login
677
- if (!currentUser) return;
678
-
679
- const workout = workouts.find(w => w.id === workoutId);
680
- if (!workout) return; // Workout not found for this user
681
-
682
- // Update basic info (unchanged)
683
- document.getElementById('detail-workout-name').textContent = workout.name;
684
- document.getElementById('detail-date').textContent = new Date(workout.date).toLocaleDateString('fr-FR');
685
- document.getElementById('detail-duration').textContent = workout.duration;
686
- document.getElementById('detail-tonnage').textContent = workout.totalTonnage.toFixed(1);
687
- document.getElementById('detail-satisfaction').textContent = `${workout.satisfaction}%`;
688
- document.getElementById('detail-exercises-count').textContent = workout.exercises.length;
689
-
690
-
691
- // Display exercises (unchanged logic)
692
- const detailExercisesContainer = document.getElementById('detail-exercises-container');
693
- detailExercisesContainer.innerHTML = ''; // Clear previous details
694
-
695
- workout.exercises.forEach(exercise => {
696
- const exerciseDiv = document.createElement('div');
697
- exerciseDiv.className = 'card'; // Use card style for each exercise detail
698
-
699
- let seriesHtml = '';
700
- exercise.series.forEach((serie, index) => {
701
- const degressiveLabel = serie.isDegressive ? ' <span class="badge" style="background-color: var(--accent-dark);">Dégressive</span>' : '';
702
- const weightFactor = exercise.isUnilateral ? 2 : 1;
703
- const seriesTonnage = serie.reps * serie.weight * weightFactor;
704
-
705
- seriesHtml += `
706
- <div class="exercise-summary">
707
- <div class="flex-between" style="font-size: 0.9rem;">
708
- <span>Série ${index + 1}: ${serie.reps} reps × ${serie.weight} kg${degressiveLabel}</span>
709
- <span style="color: #ccc;">(Tonnage: ${seriesTonnage.toFixed(1)} kg)</span>
710
- </div>
711
- </div>
712
- `;
713
- });
714
-
715
- const unilateralLabel = exercise.isUnilateral ? ' <span class="badge">Unilatéral</span>' : '';
716
-
717
- exerciseDiv.innerHTML = `
718
- <h3 style="font-size: 1.1rem; margin-bottom: 0.5rem;">${exercise.name}${unilateralLabel}</h3>
719
- <div class="series-summary">
720
- ${seriesHtml}
721
- </div>
722
- `;
723
-
724
- detailExercisesContainer.appendChild(exerciseDiv);
725
- });
726
-
727
-
728
- // Store ID for potential delete/edit
729
- currentWorkoutId = workoutId;
730
-
731
- // Show the details page
732
- showPage('workout-details-page');
733
- }
734
-
735
-
736
- function deleteWorkout() {
737
- // Check login and if a workout is selected
738
- if (!currentUser || !currentWorkoutId) return;
739
-
740
- const confirmDelete = confirm("Êtes-vous sûr de vouloir supprimer cette séance ? Cette action est irréversible.");
741
- if (!confirmDelete) return;
742
-
743
- // Filter out the workout to delete from the current user's data
744
- workouts = workouts.filter(w => w.id !== currentWorkoutId);
745
-
746
- // Save the updated data for the user
747
- saveWorkouts();
748
-
749
- // Go back to home and refresh the list
750
- showPage('home-page');
751
- renderWorkoutsList(); // This will also update stats
752
- }
753
-
754
- function clearNewWorkoutForm() {
755
- // Check login
756
- if (!currentUser) return;
757
-
758
- document.getElementById('workout-name').value = '';
759
- document.getElementById('workout-duration').value = '';
760
- setTodayDate(); // Reset date
761
- exercisesContainer.innerHTML = ''; // Clear exercises
762
- satisfactionRange.value = 75; // Reset satisfaction
763
- satisfactionValue.textContent = '75%';
764
- currentWorkoutId = null; // Ensure it's treated as new
765
- }
766
-
767
- function updateStats() {
768
- // Check login
769
- if (!currentUser) return;
770
-
771
- const workoutCount = workouts.length;
772
- document.getElementById('stats-workout-count').textContent = workoutCount;
773
-
774
- if (workoutCount === 0) {
775
- document.getElementById('stats-avg-tonnage').textContent = '0';
776
- document.getElementById('stats-avg-satisfaction').textContent = '0%';
777
- return;
778
- }
779
-
780
- // Average Tonnage (unchanged)
781
- const totalTonnageAll = workouts.reduce((sum, workout) => sum + workout.totalTonnage, 0);
782
- const avgTonnage = totalTonnageAll / workoutCount;
783
- document.getElementById('stats-avg-tonnage').textContent = avgTonnage.toFixed(1);
784
-
785
- // Average Satisfaction (unchanged)
786
- const totalSatisfaction = workouts.reduce((sum, workout) => sum + workout.satisfaction, 0);
787
- const avgSatisfaction = totalSatisfaction / workoutCount;
788
- document.getElementById('stats-avg-satisfaction').textContent = `${Math.round(avgSatisfaction)}%`;
789
- }
790
-
791
- </script>
792
- </body>
793
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <div id="app-container">
2
  <!-- Page Accueil / Liste Séances -->
3
+ <!-- SEULE CELLE-CI A 'active' AU DÉBUT -->
4
  <div id="home-page" class="active">
5
  <div class="flex-between">
6
  <h2>Mes séances</h2>
 
15
  </div>
16
 
17
  <!-- Page Nouvelle Séance -->
18
+ <!-- !!! ENLEVER class="hidden" !!! -->
19
+ <div id="new-workout-page">
20
  <div class="flex-between">
21
  <h2>Nouvelle séance</h2>
22
  <div> <!-- Conteneur pour les boutons -->
 
24
  <button id="save-workout-btn" class="btn">Enregistrer</button>
25
  </div>
26
  </div>
27
+ <!-- ... reste du contenu de new-workout-page ... -->
28
+ <div class="card">
29
  <div class="form-group">
30
  <label for="workout-name">Nom de la séance</label>
31
  <input type="text" id="workout-name" placeholder="Ex: Push, Legs, Full Body...">
 
57
  </div>
58
 
59
  <!-- Page Détail Séance -->
60
+ <!-- !!! ENLEVER class="hidden" !!! -->
61
+ <div id="workout-details-page">
62
  <div class="flex-between">
63
  <h2 id="detail-workout-name">Détail Séance</h2>
64
  <button id="back-to-home" class="btn btn-outline">Retour</button>
65
  </div>
66
+ <!-- ... reste du contenu de workout-details-page ... -->
67
+ <div class="card">
68
  <div class="workout-details-info">
69
  <div class="form-row">
70
  <p><strong>Date:</strong> <span id="detail-date"></span></p>
 
92
  </div>
93
 
94
  <!-- Page Statistiques -->
95
+ <!-- !!! ENLEVER class="hidden" !!! -->
96
+ <div id="stats-page">
97
  <h2>Statistiques</h2>
98
+ <!-- ... reste du contenu de stats-page ... -->
99
+ <div class="stats-grid">
100
  <div class="card stat-card">
101
  <div class="stat-value" id="stats-workout-count">0</div>
102
  <div>Séances Totales</div>
 
117
  </p>
118
  </div>
119
  </div>
120
+ </div>