182 lines
4.8 KiB
React
182 lines
4.8 KiB
React
import { useState } from 'react'
|
|
import { useAuth } from './context/AuthContext'
|
|
import Dashboard from './pages/Dashboard'
|
|
import ProfilePage from './pages/ProfilePage'
|
|
import ProgressPage from './pages/ProgressPage'
|
|
import WorkoutPage from './pages/WorkoutPage'
|
|
import WorkoutSelectPage from './pages/WorkoutSelectPage'
|
|
import ChatOnboarding from './pages/ChatOnboarding'
|
|
import './App.css'
|
|
|
|
const API_URL = '/api'
|
|
|
|
function App() {
|
|
const { user, logout } = useAuth()
|
|
const [view, setView] = useState('dashboard')
|
|
const [program, setProgram] = useState(null)
|
|
const [selectedDay, setSelectedDay] = useState(null)
|
|
const [currentWeek, setCurrentWeek] = useState(1)
|
|
const [logs, setLogs] = useState({})
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
const userId = user?.id || 1
|
|
const today = new Date().toISOString().split('T')[0]
|
|
|
|
if (user && !user.onboarding_complete) {
|
|
return <ChatOnboarding />
|
|
}
|
|
|
|
const fetchProgram = async () => {
|
|
if (program) return // Already loaded
|
|
try {
|
|
const res = await fetch(`${API_URL}/programs/1`)
|
|
const data = await res.json()
|
|
setProgram(data)
|
|
} catch (err) {
|
|
console.error('Failed to fetch program:', err)
|
|
}
|
|
}
|
|
|
|
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 deleteLog = async (programExerciseId, setNumber) => {
|
|
try {
|
|
await fetch(`${API_URL}/logs`, {
|
|
method: 'DELETE',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
user_id: userId,
|
|
program_exercise_id: programExerciseId,
|
|
date: today,
|
|
set_number: setNumber
|
|
})
|
|
})
|
|
// Remove from local logs state
|
|
setLogs(prev => ({
|
|
...prev,
|
|
[programExerciseId]: (prev[programExerciseId] || []).filter(l => l.set_number !== setNumber)
|
|
}))
|
|
} catch (err) {
|
|
console.error('Failed to delete log:', err)
|
|
}
|
|
}
|
|
|
|
const startWorkout = async (day) => {
|
|
await fetchProgram() // Ensure program is loaded
|
|
setSelectedDay(day)
|
|
setView('workout')
|
|
fetchLogs(day.id)
|
|
}
|
|
|
|
// Dashboard view (default after login)
|
|
if (view === 'dashboard') {
|
|
return (
|
|
<Dashboard
|
|
onStartWorkout={startWorkout}
|
|
onNavigate={setView}
|
|
/>
|
|
)
|
|
}
|
|
|
|
// Profile page
|
|
if (view === 'profile') {
|
|
return <ProfilePage onBack={() => setView('dashboard')} />
|
|
}
|
|
|
|
// Progress page
|
|
if (view === 'progress') {
|
|
return <ProgressPage onBack={() => setView('dashboard')} />
|
|
}
|
|
|
|
// Workout select page
|
|
if (view === 'select-workout') {
|
|
return (
|
|
<WorkoutSelectPage
|
|
onBack={() => setView('dashboard')}
|
|
onSelectWorkout={startWorkout}
|
|
/>
|
|
)
|
|
}
|
|
|
|
// Workout view
|
|
if (view === 'workout' && selectedDay) {
|
|
return (
|
|
<WorkoutPage
|
|
day={selectedDay}
|
|
week={currentWeek}
|
|
logs={logs}
|
|
onLogSet={logSet}
|
|
onDeleteSet={deleteLog}
|
|
onBack={() => setView('dashboard')}
|
|
fetchProgression={fetchProgression}
|
|
/>
|
|
)
|
|
}
|
|
|
|
// Fallback loading
|
|
return (
|
|
<div className="app loading">
|
|
<div className="spinner"></div>
|
|
<p>Laddar...</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default App
|