1. Removed Prev. and Body Weight % elements from the session logging screen. 2. Added logged set editing.

This commit is contained in:
aodulov
2025-11-26 09:44:57 +02:00
parent 34738697df
commit 85a351ea4e
3 changed files with 152 additions and 52 deletions

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { Plus, Activity, ChevronDown, ChevronUp, Dumbbell, PlayCircle, CheckCircle, User, Scale, X, Flame, Timer as TimerIcon, ArrowUp, ArrowRight, Footprints, Ruler, CheckSquare, Trash2, Percent, MoreVertical } from 'lucide-react';
import { Plus, Activity, ChevronDown, ChevronUp, Dumbbell, PlayCircle, CheckCircle, User, Scale, X, Flame, Timer as TimerIcon, ArrowUp, ArrowRight, Footprints, Ruler, CheckSquare, Trash2, Percent, MoreVertical, Edit } from 'lucide-react';
import { WorkoutSession, WorkoutSet, ExerciseDef, ExerciseType, WorkoutPlan, Language } from '../types';
import { getExercises, getLastSetForExercise, saveExercise, getPlans } from '../services/storage';
import { getCurrentUserProfile } from '../services/auth';
@@ -15,13 +15,14 @@ interface TrackerProps {
onSessionEnd: () => void;
onSetAdded: (set: WorkoutSet) => void;
onRemoveSet: (setId: string) => void;
onUpdateSet: (set: WorkoutSet) => void;
lang: Language;
}
import FilledInput from './FilledInput';
import ExerciseModal from './ExerciseModal';
const Tracker: React.FC<TrackerProps> = ({ userId, userWeight, activeSession, activePlan, onSessionStart, onSessionEnd, onSetAdded, onRemoveSet, lang }) => {
const Tracker: React.FC<TrackerProps> = ({ userId, userWeight, activeSession, activePlan, onSessionStart, onSessionEnd, onSetAdded, onRemoveSet, onUpdateSet, lang }) => {
const [exercises, setExercises] = useState<ExerciseDef[]>([]);
const [plans, setPlans] = useState<WorkoutPlan[]>([]);
const [selectedExercise, setSelectedExercise] = useState<ExerciseDef | null>(null);
@@ -54,6 +55,14 @@ const Tracker: React.FC<TrackerProps> = ({ userId, userWeight, activeSession, ac
const [showQuitConfirm, setShowQuitConfirm] = useState(false);
const [showMenu, setShowMenu] = useState(false);
// Edit Set State
const [editingSetId, setEditingSetId] = useState<string | null>(null);
const [editWeight, setEditWeight] = useState<string>('');
const [editReps, setEditReps] = useState<string>('');
const [editDuration, setEditDuration] = useState<string>('');
const [editDistance, setEditDistance] = useState<string>('');
const [editHeight, setEditHeight] = useState<string>('');
useEffect(() => {
const loadData = async () => {
const exList = await getExercises(userId);
@@ -174,6 +183,32 @@ const Tracker: React.FC<TrackerProps> = ({ userId, userWeight, activeSession, ac
setIsCreating(false);
};
const handleEditSet = (set: WorkoutSet) => {
setEditingSetId(set.id);
setEditWeight(set.weight?.toString() || '');
setEditReps(set.reps?.toString() || '');
setEditDuration(set.durationSeconds?.toString() || '');
setEditDistance(set.distanceMeters?.toString() || '');
setEditHeight(set.height?.toString() || '');
};
const handleSaveEdit = (set: WorkoutSet) => {
const updatedSet: WorkoutSet = {
...set,
...(editWeight && { weight: parseFloat(editWeight) }),
...(editReps && { reps: parseInt(editReps) }),
...(editDuration && { durationSeconds: parseInt(editDuration) }),
...(editDistance && { distanceMeters: parseFloat(editDistance) }),
...(editHeight && { height: parseFloat(editHeight) })
};
onUpdateSet(updatedSet);
setEditingSetId(null);
};
const handleCancelEdit = () => {
setEditingSetId(null);
};
const jumpToStep = (index: number) => {
if (!activePlan) return;
setCurrentStepIndex(index);
@@ -446,22 +481,6 @@ const Tracker: React.FC<TrackerProps> = ({ userId, userWeight, activeSession, ac
)}
</div>
{(selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.STATIC) && (
<div className="flex items-center gap-4 px-2">
<div className="flex items-center gap-2 text-on-surface-variant">
<Percent size={16} />
<span className="text-xs font-medium">{t('body_weight_percent', lang)}</span>
</div>
<input
type="number"
className="w-20 border-b border-outline-variant bg-transparent text-center text-on-surface focus:border-primary focus:outline-none"
value={bwPercentage}
onChange={(e) => setBwPercentage(e.target.value)}
/>
<span className="text-on-surface-variant text-sm">%</span>
</div>
)}
<button
onClick={handleAddSet}
className="w-full h-14 bg-primary-container text-on-primary-container font-medium text-lg rounded-full shadow-elevation-2 hover:shadow-elevation-3 active:scale-[0.98] transition-all flex items-center justify-center gap-2"
@@ -469,22 +488,6 @@ const Tracker: React.FC<TrackerProps> = ({ userId, userWeight, activeSession, ac
<CheckCircle size={24} />
<span>{t('log_set', lang)}</span>
</button>
<div className="flex justify-center">
<div className="bg-surface-container px-4 py-2 rounded-full border border-outline-variant/20 text-xs text-on-surface-variant">
{t('prev', lang)}: <span className="text-on-surface font-medium ml-1">
{lastSet ? (
<>
{lastSet?.weight ? `${lastSet?.weight}kg × ` : ''}
{lastSet?.reps ? `${lastSet?.reps}` : ''}
{lastSet?.distanceMeters ? `${lastSet?.distanceMeters}m` : ''}
{lastSet?.height ? `${lastSet?.height}cm` : ''}
{lastSet?.durationSeconds ? `${lastSet?.durationSeconds}s` : ''}
</>
) : '—'}
</span>
</div>
</div>
</div>
)}
@@ -494,29 +497,113 @@ const Tracker: React.FC<TrackerProps> = ({ userId, userWeight, activeSession, ac
<div className="flex flex-col gap-2">
{[...activeSession.sets].reverse().map((set, idx) => {
const setNumber = activeSession.sets.length - idx;
const isEditing = editingSetId === set.id;
return (
<div key={set.id} className="flex justify-between items-center p-4 bg-surface-container rounded-xl shadow-elevation-1 animate-in fade-in slide-in-from-bottom-2">
<div className="flex items-center gap-4">
<div className="flex items-center gap-4 flex-1">
<div className="w-8 h-8 rounded-full bg-secondary-container text-on-secondary-container flex items-center justify-center text-xs font-bold">
{setNumber}
</div>
<div>
<div className="text-base font-medium text-on-surface">{set.exerciseName}</div>
<div className="text-sm text-on-surface-variant">
{set.weight !== undefined && `${set.weight}kg `}
{set.reps !== undefined && `x ${set.reps}`}
{set.distanceMeters !== undefined && `${set.distanceMeters}m`}
{set.durationSeconds !== undefined && `${set.durationSeconds}s`}
{set.height !== undefined && `${set.height}cm`}
{isEditing ? (
<div className="flex-1">
<div className="text-base font-medium text-on-surface mb-2">{set.exerciseName}</div>
<div className="grid grid-cols-2 gap-2">
{set.weight !== undefined && (
<input
type="number"
step="0.1"
value={editWeight}
onChange={(e) => setEditWeight(e.target.value)}
className="px-2 py-1 bg-surface-container-high rounded text-sm text-on-surface border border-outline-variant focus:border-primary focus:outline-none"
placeholder="Weight (kg)"
/>
)}
{set.reps !== undefined && (
<input
type="number"
value={editReps}
onChange={(e) => setEditReps(e.target.value)}
className="px-2 py-1 bg-surface-container-high rounded text-sm text-on-surface border border-outline-variant focus:border-primary focus:outline-none"
placeholder="Reps"
/>
)}
{set.durationSeconds !== undefined && (
<input
type="number"
value={editDuration}
onChange={(e) => setEditDuration(e.target.value)}
className="px-2 py-1 bg-surface-container-high rounded text-sm text-on-surface border border-outline-variant focus:border-primary focus:outline-none"
placeholder="Duration (s)"
/>
)}
{set.distanceMeters !== undefined && (
<input
type="number"
step="0.1"
value={editDistance}
onChange={(e) => setEditDistance(e.target.value)}
className="px-2 py-1 bg-surface-container-high rounded text-sm text-on-surface border border-outline-variant focus:border-primary focus:outline-none"
placeholder="Distance (m)"
/>
)}
{set.height !== undefined && (
<input
type="number"
step="0.1"
value={editHeight}
onChange={(e) => setEditHeight(e.target.value)}
className="px-2 py-1 bg-surface-container-high rounded text-sm text-on-surface border border-outline-variant focus:border-primary focus:outline-none"
placeholder="Height (cm)"
/>
)}
</div>
</div>
</div>
) : (
<div>
<div className="text-base font-medium text-on-surface">{set.exerciseName}</div>
<div className="text-sm text-on-surface-variant">
{set.weight !== undefined && `${set.weight}kg `}
{set.reps !== undefined && `x ${set.reps}`}
{set.distanceMeters !== undefined && `${set.distanceMeters}m`}
{set.durationSeconds !== undefined && `${set.durationSeconds}s`}
{set.height !== undefined && `${set.height}cm`}
</div>
</div>
)}
</div>
<div className="flex items-center gap-2">
{isEditing ? (
<>
<button
onClick={handleCancelEdit}
className="p-2 text-on-surface-variant hover:text-on-surface hover:bg-surface-container-high rounded-full transition-colors"
>
<X size={20} />
</button>
<button
onClick={() => handleSaveEdit(set)}
className="p-2 text-primary hover:bg-primary-container/20 rounded-full transition-colors"
>
<CheckCircle size={20} />
</button>
</>
) : (
<>
<button
onClick={() => handleEditSet(set)}
className="p-2 text-on-surface-variant hover:text-primary hover:bg-primary-container/20 rounded-full transition-colors"
>
<Edit size={20} />
</button>
<button
onClick={() => onRemoveSet(set.id)}
className="p-2 text-on-surface-variant hover:text-error hover:bg-error-container/10 rounded-full transition-colors"
>
<Trash2 size={20} />
</button>
</>
)}
</div>
<button
onClick={() => onRemoveSet(set.id)}
className="p-2 text-on-surface-variant hover:text-error hover:bg-error-container/10 rounded-full transition-colors"
>
<Trash2 size={20} />
</button>
</div>
);
})}
@@ -552,7 +639,7 @@ const Tracker: React.FC<TrackerProps> = ({ userId, userWeight, activeSession, ac
setShowFinishConfirm(false);
onSessionEnd();
}}
className="px-6 py-2.5 rounded-full bg-primary text-on-primary font-medium"
className="px-6 py-2.5 rounded-full bg-green-600 text-white font-medium hover:bg-green-700"
>
{t('confirm', lang)}
</button>
@@ -580,7 +667,7 @@ const Tracker: React.FC<TrackerProps> = ({ userId, userWeight, activeSession, ac
// Quit without saving - just navigate away or reset
window.location.reload();
}}
className="px-6 py-2.5 rounded-full bg-error text-on-error font-medium"
className="px-6 py-2.5 rounded-full bg-green-600 text-white font-medium hover:bg-green-700"
>
{t('confirm', lang)}
</button>