import { useState, useEffect } from 'react'
import { Pencil, Trash2, 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 { CALIPER_POINTS, CALIPER_METHODS } from '../utils/guideData'
import dayjs from 'dayjs'
function emptyForm() {
return {
date: dayjs().format('YYYY-MM-DD'), sf_method:'jackson3', notes:'',
sf_chest:'', sf_axilla:'', sf_triceps:'', sf_subscap:'',
sf_suprailiac:'', sf_abdomen:'', sf_thigh:'',
sf_calf_med:'', sf_lowerback:'', sf_biceps:''
}
}
function CaliperForm({ form, setForm, profile, onSave, onCancel, saveLabel='Speichern' }) {
const sex = profile?.sex||'m'
const age = profile?.dob ? Math.floor((Date.now()-new Date(profile.dob))/(365.25*24*3600*1000)) : 30
const weight = form.weight || 80
const sfPoints = METHOD_POINTS[form.sf_method]?.[sex] || []
const sfVals = {}
sfPoints.forEach(k=>{ const v=form[`sf_${k}`]; if(v!==''&&v!=null) sfVals[k]=parseFloat(v) })
const bfPct = Object.keys(sfVals).length===sfPoints.length&&sfPoints.length>0
? Math.round(calcBodyFat(form.sf_method, sfVals, sex, age)*10)/10 : null
const bfCat = bfPct ? getBfCategory(bfPct, sex) : null
const set = (k,v) => setForm(f=>({...f,[k]:v}))
return (
set('date',e.target.value)}/>
Rechte Körperseite · Falte 1 cm abheben · Caliper 2 Sek. warten · 3× messen, Mittelwert
{sfPoints.map(k=>{
const p = CALIPER_POINTS[k]
return p ? (
set(`sf_${k}`,e.target.value)}/>
mm
) : null
})}
{bfPct!==null && (
{bfPct}%
{bfCat?.label} · {CALIPER_METHODS[form.sf_method]?.label}
)}
set('notes',e.target.value)}/>
{onCancel && }
)
}
export default function CaliperScreen() {
const [entries, setEntries] = useState([])
const [profile, setProfile] = useState(null)
const [form, setForm] = useState(emptyForm())
const [editing, setEditing] = useState(null)
const [saved, setSaved] = useState(false)
const nav = useNavigate()
const load = () => Promise.all([api.listCaliper(), api.getProfile()])
.then(([e,p])=>{ setEntries(e); setProfile(p) })
useEffect(()=>{ load() },[])
const buildPayload = (f, bfPct, sex) => {
const weight = profile?.weight || null
const payload = { date: f.date, sf_method: f.sf_method, notes: f.notes }
Object.entries(f).forEach(([k,v])=>{ if(k.startsWith('sf_')&&v!==''&&v!=null) payload[k]=parseFloat(v) })
if(bfPct!=null) {
payload.body_fat_pct = bfPct
// get latest weight from profile or skip lean/fat
}
return payload
}
const handleSave = async (bfPct, sex) => {
const payload = buildPayload(form, bfPct, sex)
await api.upsertCaliper(payload)
setSaved(true); await load()
setTimeout(()=>setSaved(false),2000)
setForm(emptyForm())
}
const handleUpdate = async (bfPct, sex) => {
const payload = buildPayload(editing, bfPct, sex)
await api.updateCaliper(editing.id, payload)
setEditing(null); await load()
}
const handleDelete = async (id) => {
if(!confirm('Eintrag löschen?')) return
await api.deleteCaliper(id); await load()
}
return (
Caliper
Verlauf ({entries.length})
{entries.length===0 &&
Noch keine Caliper-Messungen.
}
{entries.map((e,i)=>{
const prev = entries[i+1]
const bfCat = e.body_fat_pct ? getBfCategory(e.body_fat_pct, profile?.sex||'m') : null
const isEd = editing?.id===e.id
return (
{isEd ? (
setEditing(null)} saveLabel="Änderungen speichern"/>
) : (
{dayjs(e.date).format('DD. MMMM YYYY')}
{e.body_fat_pct && (
{e.body_fat_pct}%
{bfCat &&
{bfCat.label}}
{prev?.body_fat_pct &&
{e.body_fat_pct}
)}
{e.sf_method} · {CALIPER_METHODS[e.sf_method]?.label}
{e.notes &&
"{e.notes}"
}
)}
)
})}
)
}