Unilateral exercises logging

This commit is contained in:
AG
2025-12-03 23:30:32 +02:00
parent 50f3d4d49b
commit a632de65ea
24 changed files with 1656 additions and 244 deletions

View File

@@ -227,51 +227,178 @@ const ActiveSessionView: React.FC<ActiveSessionViewProps> = ({ tracker, activeSe
{selectedExercise && (
<div className="animate-in fade-in slide-in-from-bottom-4 duration-300 space-y-6">
<div className="grid grid-cols-2 gap-4">
{(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.STATIC) && (
<FilledInput
label={selectedExercise.type === ExerciseType.BODYWEIGHT ? t('add_weight', lang) : t('weight_kg', lang)}
value={weight}
step="0.1"
onChange={(e: any) => setWeight(e.target.value)}
icon={<Scale size={10} />}
autoFocus={activePlan && !isPlanFinished && activePlan.steps[currentStepIndex]?.isWeighted && (selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.STRENGTH)}
{/* Unilateral Exercise Toggle */}
{selectedExercise.isUnilateral && (
<div className="flex items-center gap-3 px-2 py-3 bg-surface-container rounded-xl">
<input
type="checkbox"
id="sameValuesBothSides"
checked={tracker.sameValuesBothSides}
onChange={(e) => tracker.handleToggleSameValues(e.target.checked)}
className="w-5 h-5 rounded border-2 border-outline bg-surface-container-high checked:bg-primary checked:border-primary cursor-pointer"
/>
)}
{(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.PLYOMETRIC) && (
<FilledInput
label={t('reps', lang)}
value={reps}
onChange={(e: any) => setReps(e.target.value)}
icon={<Activity size={10} />}
type="number"
/>
)}
{(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.STATIC) && (
<FilledInput
label={t('time_sec', lang)}
value={duration}
onChange={(e: any) => setDuration(e.target.value)}
icon={<TimerIcon size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.LONG_JUMP) && (
<FilledInput
label={t('dist_m', lang)}
value={distance}
onChange={(e: any) => setDistance(e.target.value)}
icon={<ArrowRight size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.HIGH_JUMP) && (
<FilledInput
label={t('height_cm', lang)}
value={height}
onChange={(e: any) => setHeight(e.target.value)}
icon={<ArrowUp size={10} />}
/>
)}
</div>
<label htmlFor="sameValuesBothSides" className="text-sm text-on-surface cursor-pointer flex-1">
{t('same_values_both_sides', lang)}
</label>
</div>
)}
{/* Input Forms */}
{selectedExercise.isUnilateral && !tracker.sameValuesBothSides ? (
/* Separate Left/Right Inputs */
<div className="space-y-4">
{/* Left Side */}
<div className="space-y-2">
<div className="text-sm font-medium text-primary flex items-center gap-2 px-2">
<span className="w-6 h-6 rounded-full bg-primary-container text-on-primary-container flex items-center justify-center text-xs font-bold">L</span>
{t('left', lang)}
</div>
<div className="grid grid-cols-2 gap-4">
{(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.STATIC) && (
<FilledInput
label={selectedExercise.type === ExerciseType.BODYWEIGHT ? t('add_weight', lang) : t('weight_kg', lang)}
value={tracker.weightLeft}
step="0.1"
onChange={(e: any) => tracker.setWeightLeft(e.target.value)}
icon={<Scale size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.PLYOMETRIC) && (
<FilledInput
label={t('reps', lang)}
value={tracker.repsLeft}
onChange={(e: any) => tracker.setRepsLeft(e.target.value)}
icon={<Activity size={10} />}
type="number"
/>
)}
{(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.STATIC) && (
<FilledInput
label={t('time_sec', lang)}
value={tracker.durationLeft}
onChange={(e: any) => tracker.setDurationLeft(e.target.value)}
icon={<TimerIcon size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.LONG_JUMP) && (
<FilledInput
label={t('dist_m', lang)}
value={tracker.distanceLeft}
onChange={(e: any) => tracker.setDistanceLeft(e.target.value)}
icon={<ArrowRight size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.HIGH_JUMP) && (
<FilledInput
label={t('height_cm', lang)}
value={tracker.heightLeft}
onChange={(e: any) => tracker.setHeightLeft(e.target.value)}
icon={<ArrowUp size={10} />}
/>
)}
</div>
</div>
{/* Right Side */}
<div className="space-y-2">
<div className="text-sm font-medium text-secondary flex items-center gap-2 px-2">
<span className="w-6 h-6 rounded-full bg-secondary-container text-on-secondary-container flex items-center justify-center text-xs font-bold">R</span>
{t('right', lang)}
</div>
<div className="grid grid-cols-2 gap-4">
{(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.STATIC) && (
<FilledInput
label={selectedExercise.type === ExerciseType.BODYWEIGHT ? t('add_weight', lang) : t('weight_kg', lang)}
value={tracker.weightRight}
step="0.1"
onChange={(e: any) => tracker.setWeightRight(e.target.value)}
icon={<Scale size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.PLYOMETRIC) && (
<FilledInput
label={t('reps', lang)}
value={tracker.repsRight}
onChange={(e: any) => tracker.setRepsRight(e.target.value)}
icon={<Activity size={10} />}
type="number"
/>
)}
{(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.STATIC) && (
<FilledInput
label={t('time_sec', lang)}
value={tracker.durationRight}
onChange={(e: any) => tracker.setDurationRight(e.target.value)}
icon={<TimerIcon size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.LONG_JUMP) && (
<FilledInput
label={t('dist_m', lang)}
value={tracker.distanceRight}
onChange={(e: any) => tracker.setDistanceRight(e.target.value)}
icon={<ArrowRight size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.HIGH_JUMP) && (
<FilledInput
label={t('height_cm', lang)}
value={tracker.heightRight}
onChange={(e: any) => tracker.setHeightRight(e.target.value)}
icon={<ArrowUp size={10} />}
/>
)}
</div>
</div>
</div>
) : (
/* Single Input Form (for bilateral or unilateral with same values) */
<div className="grid grid-cols-2 gap-4">
{(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.STATIC) && (
<FilledInput
label={selectedExercise.type === ExerciseType.BODYWEIGHT ? t('add_weight', lang) : t('weight_kg', lang)}
value={weight}
step="0.1"
onChange={(e: any) => setWeight(e.target.value)}
icon={<Scale size={10} />}
autoFocus={activePlan && !isPlanFinished && activePlan.steps[currentStepIndex]?.isWeighted && (selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.STRENGTH)}
/>
)}
{(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.PLYOMETRIC) && (
<FilledInput
label={t('reps', lang)}
value={reps}
onChange={(e: any) => setReps(e.target.value)}
icon={<Activity size={10} />}
type="number"
/>
)}
{(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.STATIC) && (
<FilledInput
label={t('time_sec', lang)}
value={duration}
onChange={(e: any) => setDuration(e.target.value)}
icon={<TimerIcon size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.LONG_JUMP) && (
<FilledInput
label={t('dist_m', lang)}
value={distance}
onChange={(e: any) => setDistance(e.target.value)}
icon={<ArrowRight size={10} />}
/>
)}
{(selectedExercise.type === ExerciseType.HIGH_JUMP) && (
<FilledInput
label={t('height_cm', lang)}
value={height}
onChange={(e: any) => setHeight(e.target.value)}
icon={<ArrowUp size={10} />}
/>
)}
</div>
)}
<button
onClick={handleAddSet}