import React, { createContext, useContext, useState, useEffect } from 'react'; import { WorkoutSession, WorkoutPlan, WorkoutSet } from '../types'; import { useAuth } from './AuthContext'; import { getSessions, getPlans, getActiveSession, saveSession, deleteSession, updateActiveSession, deleteActiveSession, deleteSetFromActiveSession, updateSetInActiveSession } from '../services/storage'; import { getCurrentUserProfile, getMe } from '../services/auth'; import { generateId } from '../utils/uuid'; import { logWeight } from '../services/weight'; import { useNavigate } from 'react-router-dom'; interface DataContextType { sessions: WorkoutSession[]; plans: WorkoutPlan[]; activeSession: WorkoutSession | null; activePlan: WorkoutPlan | null; startSession: (plan?: WorkoutPlan, startWeight?: number) => Promise; endSession: () => Promise; quitSession: () => Promise; addSet: (set: WorkoutSet) => void; removeSet: (setId: string) => Promise; updateSet: (updatedSet: WorkoutSet) => Promise; updateSession: (updatedSession: WorkoutSession) => void; deleteSessionById: (sessionId: string) => void; refreshData: () => Promise; } const DataContext = createContext(undefined); export const DataProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const { currentUser, updateUser } = useAuth(); const navigate = useNavigate(); const [sessions, setSessions] = useState([]); const [plans, setPlans] = useState([]); const [activeSession, setActiveSession] = useState(null); const [activePlan, setActivePlan] = useState(null); const refreshData = async () => { if (currentUser) { const s = await getSessions(currentUser.id); setSessions(s); const p = await getPlans(currentUser.id); setPlans(p); } else { setSessions([]); setPlans([]); } }; useEffect(() => { refreshData(); }, [currentUser]); // Restore active session useEffect(() => { const restoreActive = async () => { if (currentUser) { const session = await getActiveSession(currentUser.id); if (session) { setActiveSession(session); if (session.planId) { // Ensure plans are loaded or fetch specifically const currentPlans = plans.length > 0 ? plans : await getPlans(currentUser.id); const plan = currentPlans.find(p => p.id === session.planId); if (plan) setActivePlan(plan); } } } }; restoreActive(); }, [currentUser]); // Dependency logic might need tuning, but this matches App.tsx roughly const startSession = async (plan?: WorkoutPlan, startWeight?: number) => { if (!currentUser || activeSession) return; const profile = getCurrentUserProfile(currentUser.id); const currentWeight = startWeight || profile?.weight || 70; const newSession: WorkoutSession = { id: generateId(), startTime: Date.now(), type: 'STANDARD', userBodyWeight: currentWeight, sets: [], planId: plan?.id, planName: plan?.name }; setActivePlan(plan || null); setActiveSession(newSession); navigate('/'); await saveSession(currentUser.id, newSession); if (startWeight) { await logWeight(startWeight); } }; const endSession = async () => { if (activeSession && currentUser) { const finishedSession = { ...activeSession, endTime: Date.now() }; await updateActiveSession(currentUser.id, finishedSession); setSessions(prev => [finishedSession, ...prev]); setActiveSession(null); setActivePlan(null); const res = await getMe(); if (res.success && res.user) { updateUser(res.user); } } }; const quitSession = async () => { if (currentUser) { await deleteActiveSession(currentUser.id); setActiveSession(null); setActivePlan(null); } }; const addSet = (set: WorkoutSet) => { if (activeSession) { const updatedSession = { ...activeSession, sets: [...activeSession.sets, set] }; setActiveSession(updatedSession); // Context update is optimistic, actual save usually happens in hooks or components? // In App.tsx handleAddSet only updated local state. // Wait, useTracker usually handles saving sets via API? // In App.tsx: handleAddSet just set state. // useTracker.ts calls onSetAdded, but ALSO calls api to save it? // Let's look at useTracker.ts. // handleLogSet in useTracker calls API then onSetAdded. // So this state update is mainly for UI sync in App. } }; const removeSet = async (setId: string) => { if (activeSession && currentUser) { await deleteSetFromActiveSession(currentUser.id, setId); const updatedSession = { ...activeSession, sets: activeSession.sets.filter(s => s.id !== setId) }; setActiveSession(updatedSession); } }; const updateSet = async (updatedSet: WorkoutSet) => { if (activeSession && currentUser) { const response = await updateSetInActiveSession(currentUser.id, updatedSet.id, updatedSet); const updatedSession = { ...activeSession, sets: activeSession.sets.map(s => s.id === updatedSet.id ? response : s) }; setActiveSession(updatedSession); } }; const updateSession = (updatedSession: WorkoutSession) => { if (!currentUser) return; saveSession(currentUser.id, updatedSession); setSessions(prev => prev.map(s => s.id === updatedSession.id ? updatedSession : s)); }; const deleteSessionById = (sessionId: string) => { if (!currentUser) return; deleteSession(currentUser.id, sessionId); setSessions(prev => prev.filter(s => s.id !== sessionId)); }; return ( {children} ); }; export const useData = () => { const context = useContext(DataContext); if (context === undefined) { throw new Error('useData must be used within a DataProvider'); } return context; };