import { useState, useEffect } from 'react' import { useAuth } from './context/AuthContext' import './App.css' const API_URL = '/api' function App() { const { user, logout } = useAuth() const [view, setView] = useState('program') const [program, setProgram] = useState(null) const [selectedDay, setSelectedDay] = useState(null) const [currentWeek, setCurrentWeek] = useState(1) const [logs, setLogs] = useState({}) const [loading, setLoading] = useState(true) const userId = user?.id || 1 const today = new Date().toISOString().split('T')[0] useEffect(() => { fetchProgram() }, []) const fetchProgram = async () => { try { const res = await fetch(`${API_URL}/programs/1`) const data = await res.json() setProgram(data) setLoading(false) } catch (err) { console.error('Failed to fetch program:', err) setLoading(false) } } const fetchLogs = async (dayId) => { try { const day = program.days.find(d => d.id === dayId) if (!day) return const newLogs = {} for (const exercise of day.exercises) { if (!exercise.id) continue const res = await fetch(`${API_URL}/logs?user_id=${userId}&date=${today}&program_exercise_id=${exercise.id}`) const data = await res.json() newLogs[exercise.id] = data } setLogs(newLogs) } catch (err) { console.error('Failed to fetch logs:', err) } } const fetchProgression = async (programExerciseId) => { try { const res = await fetch(`${API_URL}/progression/${programExerciseId}?user_id=${userId}`) return await res.json() } catch (err) { console.error('Failed to fetch progression:', err) return null } } const logSet = async (programExerciseId, setNumber, weight, reps, completed) => { try { const res = await fetch(`${API_URL}/logs`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user_id: userId, program_exercise_id: programExerciseId, date: today, set_number: setNumber, weight: parseFloat(weight) || 0, reps: parseInt(reps) || 0, completed }) }) const data = await res.json() // Update local logs setLogs(prev => ({ ...prev, [programExerciseId]: [ ...(prev[programExerciseId] || []).filter(l => l.set_number !== setNumber), data ].sort((a, b) => a.set_number - b.set_number) })) } catch (err) { console.error('Failed to log set:', err) } } const startWorkout = (day) => { setSelectedDay(day) setView('workout') fetchLogs(day.id) } if (loading) { return (

Laddar program...

) } if (view === 'workout' && selectedDay) { return ( setView('program')} fetchProgression={fetchProgression} /> ) } return (

🏋️ Gravl

Vecka {currentWeek}

{program?.name || 'Laddar...'}

{program?.description}

Veckans pass

{program?.days?.map((day, idx) => (
startWorkout(day)}>
Dag {day.day_number} {day.name}
{day.exercises?.filter(e => e.name).slice(0, 3).map((ex, i) => ( {ex.name} ))} {day.exercises?.filter(e => e.name).length > 3 && ( +{day.exercises.filter(e => e.name).length - 3} )}
Starta →
))}
) } function WorkoutView({ day, week, logs, onLogSet, onBack, fetchProgression }) { const [progressions, setProgressions] = useState({}) const [expandedExercise, setExpandedExercise] = useState(null) useEffect(() => { loadProgressions() }, [day]) const loadProgressions = async () => { const progs = {} for (const exercise of day.exercises) { if (exercise.id) { progs[exercise.id] = await fetchProgression(exercise.id) } } setProgressions(progs) } const exercises = day.exercises?.filter(e => e.name) || [] return (

{day.name}

Vecka {week} • Dag {day.day_number}
{exercises.map((exercise, idx) => ( setExpandedExercise( expandedExercise === exercise.id ? null : exercise.id )} onLogSet={onLogSet} /> ))}
) } function ExerciseCard({ exercise, logs, progression, expanded, onToggle, onLogSet }) { const [setInputs, setSetInputs] = useState({}) useEffect(() => { // Initialize with suggested weight or last logged const initial = {} for (let i = 1; i <= exercise.sets; i++) { const existingLog = logs.find(l => l.set_number === i) initial[i] = { weight: existingLog?.weight || progression?.suggestedWeight || '', reps: existingLog?.reps || '', completed: existingLog?.completed || false } } setSetInputs(initial) }, [exercise, logs, progression]) const handleInputChange = (setNum, field, value) => { setSetInputs(prev => ({ ...prev, [setNum]: { ...prev[setNum], [field]: value } })) } const handleComplete = (setNum) => { const input = setInputs[setNum] const newCompleted = !input.completed setSetInputs(prev => ({ ...prev, [setNum]: { ...prev[setNum], completed: newCompleted } })) onLogSet(exercise.id, setNum, input.weight, input.reps, newCompleted) } const completedSets = Object.values(setInputs).filter(s => s.completed).length return (

{exercise.name}

{exercise.muscle_group}
{exercise.sets}×{exercise.reps_min}-{exercise.reps_max} {completedSets}/{exercise.sets}
{expanded && (
{progression && (
💡 {progression.reason} {progression.suggestedWeight && ( → {progression.suggestedWeight} kg )}
)}
{Array.from({ length: exercise.sets }, (_, i) => i + 1).map(setNum => { const input = setInputs[setNum] || { weight: '', reps: '', completed: false } return (
Set {setNum}
handleInputChange(setNum, 'weight', e.target.value)} className="weight-input" inputMode="decimal" /> × handleInputChange(setNum, 'reps', e.target.value)} className="reps-input" inputMode="numeric" />
) })}
)}
) } export default App