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 => ( ))}
Not at allVery 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}
))}
)} {/* 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}
))}
)} {/* 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 => ( ))} {(parq.heart || parq.joints || parq.meds) && (
⚠️ We recommend checking with your doctor before starting. This won't stop you — just be mindful.
)}
)} {/* Step 3: Body Metrics */} {step === 3 && (

About you

Optional — helps estimate nutrition needs.

setAge(e.target.value)} placeholder="e.g. 35" />
setHeightCm(e.target.value)} placeholder="175" />
setWeightKg(e.target.value)} placeholder="80" />
)} {/* 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 })} />
)} {/* Step 5: Activities + Equipment */} {step === 5 && (

What sounds fun?

Pick all that interest you.

{ACTIVITIES.map(a => (
toggleActivity(a)}>{a}
))}
{EQUIPMENT.map(e => (
setEquipment(e.value)}> {e.label}
))}
)} {/* Step 6: Define Rewards */} {step === 6 && (

Define your rewards

What guilty pleasures do you want to earn?

{rewards.map((r, i) => (
{ const next = [...rewards]; next[i] = { ...r, name: e.target.value }; setRewards(next) }} /> { const next = [...rewards]; next[i] = { ...r, cost: parseInt(e.target.value) || 0 }; setRewards(next) }} />
))}
)} {/* 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 ↗
))}
)}
) }