From 52fce8022a106ea33c680b95c10c76cee13b9b86 Mon Sep 17 00:00:00 2001 From: Sten Levasseur Date: Tue, 12 Aug 2025 14:44:46 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20feat:=20enhance=20workout=20ele?= =?UTF-8?q?ments=20step=20UI=20and=20search=20functionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add tooltips - Improve complex search to include exercise names within complexes - Update button styling and background colors - Display exercise names in complex cards - Refactor layout and improve spacing consistency --- .../workout/steps/workout-elements-step.tsx | 99 ++++++++++++------- 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/apps/web/src/features/workout/steps/workout-elements-step.tsx b/apps/web/src/features/workout/steps/workout-elements-step.tsx index 7aa2fa9..f81e7f4 100644 --- a/apps/web/src/features/workout/steps/workout-elements-step.tsx +++ b/apps/web/src/features/workout/steps/workout-elements-step.tsx @@ -2,6 +2,7 @@ import { api } from '@/lib/api'; import { Button } from '@/shared/components/ui/button'; import { Card, CardContent } from '@/shared/components/ui/card'; import { Input } from '@/shared/components/ui/input'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/shared/components/ui/tooltip'; import { DndContext, DragEndEvent, @@ -132,12 +133,20 @@ export function WorkoutElementsStep({ exercise.name.toLowerCase().includes(exerciseSearch.toLowerCase()) ) || []; - const filteredComplexes = complexes?.filter(complex => - complex.complexCategory?.name?.toLowerCase().includes(complexSearch.toLowerCase()) - ) || []; + const filteredComplexes = complexes?.filter(complex => { + const searchTerm = complexSearch.toLowerCase(); + // Recherche dans le nom de la catégorie + const categoryMatch = complex.complexCategory?.name?.toLowerCase().includes(searchTerm); + // Recherche dans les noms des exercices du complexe + const exerciseMatch = complex.exercises.some(exercise => + exercise.name.toLowerCase().includes(searchTerm) + ); + return categoryMatch || exerciseMatch; + }) || []; return ( -
+ +
{/* Layout principal : 2 colonnes */}
@@ -204,7 +213,7 @@ export function WorkoutElementsStep({ e.stopPropagation(); setCreateExerciseModalOpen(true); }} - className="w-full bg-orange-100" + className="w-full bg-primary/5 hover:bg-primary/10" > Créer un nouvel exercice @@ -215,23 +224,30 @@ export function WorkoutElementsStep({ {filteredExercises.map((exercise) => (
-
-
{exercise.name}
+
+
{exercise.name}

{exercise.exerciseCategory.name}

- + + + + + +

Ajouter cet exercice à l'entraînement

+
+
))} @@ -241,7 +257,7 @@ export function WorkoutElementsStep({ {activeTab === 'complex' && (
-
+
Créer un nouveau complexe @@ -272,23 +288,39 @@ export function WorkoutElementsStep({ {filteredComplexes.map((complex) => (
-
-
{complex.complexCategory?.name || 'Complex'}
-

- {complex.exercises.length} exercices -

+
+
+ {complex.exercises.map((exercise, index) => ( + + {exercise.name} + {index < complex.exercises.length - 1 ? ', ' : ''} + + ))} +
+ {complex.complexCategory?.name && ( +

+ {complex.complexCategory.name} +

+ )}
- + + + + + +

Ajouter ce complexe à l'entraînement

+
+
))} @@ -396,6 +428,7 @@ export function WorkoutElementsStep({ onCancel={() => setCreateComplexModalOpen(false)} /> -
+
+ ); } From 750f8b224859d4197f5b88ed84e7f0ce48551d2c Mon Sep 17 00:00:00 2001 From: Sten Levasseur Date: Tue, 12 Aug 2025 15:08:33 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20editable=20descri?= =?UTF-8?q?ptions=20for=20workout=20elements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add editable description fields for both exercises and complexes - Implement inline editing with Textarea components - Show exercise names in complex selection dropdowns - Improve complex display by showing exercise names instead of just category - Add keyboard shortcuts (Ctrl+Enter to save, Escape to cancel) - Fix typo: change "font-sm" to "font-medium" for exercise names --- .../workout/sortable-workout-element.tsx | 126 +++++++++++++++--- 1 file changed, 111 insertions(+), 15 deletions(-) diff --git a/apps/web/src/features/workout/sortable-workout-element.tsx b/apps/web/src/features/workout/sortable-workout-element.tsx index fd4f039..67e7fc6 100644 --- a/apps/web/src/features/workout/sortable-workout-element.tsx +++ b/apps/web/src/features/workout/sortable-workout-element.tsx @@ -8,6 +8,7 @@ import { FormMessage, } from '@/shared/components/ui/form'; import { Input } from '@/shared/components/ui/input'; +import { Textarea } from '@/shared/components/ui/textarea'; import { Select, SelectContent, @@ -64,6 +65,10 @@ export function SortableWorkoutElement({ const [editingWeight, setEditingWeight] = useState(false); const [editingRest, setEditingRest] = useState(false); const [editingElement, setEditingElement] = useState(false); + const [editingDescription, setEditingDescription] = useState(false); + const [editingExerciseDescription, setEditingExerciseDescription] = useState(false); + const [localDescription, setLocalDescription] = useState(''); + const [localExerciseDescription, setLocalExerciseDescription] = useState(''); const selectRef = useRef(null); const { @@ -87,19 +92,38 @@ export function SortableWorkoutElement({ // Trouver le complex sélectionné const selectedComplex = complexes.find((c) => c.id === selectedComplexId); + + // Trouver l'exercice sélectionné + const selectedExercise = exercises.find((e) => e.id === control._formValues.elements[index].id); - // Mettre à jour selectedComplexId quand l'ID change dans le form + // Mettre à jour selectedComplexId et exercice quand l'ID change dans le form useEffect(() => { const currentId = control._formValues.elements[index].id; - if ( - currentId && - control._formValues.elements[index].type === WORKOUT_ELEMENT_TYPES.COMPLEX - ) { + const currentType = control._formValues.elements[index].type; + + if (currentId && currentType === WORKOUT_ELEMENT_TYPES.COMPLEX) { setSelectedComplexId(currentId); + // Initialiser la description locale avec celle du complexe + const complex = complexes.find(c => c.id === currentId); + if (complex?.description && !localDescription) { + setLocalDescription(complex.description); + } + } + + if (currentId && currentType === WORKOUT_ELEMENT_TYPES.EXERCISE) { + // Initialiser la description locale avec celle de l'exercice + const exercise = exercises.find(e => e.id === currentId); + if (exercise?.description && !localExerciseDescription) { + setLocalExerciseDescription(exercise.description); + } } }, [ control._formValues.elements[index].id, control._formValues.elements[index].type, + complexes, + exercises, + localDescription, + localExerciseDescription, ]); const renderEditableBadge = ( @@ -256,7 +280,14 @@ export function SortableWorkoutElement({ )) : complexes.map((complex) => ( - {complex.complexCategory?.name || 'Complex'} +
+ + {complex.exercises.map(ex => ex.name).join(', ')} + + + {complex.complexCategory?.name} + +
))} @@ -275,7 +306,7 @@ export function SortableWorkoutElement({ > {type === WORKOUT_ELEMENT_TYPES.EXERCISE ? exercises.find((e) => e.id === field.value)?.name - : complexes.find((c) => c.id === field.value)?.complexCategory?.name || 'Complex'} + : complexes.find((c) => c.id === field.value)?.exercises.map(ex => ex.name).join(', ') || 'Complex'} )} @@ -320,6 +351,42 @@ export function SortableWorkoutElement({ )} {renderElementSelect(WORKOUT_ELEMENT_TYPES.EXERCISE)}
+
+ {editingExerciseDescription ? ( +