Code maintainability fixes
This commit is contained in:
65
src/hooks/usePlanExecution.ts
Normal file
65
src/hooks/usePlanExecution.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { WorkoutSession, WorkoutPlan, ExerciseDef } from '../types';
|
||||
|
||||
interface UsePlanExecutionProps {
|
||||
activeSession: WorkoutSession | null;
|
||||
activePlan: WorkoutPlan | null;
|
||||
exercises: ExerciseDef[];
|
||||
}
|
||||
|
||||
export const usePlanExecution = ({ activeSession, activePlan, exercises }: UsePlanExecutionProps) => {
|
||||
const [currentStepIndex, setCurrentStepIndex] = useState(0);
|
||||
const [showPlanPrep, setShowPlanPrep] = useState<WorkoutPlan | null>(null);
|
||||
const [showPlanList, setShowPlanList] = useState(false);
|
||||
|
||||
// Automatically determine current step based on logged sets vs plan
|
||||
useEffect(() => {
|
||||
if (activeSession && activePlan) {
|
||||
const performedCounts = new Map<string, number>();
|
||||
for (const set of activeSession.sets) {
|
||||
performedCounts.set(set.exerciseId, (performedCounts.get(set.exerciseId) || 0) + 1);
|
||||
}
|
||||
|
||||
let nextStepIndex = activePlan.steps.length; // Default to finished
|
||||
const plannedCounts = new Map<string, number>();
|
||||
for (let i = 0; i < activePlan.steps.length; i++) {
|
||||
const step = activePlan.steps[i];
|
||||
const exerciseId = step.exerciseId;
|
||||
plannedCounts.set(exerciseId, (plannedCounts.get(exerciseId) || 0) + 1);
|
||||
const performedCount = performedCounts.get(exerciseId) || 0;
|
||||
|
||||
if (performedCount < plannedCounts.get(exerciseId)!) {
|
||||
nextStepIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setCurrentStepIndex(nextStepIndex);
|
||||
}
|
||||
}, [activeSession, activePlan]);
|
||||
|
||||
const getCurrentStep = () => {
|
||||
if (activeSession && activePlan && activePlan.steps.length > 0) {
|
||||
if (currentStepIndex < activePlan.steps.length) {
|
||||
return activePlan.steps[currentStepIndex];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const jumpToStep = (index: number) => {
|
||||
if (!activePlan) return;
|
||||
setCurrentStepIndex(index);
|
||||
setShowPlanList(false);
|
||||
};
|
||||
|
||||
return {
|
||||
currentStepIndex,
|
||||
setCurrentStepIndex,
|
||||
showPlanPrep,
|
||||
setShowPlanPrep,
|
||||
showPlanList,
|
||||
setShowPlanList,
|
||||
getCurrentStep,
|
||||
jumpToStep
|
||||
};
|
||||
};
|
||||
27
src/hooks/useSessionTimer.ts
Normal file
27
src/hooks/useSessionTimer.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { WorkoutSession } from '../types';
|
||||
|
||||
export const useSessionTimer = (activeSession: WorkoutSession | null) => {
|
||||
const [elapsedTime, setElapsedTime] = useState<string>('00:00:00');
|
||||
|
||||
useEffect(() => {
|
||||
let interval: number;
|
||||
if (activeSession) {
|
||||
const updateTimer = () => {
|
||||
const diff = Math.floor((Date.now() - activeSession.startTime) / 1000);
|
||||
const h = Math.floor(diff / 3600);
|
||||
const m = Math.floor((diff % 3600) / 60);
|
||||
const s = diff % 60;
|
||||
setElapsedTime(`${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`);
|
||||
};
|
||||
|
||||
updateTimer();
|
||||
interval = window.setInterval(updateTimer, 1000);
|
||||
} else {
|
||||
setElapsedTime('00:00:00');
|
||||
}
|
||||
return () => clearInterval(interval);
|
||||
}, [activeSession]);
|
||||
|
||||
return elapsedTime;
|
||||
};
|
||||
147
src/hooks/useWorkoutForm.ts
Normal file
147
src/hooks/useWorkoutForm.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { WorkoutSet, ExerciseDef, ExerciseType } from '../types';
|
||||
import { getLastSetForExercise } from '../services/storage';
|
||||
|
||||
interface UseWorkoutFormProps {
|
||||
userId: string;
|
||||
onSetAdded?: (set: WorkoutSet) => void;
|
||||
onUpdateSet?: (set: WorkoutSet) => void;
|
||||
}
|
||||
|
||||
export const useWorkoutForm = ({ userId, onSetAdded, onUpdateSet }: UseWorkoutFormProps) => {
|
||||
const [weight, setWeight] = useState<string>('');
|
||||
const [reps, setReps] = useState<string>('');
|
||||
const [duration, setDuration] = useState<string>('');
|
||||
const [distance, setDistance] = useState<string>('');
|
||||
const [height, setHeight] = useState<string>('');
|
||||
const [bwPercentage, setBwPercentage] = useState<string>('100');
|
||||
|
||||
// Unilateral State
|
||||
const [unilateralSide, setUnilateralSide] = useState<'LEFT' | 'RIGHT'>('LEFT');
|
||||
|
||||
// Editing 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>('');
|
||||
|
||||
const resetForm = () => {
|
||||
setWeight('');
|
||||
setReps('');
|
||||
setDuration('');
|
||||
setDistance('');
|
||||
setHeight('');
|
||||
};
|
||||
|
||||
const updateFormFromLastSet = async (exerciseId: string, exerciseType: ExerciseType, bodyWeightPercentage?: number) => {
|
||||
setBwPercentage(bodyWeightPercentage ? bodyWeightPercentage.toString() : '100');
|
||||
|
||||
const set = await getLastSetForExercise(userId, exerciseId);
|
||||
if (set) {
|
||||
setWeight(set.weight?.toString() || '');
|
||||
setReps(set.reps?.toString() || '');
|
||||
setDuration(set.durationSeconds?.toString() || '');
|
||||
setDistance(set.distanceMeters?.toString() || '');
|
||||
setHeight(set.height?.toString() || '');
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
|
||||
// Clear irrelevant fields
|
||||
if (exerciseType !== ExerciseType.STRENGTH && exerciseType !== ExerciseType.BODYWEIGHT) setWeight('');
|
||||
if (exerciseType !== ExerciseType.STRENGTH && exerciseType !== ExerciseType.BODYWEIGHT && exerciseType !== ExerciseType.PLYOMETRIC) setReps('');
|
||||
if (exerciseType !== ExerciseType.CARDIO && exerciseType !== ExerciseType.STATIC) setDuration('');
|
||||
if (exerciseType !== ExerciseType.CARDIO && exerciseType !== ExerciseType.LONG_JUMP) setDistance('');
|
||||
if (exerciseType !== ExerciseType.HIGH_JUMP) setHeight('');
|
||||
};
|
||||
|
||||
const prepareSetData = (selectedExercise: ExerciseDef, isSporadic: boolean = false) => {
|
||||
const setData: Partial<WorkoutSet> = {
|
||||
exerciseId: selectedExercise.id,
|
||||
};
|
||||
|
||||
if (selectedExercise.isUnilateral) {
|
||||
setData.side = unilateralSide;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return setData;
|
||||
};
|
||||
|
||||
const startEditing = (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 saveEdit = (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) })
|
||||
};
|
||||
if (onUpdateSet) onUpdateSet(updatedSet);
|
||||
setEditingSetId(null);
|
||||
};
|
||||
|
||||
const cancelEdit = () => {
|
||||
setEditingSetId(null);
|
||||
};
|
||||
|
||||
return {
|
||||
weight, setWeight,
|
||||
reps, setReps,
|
||||
duration, setDuration,
|
||||
distance, setDistance,
|
||||
height, setHeight,
|
||||
bwPercentage, setBwPercentage,
|
||||
unilateralSide, setUnilateralSide,
|
||||
editingSetId,
|
||||
editWeight, setEditWeight,
|
||||
editReps, setEditReps,
|
||||
editDuration, setEditDuration,
|
||||
editDistance, setEditDistance,
|
||||
editHeight, setEditHeight,
|
||||
resetForm,
|
||||
updateFormFromLastSet,
|
||||
prepareSetData,
|
||||
startEditing,
|
||||
saveEdit,
|
||||
cancelEdit
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user