// Add this to Tracker.tsx imports (line 9, after api import): import { logSporadicSet } from '../services/sporadicSets'; // Add this to TrackerProps interface (after onUpdateSet, around line 21): onSporadicSetAdded?: () => void; // Update component function signature (line 28): const Tracker: React.FC = ({ userId, userWeight, activeSession, activePlan, onSessionStart, onSessionEnd, onSessionQuit, onSetAdded, onRemoveSet, onUpdateSet, onSporadicSetAdded, lang }) => { // Add these state variables (after editHeight state, around line 69): const [isSporadicMode, setIsSporadicMode] = useState(false); const [sporadicSuccess, setSporadicSuccess] = useState(false); // Add this handler function (after handleCancelEdit, around line 289): const handleLogSporadicSet = async () => { if (!selectedExercise) return; const setData: any = { exerciseId: selectedExercise.id }; switch (selectedExercise.type) { case ExerciseType.STRENGTH: if (weight) setData.weight = parseFloat(weight); if (reps) setData.reps = parseInt(reps); break; case ExerciseType.BODYWEIGHT: if (weight) setData.weight = parseFloat(weight); if (reps) setData.reps = parseInt(reps); setData.bodyWeightPercentage = parseFloat(bwPercentage) || 100; break; case ExerciseType.CARDIO: if (duration) setData.durationSeconds = parseInt(duration); if (distance) setData.distanceMeters = parseFloat(distance); break; case ExerciseType.STATIC: if (duration) setData.durationSeconds = parseInt(duration); setData.bodyWeightPercentage = parseFloat(bwPercentage) || 100; break; case ExerciseType.HIGH_JUMP: if (height) setData.height = parseFloat(height); break; case ExerciseType.LONG_JUMP: if (distance) setData.distanceMeters = parseFloat(distance); break; case ExerciseType.PLYOMETRIC: if (reps) setData.reps = parseInt(reps); break; } const result = await logSporadicSet(setData); if (result) { setSporadicSuccess(true); setTimeout(() => setSporadicSuccess(false), 2000); // Reset form setWeight(''); setReps(''); setDuration(''); setDistance(''); setHeight(''); setSelectedExercise(null); setSearchQuery(''); if (onSporadicSetAdded) onSporadicSetAdded(); } }; // Replace the single "Free Workout" button section (around line 347-355) with:
// Add this new section after the "no active session" return statement (after line 396, before the main return): if (!activeSession && isSporadicMode) { return (
{/* Header */}

{t('quick_log', lang)}

{/* Success Message */} {sporadicSuccess && (
{t('log_sporadic_success', lang)}
)} {/* Exercise Selection and Form - reuse existing components */}
) => { setSearchQuery(e.target.value); setShowSuggestions(true); }} onFocus={() => setShowSuggestions(true)} onBlur={() => setTimeout(() => setShowSuggestions(false), 100)} icon={} autoComplete="off" type="text" /> {showSuggestions && (
{filteredExercises.length > 0 ? ( filteredExercises.map(ex => ( )) ) : (
{t('no_exercises_found', lang)}
)}
)}
{selectedExercise && (
{(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT) && ( setWeight(e.target.value)} icon={} autoFocus /> )} {(selectedExercise.type === ExerciseType.STRENGTH || selectedExercise.type === ExerciseType.BODYWEIGHT || selectedExercise.type === ExerciseType.PLYOMETRIC) && ( setReps(e.target.value)} icon={} /> )} {(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.STATIC) && ( setDuration(e.target.value)} icon={} /> )} {(selectedExercise.type === ExerciseType.CARDIO || selectedExercise.type === ExerciseType.LONG_JUMP) && ( setDistance(e.target.value)} icon={} /> )} {selectedExercise.type === ExerciseType.HIGH_JUMP && ( setHeight(e.target.value)} icon={} /> )}
)}
{/* Exercise Modal */} {isCreating && ( setIsCreating(false)} onCreate={handleCreateExercise} lang={lang} /> )}
); }