import { useState } from 'react'
import { ChevronRight, ChevronLeft, Check, X, BookOpen } from 'lucide-react'
import { useNavigate } from 'react-router-dom'
import { api } from '../utils/api'
import { calcBodyFat, getBfCategory, METHOD_POINTS } from '../utils/calc'
import { CIRCUMFERENCE_POINTS, CALIPER_POINTS, CALIPER_METHODS } from '../utils/guideData'
import dayjs from 'dayjs'
// ── Circumference Wizard ──────────────────────────────────────────────────────
function CircumWizard({ onDone, onCancel }) {
const [step, setStep] = useState(0)
const [date, setDate] = useState(dayjs().format('YYYY-MM-DD'))
const [values, setValues] = useState({})
const [saving, setSaving] = useState(false)
const points = CIRCUMFERENCE_POINTS
const current = points[step]
const totalSteps = points.length
const handleNext = () => {
if (step < totalSteps - 1) setStep(s => s + 1)
else handleSave()
}
const handleSave = async () => {
setSaving(true)
try {
const payload = { date }
Object.entries(values).forEach(([k,v]) => { if(v) payload[k] = parseFloat(v) })
await api.upsertCirc(payload)
onDone()
} finally { setSaving(false) }
}
const progress = ((step + 1) / totalSteps) * 100
return (
{/* Header */}
Schritt {step+1} von {totalSteps}
{/* Datum (nur erster Schritt) */}
{step === 0 && (
)}
{/* Messpunkt */}
{/* Punkt-Indikator */}
{step+1}
{current.label}
Umfang messen
{/* Anleitung */}
{[
['📍 Wo', current.where],
['🧍 Haltung', current.posture],
['📏 Maßband', current.how],
['💡 Tipp', current.tip],
].map(([label, text]) => (
))}
{/* Eingabe */}
setValues(v => ({...v, [current.id]: e.target.value}))}
onKeyDown={e => e.key==='Enter' && handleNext()}
autoFocus
/>
cm
{values[current.id] && (
✓ {values[current.id]} cm erfasst
)}
{/* Navigation */}
)
}
// ── Caliper Wizard ────────────────────────────────────────────────────────────
function CaliperWizard({ onDone, onCancel, profile }) {
const [method, setMethod] = useState('jackson3')
const [step, setStep] = useState(-1) // -1 = method select
const [date, setDate] = useState(dayjs().format('YYYY-MM-DD'))
const [values, setValues] = useState({})
const [saving, setSaving] = useState(false)
const sex = profile?.sex || 'm'
const age = profile?.dob ? Math.floor((Date.now()-new Date(profile.dob))/(365.25*24*3600*1000)) : 30
const sfPoints = METHOD_POINTS[method]?.[sex] || []
const current = step >= 0 ? CALIPER_POINTS[sfPoints[step]] : null
const totalSteps = sfPoints.length
// Live BF calculation
const sfVals = {}
sfPoints.forEach(k => { const v=values[`sf_${k}`]; if(v) sfVals[k]=parseFloat(v) })
const bfPct = Object.keys(sfVals).length === sfPoints.length && sfPoints.length > 0
? Math.round(calcBodyFat(method, sfVals, sex, age)*10)/10 : null
const bfCat = bfPct ? getBfCategory(bfPct, sex) : null
const handleNext = () => {
if (step < totalSteps - 1) setStep(s => s+1)
else handleSave()
}
const handleSave = async () => {
setSaving(true)
try {
const payload = { date, sf_method: method }
Object.entries(values).forEach(([k,v]) => { if(v) payload[k]=parseFloat(v) })
if (bfPct) {
payload.body_fat_pct = bfPct
if (profile?.weight || values.weight) {
const w = parseFloat(profile?.weight || values.weight)
payload.lean_mass = Math.round(w*(1-bfPct/100)*10)/10
payload.fat_mass = Math.round(w*(bfPct/100)*10)/10
}
}
await api.upsertCaliper(payload)
onDone()
} finally { setSaving(false) }
}
const progress = step >= 0 ? ((step+1)/totalSteps)*100 : 0
// Method selection screen
if (step === -1) {
return (
Caliper-Methode
setDate(e.target.value)}/>
{Object.entries(CALIPER_METHODS).map(([k,m]) => (
))}
Immer rechte Körperseite · Falte 1 cm abheben · Caliper 2 Sek. · 3× messen, Mittelwert
)
}
return (
{/* Header */}
Punkt {step+1} von {totalSteps} · {CALIPER_METHODS[method]?.label}
{/* Live BF Preview */}
{bfPct && (
{bfPct}%
{bfCat &&
{bfCat.label}
}
Körperfett (live)
)}
{/* Messpunkt */}
{current && (
{step+1}
{current.label}
Hautfalte messen
{[
['📍 Wo', current.where],
['🧍 Haltung', current.posture],
['🔧 Technik', current.how],
['💡 Tipp', current.tip],
].map(([label, text]) => (
))}
setValues(v => ({...v, [`sf_${sfPoints[step]}`]: e.target.value}))}
onKeyDown={e => e.key==='Enter' && handleNext()}
autoFocus
/>
mm
{values[`sf_${sfPoints[step]}`] && (
✓ {values[`sf_${sfPoints[step]}`]} mm erfasst
)}
)}
{/* Navigation */}
)
}
// ── Main Wizard Page ──────────────────────────────────────────────────────────
export default function MeasureWizard() {
const [mode, setMode] = useState(null) // null | 'circum' | 'caliper'
const [done, setDone] = useState(false)
const [profile, setProfile] = useState(null)
const nav = useNavigate()
useState(() => { api.getProfile().then(setProfile) })
if (done) {
return (
✅
Gespeichert!
Deine Messung wurde erfolgreich gespeichert.
)
}
if (mode === 'circum') return (
setDone(true)} onCancel={()=>setMode(null)}/>
)
if (mode === 'caliper') return (
setDone(true)} onCancel={()=>setMode(null)} profile={profile}/>
)
return (
Assistent
Der Assistent führt dich Schritt für Schritt durch die Messung – mit Anleitung für jeden Messpunkt.
💡 Für schnelle Einzeleingaben oder Bearbeitung bestehender Werte nutze die direkten Screens
unter Gewicht, Umfänge und Caliper.
)
}