1. Tailwind migretion. 2. Backend Type Safety. 3. Context Refactoring.

This commit is contained in:
AG
2025-12-07 21:54:32 +02:00
parent e893336d46
commit 57f7ad077e
27 changed files with 1536 additions and 580 deletions

View File

@@ -1,30 +1,18 @@
import React from 'react';
import { WorkoutSession, WorkoutSet, WorkoutPlan, Language } from '../../types';
import { Language } from '../../types';
import { useTracker } from './useTracker';
import IdleView from './IdleView';
import SporadicView from './SporadicView';
import ActiveSessionView from './ActiveSessionView';
interface TrackerProps {
userId: string;
userWeight?: number;
activeSession: WorkoutSession | null;
activePlan: WorkoutPlan | null;
onSessionStart: (plan?: WorkoutPlan, startWeight?: number) => void;
onSessionEnd: () => void;
onSessionQuit: () => void;
onSetAdded: (set: WorkoutSet) => void;
onRemoveSet: (setId: string) => void;
onUpdateSet: (set: WorkoutSet) => void;
onSporadicSetAdded?: () => void;
lang: Language;
}
const Tracker: React.FC<TrackerProps> = (props) => {
const tracker = useTracker(props);
const { isSporadicMode } = tracker;
const { activeSession, lang, onSessionEnd, onSessionQuit, onRemoveSet } = props;
const Tracker: React.FC<TrackerProps> = ({ lang }) => {
const tracker = useTracker({}); // No props needed, hook uses context
const { activeSession, isSporadicMode, onSessionEnd, onSessionQuit, onRemoveSet } = tracker;
if (activeSession) {
return (

View File

@@ -1,36 +1,32 @@
import { useState, useEffect } from 'react';
import { WorkoutSession, WorkoutSet, ExerciseDef, ExerciseType, WorkoutPlan } from '../../types';
import { WorkoutSession, WorkoutSet, ExerciseDef, WorkoutPlan } from '../../types';
import { getExercises, saveExercise, getPlans } from '../../services/storage';
import { api } from '../../services/api';
import { useSessionTimer } from '../../hooks/useSessionTimer';
import { useWorkoutForm } from '../../hooks/useWorkoutForm';
import { usePlanExecution } from '../../hooks/usePlanExecution';
import { useAuth } from '../../context/AuthContext';
import { useActiveWorkout } from '../../context/ActiveWorkoutContext';
import { useSession } from '../../context/SessionContext';
interface UseTrackerProps {
userId: string;
userWeight?: number;
activeSession: WorkoutSession | null;
activePlan: WorkoutPlan | null;
onSessionStart: (plan?: WorkoutPlan, startWeight?: number) => void;
onSessionEnd: () => void;
onSessionQuit: () => void;
onSetAdded: (set: WorkoutSet) => void;
onRemoveSet: (setId: string) => void;
onUpdateSet: (set: WorkoutSet) => void;
onSporadicSetAdded?: () => void;
}
export const useTracker = (props: any) => { // Props ignored/removed
const { currentUser } = useAuth();
const userId = currentUser?.id || '';
const userWeight = currentUser?.profile?.weight;
const {
activeSession,
activePlan,
startSession,
addSet,
updateSet,
quitSession,
endSession,
removeSet
} = useActiveWorkout();
const { refreshData: refreshHistory } = useSession();
export const useTracker = ({
userId,
userWeight,
activeSession,
activePlan,
onSessionStart,
onSessionEnd,
onSetAdded,
onUpdateSet,
onSporadicSetAdded
}: UseTrackerProps) => {
const [exercises, setExercises] = useState<ExerciseDef[]>([]);
const [plans, setPlans] = useState<WorkoutPlan[]>([]);
const [selectedExercise, setSelectedExercise] = useState<ExerciseDef | null>(null);
@@ -56,11 +52,18 @@ export const useTracker = ({
// Hooks
const elapsedTime = useSessionTimer(activeSession);
const form = useWorkoutForm({ userId, onUpdateSet });
// useWorkoutForm needs onUpdateSet. But context updateSet signature might be different?
// context: updateSet(setId, updates). useWorkoutForm expects onUpdateSet(set).
// We can adaptor.
const handleUpdateSetWrapper = (set: WorkoutSet) => {
updateSet(set.id, set);
};
const form = useWorkoutForm({ userId, onUpdateSet: handleUpdateSetWrapper });
const planExec = usePlanExecution({ activeSession, activePlan, exercises });
// Initial Data Load
useEffect(() => {
if (!userId) return;
const loadData = async () => {
const exList = await getExercises(userId);
exList.sort((a, b) => a.name.localeCompare(b.name));
@@ -82,7 +85,7 @@ export const useTracker = ({
// Function to reload Quick Log session
const loadQuickLogSession = async () => {
try {
const response = await api.get('/sessions/quick-log');
const response = await api.get<{ success: boolean; session?: WorkoutSession }>('/sessions/quick-log');
if (response.success && response.session) {
setQuickLogSession(response.session);
}
@@ -125,40 +128,21 @@ export const useTracker = ({
if (plan && plan.description) {
planExec.setShowPlanPrep(plan);
} else {
onSessionStart(plan, parseFloat(userBodyWeight));
startSession(plan, parseFloat(userBodyWeight));
}
};
const confirmPlanStart = () => {
if (planExec.showPlanPrep) {
onSessionStart(planExec.showPlanPrep, parseFloat(userBodyWeight));
startSession(planExec.showPlanPrep, parseFloat(userBodyWeight));
planExec.setShowPlanPrep(null);
}
}
const handleAddSet = async () => {
if (!activeSession || !selectedExercise) return;
const setData = form.prepareSetData(selectedExercise);
try {
const response = await api.post('/sessions/active/log-set', setData);
if (response.success) {
const { newSet, activeExerciseId } = response;
onSetAdded(newSet);
if (activePlan && activeExerciseId) {
const nextStepIndex = activePlan.steps.findIndex(step => step.exerciseId === activeExerciseId);
if (nextStepIndex !== -1) {
planExec.setCurrentStepIndex(nextStepIndex);
}
} else if (activePlan && !activeExerciseId) {
planExec.setCurrentStepIndex(activePlan.steps.length);
}
}
} catch (error) {
console.error("Failed to log set:", error);
}
await addSet(setData);
};
const handleLogSporadicSet = async () => {
@@ -172,7 +156,7 @@ export const useTracker = ({
setTimeout(() => setSporadicSuccess(false), 2000);
loadQuickLogSession();
form.resetForm();
if (onSporadicSetAdded) onSporadicSetAdded();
refreshHistory();
}
} catch (error) {
console.error("Failed to log quick log set:", error);
@@ -255,6 +239,14 @@ export const useTracker = ({
handleCancelEdit,
resetForm,
quickLogSession,
loadQuickLogSession
loadQuickLogSession,
// Pass through context methods for UI to use
onSessionEnd: endSession,
onSessionQuit: quitSession,
onRemoveSet: removeSet,
activeSession // Need this in view
};
};