Add Dashboard with weekly calendar and today's workout
- Dashboard.jsx: main landing page after login - Coach greeting based on time of day - Weekly calendar showing workout days - Today's workout card with exercises - Quick stats (workouts/week, streak) - Upcoming workouts list - Full responsive CSS - App.jsx updated to show Dashboard first
This commit is contained in:
+15
-69
@@ -1,34 +1,30 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useAuth } from './context/AuthContext'
|
||||
import Dashboard from './pages/Dashboard'
|
||||
import './App.css'
|
||||
|
||||
const API_URL = '/api'
|
||||
|
||||
function App() {
|
||||
const { user, logout } = useAuth()
|
||||
const [view, setView] = useState('program')
|
||||
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(true)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const userId = user?.id || 1
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
|
||||
useEffect(() => {
|
||||
fetchProgram()
|
||||
}, [])
|
||||
|
||||
const fetchProgram = async () => {
|
||||
if (program) return // Already loaded
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,21 +86,19 @@ function App() {
|
||||
}
|
||||
}
|
||||
|
||||
const startWorkout = (day) => {
|
||||
const startWorkout = async (day) => {
|
||||
await fetchProgram() // Ensure program is loaded
|
||||
setSelectedDay(day)
|
||||
setView('workout')
|
||||
fetchLogs(day.id)
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="app loading">
|
||||
<div className="spinner"></div>
|
||||
<p>Laddar program...</p>
|
||||
</div>
|
||||
)
|
||||
// Dashboard view (default after login)
|
||||
if (view === 'dashboard') {
|
||||
return <Dashboard onStartWorkout={startWorkout} />
|
||||
}
|
||||
|
||||
// Workout view
|
||||
if (view === 'workout' && selectedDay) {
|
||||
return (
|
||||
<WorkoutView
|
||||
@@ -112,65 +106,17 @@ function App() {
|
||||
week={currentWeek}
|
||||
logs={logs}
|
||||
onLogSet={logSet}
|
||||
onBack={() => setView('program')}
|
||||
onBack={() => setView('dashboard')}
|
||||
fetchProgression={fetchProgression}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
// Fallback loading
|
||||
return (
|
||||
<div className="app">
|
||||
<header className="header">
|
||||
<div className="header-left">
|
||||
<h1>🏋️ Gravl</h1>
|
||||
<button className="logout-btn" onClick={logout}>Logga ut</button>
|
||||
</div>
|
||||
<div className="week-selector">
|
||||
<button
|
||||
onClick={() => setCurrentWeek(w => Math.max(1, w - 1))}
|
||||
disabled={currentWeek === 1}
|
||||
>
|
||||
←
|
||||
</button>
|
||||
<span>Vecka {currentWeek}</span>
|
||||
<button
|
||||
onClick={() => setCurrentWeek(w => Math.min(program?.weeks || 6, w + 1))}
|
||||
disabled={currentWeek === (program?.weeks || 6)}
|
||||
>
|
||||
→
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main className="main">
|
||||
<section className="program-info">
|
||||
<h2>{program?.name || 'Laddar...'}</h2>
|
||||
<p>{program?.description}</p>
|
||||
</section>
|
||||
|
||||
<section className="days-list">
|
||||
<h3>Veckans pass</h3>
|
||||
{program?.days?.map((day, idx) => (
|
||||
<div key={day.id} className="day-card" onClick={() => startWorkout(day)}>
|
||||
<div className="day-header">
|
||||
<span className="day-number">Dag {day.day_number}</span>
|
||||
<span className="day-name">{day.name}</span>
|
||||
</div>
|
||||
<div className="day-exercises">
|
||||
{day.exercises?.filter(e => e.name).slice(0, 3).map((ex, i) => (
|
||||
<span key={i} className="exercise-tag">{ex.name}</span>
|
||||
))}
|
||||
{day.exercises?.filter(e => e.name).length > 3 && (
|
||||
<span className="exercise-tag more">+{day.exercises.filter(e => e.name).length - 3}</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="day-action">
|
||||
Starta →
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</section>
|
||||
</main>
|
||||
<div className="app loading">
|
||||
<div className="spinner"></div>
|
||||
<p>Laddar...</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user