Files
gravl/frontend/src/App.jsx
T

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