mitai-jinkendo/frontend/src/pages/GuidePage.jsx
Lars Stommer 89b6c0b072
Some checks are pending
Deploy to Raspberry Pi / deploy (push) Waiting to run
Build Test / build-frontend (push) Waiting to run
Build Test / lint-backend (push) Waiting to run
feat: initial commit – Mitai Jinkendo v9a
2026-03-16 13:35:11 +01:00

115 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from 'react'
import { ChevronDown, ChevronUp } from 'lucide-react'
import { CIRCUMFERENCE_POINTS, CALIPER_POINTS, CALIPER_METHODS } from '../utils/guideData'
function PointCard({ point, index }) {
const [open, setOpen] = useState(false)
return (
<div style={{border:`1px solid ${open ? point.color : 'var(--border)'}`,borderRadius:10,marginBottom:8,overflow:'hidden',transition:'border-color 0.15s'}}>
<div style={{display:'flex',alignItems:'center',gap:10,padding:'11px 14px',cursor:'pointer',background: open ? 'var(--surface2)' : 'var(--surface)'}}
onClick={() => setOpen(o => !o)}>
<div style={{width:28,height:28,borderRadius:'50%',background:point.color,display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
<span style={{fontSize:12,fontWeight:700,color:'white'}}>{index+1}</span>
</div>
<span style={{flex:1,fontSize:14,fontWeight:500}}>{point.label}</span>
{open ? <ChevronUp size={16} color="var(--text3)"/> : <ChevronDown size={16} color="var(--text3)"/>}
</div>
{open && (
<div style={{padding:'12px 14px',borderTop:'1px solid var(--border)',background:'var(--surface)'}}>
{[['📍 Wo', point.where], ['🧍 Haltung', point.posture], ['📏 Band', point.how], ['💡 Tipp', point.tip]].map(([label, val]) => (
<div key={label} style={{display:'grid',gridTemplateColumns:'90px 1fr',gap:'4px 8px',marginBottom:8}}>
<span style={{fontSize:11,fontWeight:600,color:'var(--text3)',textTransform:'uppercase',letterSpacing:'0.04em',paddingTop:2}}>{label}</span>
<span style={{fontSize:13,color:'var(--text2)',lineHeight:1.55}}>{val}</span>
</div>
))}
</div>
)}
</div>
)
}
export default function GuidePage() {
const [tab, setTab] = useState('circum')
const [caliperMethod, setCaliperMethod] = useState('jackson3')
const sex = 'm' // could read from profile
const methodPoints = CALIPER_METHODS[caliperMethod]?.points_m || []
return (
<div>
<h1 className="page-title">Messanleitung</h1>
<div className="tabs">
<button className={'tab' + (tab === 'circum' ? ' active' : '')} onClick={() => setTab('circum')}>Umfänge</button>
<button className={'tab' + (tab === 'caliper' ? ' active' : '')} onClick={() => setTab('caliper')}>Caliper</button>
<button className={'tab' + (tab === 'tips' ? ' active' : '')} onClick={() => setTab('tips')}>Allgemein</button>
</div>
{tab === 'circum' && (
<div>
<div style={{padding:'10px 14px',background:'var(--accent-light)',borderRadius:10,marginBottom:14,fontSize:13,color:'var(--accent-dark)',lineHeight:1.6}}>
Klicke auf einen Messpunkt für genaue Anleitung zu Körperhaltung und Messung.
</div>
{CIRCUMFERENCE_POINTS.map((p, i) => <PointCard key={p.id} point={p} index={i}/>)}
</div>
)}
{tab === 'caliper' && (
<div>
<div style={{marginBottom:14}}>
<div style={{fontSize:13,fontWeight:600,color:'var(--text3)',marginBottom:6}}>METHODE WÄHLEN</div>
<div style={{display:'flex',flexDirection:'column',gap:6}}>
{Object.entries(CALIPER_METHODS).map(([key, m]) => (
<button key={key} onClick={() => setCaliperMethod(key)}
style={{padding:'9px 14px',borderRadius:10,border:`1.5px solid ${caliperMethod===key?'var(--accent)':'var(--border2)'}`,
background: caliperMethod===key?'var(--accent-light)':'var(--surface)',
color: caliperMethod===key?'var(--accent-dark)':'var(--text2)',
fontFamily:'var(--font)',fontSize:13,fontWeight:500,textAlign:'left',cursor:'pointer',
display:'flex',justifyContent:'space-between',alignItems:'center'}}>
<span>{m.label}</span>
<span style={{fontSize:11,opacity:0.7}}>{m.points_m.length} Punkte</span>
</button>
))}
</div>
</div>
<div style={{padding:'10px 14px',background:'var(--warn-bg)',borderRadius:10,marginBottom:14,fontSize:13,color:'var(--warn-text)',lineHeight:1.6}}>
<strong>Caliper-Grundregel:</strong> Immer rechte Körperseite · Falte 1 cm neben dem Punkt abheben · Caliper 1 cm neben Fingern ansetzen · 2 Sek. warten · 3× messen, Mittelwert nehmen
</div>
{methodPoints.map((id, i) => {
const p = CALIPER_POINTS[id]
if (!p) return null
return <PointCard key={id} point={p} index={i}/>
})}
</div>
)}
{tab === 'tips' && (
<div>
{[
{ icon:'🌅', title:'Zeitpunkt', text:'Immer morgens nüchtern messen vor dem Frühstück und vor dem Sport. Zu festen Zeiten messen für vergleichbare Werte.' },
{ icon:'👗', title:'Kleidung', text:'Immer in vergleichbarer Unterwäsche oder ohne Kleidung messen. Kleidung kann die Werte verfälschen.' },
{ icon:'📏', title:'Maßband', text:'Maßband flach und waagerecht anlegen parallel zum Boden. Weder spannen noch locker lassen. 1 Finger Luft bei Hals-Messungen.' },
{ icon:'🔢', title:'Wiederholungen', text:'Jeden Wert 2× messen und den Durchschnitt notieren. Bei Abweichungen über 1 cm eine dritte Messung machen.' },
{ icon:'💧', title:'Wassereinlagerungen', text:'Nicht nach dem Sport, nach Alkohol, oder bei Krankheit messen. Beine schwellen gegen Abend an Wade morgens messen.' },
{ icon:'📅', title:'Intervall', text:'Wöchentliche oder zweiwöchentliche Messungen reichen. Tägliche Schwankungen von 12 kg sind normal und nicht aussagekräftig.' },
{ icon:'📸', title:'Fortschrittsfotos', text:'Fotos bei gleicher Beleuchtung und gleichem Hintergrund machen. Morgendlich nüchtern, gleiche Pose, gleiche Kamera-Distanz.' },
{ icon:'🔬', title:'Caliper vs. Maßband', text:'Caliper misst Unterhautfett direkt genauer als Umfänge allein. Umfänge erfassen die Gesamtgröße inklusive Muskeln. Beide Werte kombiniert geben das vollständigste Bild.' },
].map(item => (
<div key={item.title} className="card section-gap">
<div style={{display:'flex',gap:12,alignItems:'flex-start'}}>
<span style={{fontSize:22,flexShrink:0}}>{item.icon}</span>
<div>
<div style={{fontWeight:600,fontSize:14,marginBottom:4}}>{item.title}</div>
<div style={{fontSize:13,color:'var(--text2)',lineHeight:1.6}}>{item.text}</div>
</div>
</div>
</div>
))}
</div>
)}
</div>
)
}