Browse Source

feat(locales): add total volume translation for English and French locales
feat(workout-session): implement getTotalVolume function to calculate total workout volume based on completed sets
feat(workout-session-header): display total volume in the workout session header UI

Mathias 1 month ago
parent
commit
d4ba8ec82a

+ 1 - 0
locales/en.ts

@@ -223,6 +223,7 @@ export default {
       elapsed_time: "Elapsed Time",
       chronometer: "Chronometer",
       exercise_progress: "Exercise Progress",
+      total_volume: "Total Volume",
       current_exercise: "Current Exercise",
       complete: "Complete",
       active: "Active",

+ 1 - 0
locales/fr.ts

@@ -224,6 +224,7 @@ export default {
       chronometer: "Chronomètre",
       total_workout_time: "Temps total d'entraînement",
       exercise_progress: "Progression",
+      total_volume: "Volume Total",
       current_exercise: "Exercice actuel",
       complete: "Terminé",
       active: "Actif",

+ 31 - 0
src/features/workout-session/model/workout-session.store.ts

@@ -48,6 +48,7 @@ interface WorkoutSessionState {
   formatElapsedTime: () => string;
   getExercisesCompleted: () => number;
   getTotalExercises: () => number;
+  getTotalVolume: () => number;
   loadSessionFromLocal: () => void;
 }
 
@@ -296,6 +297,36 @@ export const useWorkoutSessionStore = create<WorkoutSessionState>((set, get) =>
     return session.exercises.length;
   },
 
+  getTotalVolume: () => {
+    const { session } = get();
+    if (!session) return 0;
+
+    let totalVolume = 0;
+
+    session.exercises.forEach((exercise) => {
+      exercise.sets.forEach((set) => {
+        // Vérifier si le set est complété et contient REPS et WEIGHT
+        if (set.completed && set.types.includes("REPS") && set.types.includes("WEIGHT") && set.valuesInt) {
+          const repsIndex = set.types.indexOf("REPS");
+          const weightIndex = set.types.indexOf("WEIGHT");
+
+          const reps = set.valuesInt[repsIndex] || 0;
+          const weight = set.valuesInt[weightIndex] || 0;
+
+          // Convertir les livres en kg si nécessaire
+          const weightInKg =
+            set.units && set.units[weightIndex] === "lbs"
+              ? weight * 0.453592 // 1 lb = 0.453592 kg
+              : weight;
+
+          totalVolume += reps * weightInKg;
+        }
+      });
+    });
+
+    return Math.round(totalVolume);
+  },
+
   formatElapsedTime: () => {
     const { elapsedTime } = get();
     const hours = Math.floor(elapsedTime / 3600);

+ 20 - 3
src/features/workout-session/ui/workout-session-header.tsx

@@ -1,7 +1,7 @@
 "use client";
 
 import { useState } from "react";
-import { Clock, Play, Pause, RotateCcw, X, Target } from "lucide-react";
+import { Clock, Play, Pause, RotateCcw, X, Target, Weight } from "lucide-react";
 
 import { useCurrentLocale, useI18n } from "locales/client";
 import { cn } from "@/shared/lib/utils";
@@ -32,9 +32,10 @@ export function WorkoutSessionHeader({
   const [showQuitDialog, setShowQuitDialog] = useState(false);
   const [resetCount, setResetCount] = useState(0);
   const locale = useCurrentLocale();
-  const { getExercisesCompleted, getTotalExercises, session } = useWorkoutSession();
+  const { getExercisesCompleted, getTotalExercises, session, getTotalVolume } = useWorkoutSession();
   const exercisesCompleted = getExercisesCompleted();
   const totalExercises = getTotalExercises();
+  const totalVolume = getTotalVolume();
 
   const handleQuitClick = () => {
     setShowQuitDialog(true);
@@ -56,7 +57,6 @@ export function WorkoutSessionHeader({
         <div className="rounded-xl p-3 bg-slate-50 dark:bg-slate-900/80 border border-slate-200 dark:border-slate-700">
           <div className="flex items-center justify-between mb-4">
             <div className="flex items-center gap-2">
-              <div className="w-2 h-2 rounded-full bg-emerald-400 animate-ping"></div>
               <span className="text-emerald-400 font-semibold text-xs uppercase tracking-wider">
                 {t("workout_builder.session.started_at")}{" "}
                 {new Date(session?.startedAt || "").toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" })}
@@ -145,6 +145,23 @@ export function WorkoutSessionHeader({
                 </div>
               </div>
             </div>
+
+            {/* Card 3: Volume Total */}
+            <div className="bg-white dark:bg-slate-800 rounded-lg p-3 border border-slate-200 dark:border-slate-700 transition-colors duration-200 dark:text-white dark:hover:bg-slate-700">
+              <div className="flex items-center gap-2 mb-2">
+                <div className="w-8 h-8 rounded-full bg-orange-500/20 flex items-center justify-center">
+                  <Weight className="h-4 w-4 text-orange-400" />
+                </div>
+                <div>
+                  <h3 className="text-slate-700 dark:text-white font-semibold text-base">{t("workout_builder.session.total_volume")}</h3>
+                </div>
+              </div>
+
+              <div className="text-center">
+                <div className="text-2xl font-bold text-slate-900 dark:text-white mb-1">{totalVolume}</div>
+                <span className="text-sm text-slate-400">kg</span>
+              </div>
+            </div>
           </div>
         </div>
       </div>