import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { api } from '../api'
const GOALS = [
{ value: 'lose_weight', label: 'Lose Weight', icon: '⚖️' },
{ value: 'build_strength', label: 'Build Strength', icon: '💪' },
{ value: 'get_active', label: 'Get More Active', icon: '🏃' },
{ value: 'feel_better', label: 'Feel Better Overall', icon: '😊' },
]
const TTM_STAGES = [
{ value: 'precontemplation', label: "I'm not exercising and haven't thought about starting" },
{ value: 'contemplation', label: "I've been thinking about getting more active but haven't started" },
{ value: 'preparation', label: 'I do some exercise but not consistently' },
{ value: 'action', label: "I've been exercising regularly for a few months" },
{ value: 'maintenance', label: "I've been exercising regularly for 6+ months" },
]
const ACTIVITIES = [
'Walking', 'Hiking', 'Running', 'Cycling', 'Swimming',
'Bodyweight', 'Weights', 'Yoga', 'Martial Arts', 'Dance', 'Team Sports',
]
const EQUIPMENT = [
{ value: 'none', label: 'Nothing — bodyweight only' },
{ value: 'basic_home', label: 'Basic home equipment' },
{ value: 'full_gym', label: 'Full gym access' },
]
export default function Onboarding() {
const [step, setStep] = useState(0)
const [goal, setGoal] = useState('')
const [ttm, setTtm] = useState('')
const [age, setAge] = useState('')
const [heightCm, setHeightCm] = useState('')
const [weightKg, setWeightKg] = useState('')
const [gender, setGender] = useState('')
const [parq, setParq] = useState({ heart: false, joints: false, meds: false })
const [motivation, setMotivation] = useState({ ext: 0, intro: 0, ident: 0, intr: 0, amot: 0 })
const [activities, setActivities] = useState([])
const [equipment, setEquipment] = useState('none')
const [daysPerWeek, setDaysPerWeek] = useState(3)
const [minsPerSession, setMinsPerSession] = useState(30)
const [rewards, setRewards] = useState([{ name: '', cost: 100 }])
const [recommendations, setRecommendations] = useState([])
const [loading, setLoading] = useState(false)
const navigate = useNavigate()
const totalSteps = 8
function Likert({ label, value, onChange }) {
return (
{label}
{[1, 2, 3, 4, 5].map(n => (
onChange(n)}>
{n}
))}
Not at all Very true
)
}
async function handlePhase1() {
setLoading(true)
try {
await api.savePhase1({ primary_goal: goal, ttm_stage: ttm })
setStep(2)
} catch (err) { alert(err.message) }
finally { setLoading(false) }
}
async function handlePhase2() {
setLoading(true)
try {
await api.savePhase2({
age: age ? parseInt(age) : null,
height_cm: heightCm ? parseFloat(heightCm) : null,
weight_kg: weightKg ? parseFloat(weightKg) : null,
gender: gender || null,
parq_heart_condition: parq.heart,
parq_joint_issues: parq.joints,
parq_medications: parq.meds,
motivation_external: motivation.ext || null,
motivation_introjected: motivation.intro || null,
motivation_identified: motivation.ident || null,
motivation_intrinsic: motivation.intr || null,
motivation_amotivation: motivation.amot || null,
activity_preferences: activities.map(a => a.toLowerCase().replace(/ /g, '_')),
equipment_access: equipment,
days_per_week: daysPerWeek,
minutes_per_session: minsPerSession,
})
// Create rewards
for (const r of rewards) {
if (r.name.trim()) {
await api.createReward({ name: r.name, point_cost: r.cost || 100 })
}
}
// Get recommendations
const recs = await api.getRecommendations()
setRecommendations(recs.recommendations || [])
setStep(7)
} catch (err) { alert(err.message) }
finally { setLoading(false) }
}
async function handleCommit(rec) {
try {
const today = new Date()
const monday = new Date(today)
monday.setDate(today.getDate() + ((8 - today.getDay()) % 7 || 7))
const startDate = monday.toISOString().split('T')[0]
await api.createProgram({
name: rec.name,
source: rec.source,
source_url: rec.url,
start_date: startDate,
duration_days: rec.duration_days || 90,
})
navigate('/')
} catch (err) { alert(err.message) }
}
function toggleActivity(a) {
setActivities(prev => prev.includes(a) ? prev.filter(x => x !== a) : [...prev, a])
}
// Progress bar
const progress = Math.round(((step + 1) / totalSteps) * 100)
return (
{/* Step 0: Goal */}
{step === 0 && (
What matters most to you?
Pick one — you can change this anytime.
{GOALS.map(g => (
setGoal(g.value)}>
{g.icon}
{g.label}
))}
setStep(1)}>Continue
)}
{/* Step 1: TTM Stage */}
{step === 1 && (
Where are you now?
Be honest — there's no wrong answer.
{TTM_STAGES.map(s => (
setTtm(s.value)}
>{s.label}
))}
{loading ? '...' : 'Continue'}
)}
{/* Step 2: Safety (PAR-Q+) */}
{step === 2 && (
Quick health check
For your safety — this takes 10 seconds.
{[
{ key: 'heart', label: 'I have a heart condition or high blood pressure' },
{ key: 'joints', label: 'I have bone or joint problems that could worsen with exercise' },
{ key: 'meds', label: 'I take prescription medications for a chronic condition' },
].map(q => (
setParq({ ...parq, [q.key]: e.target.checked })} style={{ width: 'auto' }} />
{q.label}
))}
{(parq.heart || parq.joints || parq.meds) && (
⚠️ We recommend checking with your doctor before starting. This won't stop you — just be mindful.
)}
setStep(3)}>Continue
)}
{/* Step 3: Body Metrics */}
{step === 3 && (
About you
Optional — helps estimate nutrition needs.
Age
setAge(e.target.value)} placeholder="e.g. 35" />
Gender
setGender(e.target.value)}>
Prefer not to say
Male
Female
setStep(4)}>Skip
setStep(4)}>Continue
)}
{/* Step 4: Motivation (BREQ-2) */}
{step === 4 && (
What drives you?
Rate each honestly — helps us calibrate your experience.
setMotivation({ ...motivation, ext: v })} />
setMotivation({ ...motivation, intro: v })} />
setMotivation({ ...motivation, ident: v })} />
setMotivation({ ...motivation, intr: v })} />
setMotivation({ ...motivation, amot: v })} />
setStep(5)}>Continue
)}
{/* Step 5: Activities + Equipment */}
{step === 5 && (
What sounds fun?
Pick all that interest you.
{ACTIVITIES.map(a => (
toggleActivity(a)}>{a}
))}
Equipment access
{EQUIPMENT.map(e => (
setEquipment(e.value)}>
{e.label}
))}
Days/week
setDaysPerWeek(parseInt(e.target.value))}>
{[1, 2, 3, 4, 5, 6, 7].map(n => {n} )}
Minutes/session
setMinsPerSession(parseInt(e.target.value))}>
{[15, 20, 30, 45, 60, 90].map(n => {n} )}
setStep(6)}>Continue
)}
{/* Step 6: Define Rewards */}
{step === 6 && (
)}
{/* Step 7: Recommendations + Commit */}
{step === 7 && (
Recommended for you
Pick a program and commit to 90 days.
{recommendations.map(rec => (
{rec.name}
{rec.difficulty} • {rec.duration_days ? `${rec.duration_days} days` : 'Ongoing'} • {rec.source}
{rec.description}
View ↗
handleCommit(rec)}>Select & Commit
))}
navigate('/')}>Skip for now
)}
)
}