瀏覽代碼

feat(locales): add congratulatory messages and instructions in English and French for workout completion
refactor(Header): replace hardcoded home label with translation function for better localization support
refactor(release-notes-dialog): replace hardcoded changelog title with translation function for better localization support
refactor(workout-stepper): use translation for congratulatory messages to enhance localization
fix(workout-session.store): set isTimerRunning to false when starting a new workout session
refactor(workout-session-header):

Mathias 1 月之前
父節點
當前提交
c8b458d42a

+ 6 - 0
locales/en.ts

@@ -153,6 +153,9 @@ export default {
       exercise_selection_description: "This step will show you personalized exercise recommendations.",
     },
     session: {
+      congrats: "Congratulations, workout finished! 🎉",
+      congrats_subtitle: "You've done it !",
+      see_instructions: "See instructions",
       finish_set: "Finish Set",
       finish_session: "Finish Session",
       bodyweight: "Bodyweight",
@@ -168,6 +171,7 @@ export default {
       set_number_singular: "Set {number}",
       set_number_plural_singular: "Sets {number}",
       workout_in_progress: "Workout in Progress",
+      started_at: "Started at",
       quit_workout: "Quit Workout",
       elapsed_time: "Elapsed Time",
       chronometer: "Chronometer",
@@ -283,5 +287,7 @@ export default {
     donate: "Donate",
     my_account: "My account",
     dashboard: "Dashboard",
+    home: "Home",
+    changelog: "Changelog",
   },
 } as const;

+ 6 - 0
locales/fr.ts

@@ -153,6 +153,9 @@ export default {
       exercise_selection_description: "Cette étape vous montrera des recommandations d'exercices personnalisées.",
     },
     session: {
+      congrats: "Bravo, séance terminée ! 🎉",
+      congrats_subtitle: "Tu l'as fait !",
+      see_instructions: "Voir les instructions",
       finish_set: "Valider la série",
       finish_session: "Terminer la séance",
       bodyweight: "Poids du corps",
@@ -168,6 +171,7 @@ export default {
       set_number_singular: "Série {number}",
       set_number_plural_singular: "Séries {number}",
       workout_in_progress: "Entraînement en cours",
+      started_at: "Débuté à",
       quit_workout: "Quitter l'Entraînement",
       elapsed_time: "Temps écoulé",
       chronometer: "Chronomètre",
@@ -284,5 +288,7 @@ export default {
     donate: "Faire un don",
     my_account: "Mon compte",
     dashboard: "Tableau de bord",
+    home: "Accueil",
+    changelog: "Annonces & notes de version",
   },
 } as const;

+ 2 - 2
src/features/layout/Header.tsx

@@ -46,8 +46,8 @@ export const Header = () => {
 
       {/* User Menu */}
       <div className="navbar-end">
-        <Link aria-label="Accueil" className="hover:bg-slate-100 rounded-full p-2 transition" href="/">
-          <InlineTooltip title="Accueil">
+        <Link aria-label={t("commons.home")} className="hover:bg-slate-100 rounded-full p-2 transition" href="/">
+          <InlineTooltip title={t("commons.home")}>
             <Home className="w-6 h-6 text-blue-500" />
           </InlineTooltip>
         </Link>

+ 1 - 1
src/features/release-notes/ui/release-notes-dialog.tsx

@@ -19,7 +19,7 @@ export function ReleaseNotesDialog() {
     <Dialog>
       <DialogTrigger asChild>
         <Button aria-label={t("release_notes.release_notes")} className="rounded-full hover:bg-slate-100" size="small" variant="ghost">
-          <InlineTooltip title="Annonces / Changelog">
+          <InlineTooltip title={t("commons.changelog")}>
             <Bell className="text-blue-500 h-6 w-6" />
           </InlineTooltip>
         </Button>

+ 2 - 2
src/features/workout-builder/ui/workout-stepper.tsx

@@ -125,8 +125,8 @@ export function WorkoutStepper() {
     return (
       <div className="flex flex-col items-center justify-center py-16">
         <Image alt="Trophée" className="w-56 h-56" src={Trophy} />
-        <h2 className="text-2xl font-bold mb-2">Bravo, séance terminée ! 🎉</h2>
-        <p className="text-lg text-slate-600 mb-6">Tu as complété tous tes exercices.</p>
+        <h2 className="text-2xl font-bold mb-2">{t("workout_builder.session.congrats")}</h2>
+        <p className="text-lg text-slate-600 mb-6">{t("workout_builder.session.congrats_subtitle")}</p>
         <Button onClick={() => router.push("/profile")}>{t("commons.go_to_profile")}</Button>
       </div>
     );

+ 1 - 1
src/features/workout-session/model/workout-session.store.ts

@@ -90,7 +90,7 @@ export const useWorkoutSessionStore = create<WorkoutSessionState>((set, get) =>
     set({
       session: newSession,
       elapsedTime: 0,
-      isTimerRunning: true,
+      isTimerRunning: false,
       isWorkoutActive: true,
       currentExerciseIndex: 0,
       currentExercise: sessionExercises[0],

+ 6 - 5
src/features/workout-session/ui/workout-session-header.tsx

@@ -3,7 +3,7 @@
 import { useState } from "react";
 import { Clock, Play, Pause, RotateCcw, X, Target } from "lucide-react";
 
-import { useI18n } from "locales/client";
+import { useCurrentLocale, useI18n } from "locales/client";
 import { cn } from "@/shared/lib/utils";
 import { useWorkoutSession } from "@/features/workout-session/model/use-workout-session";
 import { Timer } from "@/components/ui/timer";
@@ -33,8 +33,8 @@ export function WorkoutSessionHeader({
   const t = useI18n();
   const [showQuitDialog, setShowQuitDialog] = useState(false);
   const [resetCount, setResetCount] = useState(0);
-
-  const { getExercisesCompleted, getTotalExercises } = useWorkoutSession();
+  const locale = useCurrentLocale();
+  const { getExercisesCompleted, getTotalExercises, session } = useWorkoutSession();
   const exercisesCompleted = getExercisesCompleted();
   const totalExercises = getTotalExercises();
 
@@ -63,9 +63,10 @@ export function WorkoutSessionHeader({
         <div className="rounded-xl p-3 bg-slate-50">
           <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-pulse"></div>
+              <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.workout_in_progress")}
+                {t("workout_builder.session.started_at")}{" "}
+                {new Date(session?.startedAt || "").toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" })}
               </span>
             </div>
 

+ 1 - 6
src/features/workout-session/ui/workout-session-sets.tsx

@@ -32,11 +32,6 @@ export function WorkoutSessionSets({
   const exerciseDetailsMap = Object.fromEntries(session?.exercises.map((ex) => [ex.id, ex]) || []);
   const [videoModal, setVideoModal] = useState<{ open: boolean; exerciseId?: string }>({ open: false });
 
-  // Calcul de la progression (exercices terminés / total)
-  const totalExercises = session?.exercises.length || 0;
-  const completedExercises = session?.exercises.filter((ex) => ex.sets.length > 0 && ex.sets.every((set) => set.completed)).length || 0;
-  const progressPercent = totalExercises > 0 ? Math.round((completedExercises / totalExercises) * 100) : 0;
-
   if (showCongrats) {
     return (
       <div className="flex flex-col items-center justify-center py-16">
@@ -149,7 +144,7 @@ export function WorkoutSessionSets({
                         setVideoModal({ open: true, exerciseId: ex.id });
                       }}
                     >
-                      Voir les instructions
+                      {t("workout_builder.session.see_instructions")}
                     </span>
                   )}
                   {/* Fallback: description si pas d'introduction */}