Final Feature 9c #10
|
|
@ -598,26 +598,62 @@ function OverviewCards({ data }) {
|
|||
|
||||
// ── Chart: Kalorien vs Gewicht ────────────────────────────────────────────────
|
||||
function CaloriesVsWeight({ data }) {
|
||||
const filtered = data.filter(d => d.kcal && d.weight)
|
||||
const withAvg = rollingAvg(filtered.map(d=>({...d,date:dayjs(d.date).format('DD.MM')})), 'kcal')
|
||||
// BUG-003 fix: Show all weight data, extrapolate kcal if missing
|
||||
const filtered = data.filter(d => d.kcal || d.weight)
|
||||
if (filtered.length < 3) return (
|
||||
<div style={{padding:20,textAlign:'center',color:'var(--text3)',fontSize:13}}>
|
||||
Zu wenig gemeinsame Daten (Gewicht + Kalorien am selben Tag nötig)
|
||||
Zu wenig Daten für diese Auswertung
|
||||
</div>
|
||||
)
|
||||
|
||||
// Find last real kcal value
|
||||
const lastKcalIndex = filtered.findLastIndex(d => d.kcal)
|
||||
const lastKcal = lastKcalIndex >= 0 ? filtered[lastKcalIndex].kcal : null
|
||||
|
||||
// Extrapolate missing kcal values at the end
|
||||
const withExtrapolated = filtered.map((d, i) => ({
|
||||
...d,
|
||||
kcal: d.kcal || (i > lastKcalIndex && lastKcal ? lastKcal : null),
|
||||
isKcalExtrapolated: !d.kcal && i > lastKcalIndex && lastKcal
|
||||
}))
|
||||
|
||||
// Format dates and calculate rolling average
|
||||
const formatted = withExtrapolated.map(d => ({
|
||||
...d,
|
||||
date: dayjs(d.date).format('DD.MM')
|
||||
}))
|
||||
const withAvg = rollingAvg(formatted, 'kcal')
|
||||
|
||||
// Split into real and extrapolated segments for dashed lines
|
||||
const realData = withAvg.map(d => ({
|
||||
...d,
|
||||
kcal_extrap: d.isKcalExtrapolated ? d.kcal : null,
|
||||
kcal_avg_extrap: d.isKcalExtrapolated ? d.kcal_avg : null,
|
||||
kcal: d.isKcalExtrapolated ? null : d.kcal,
|
||||
kcal_avg: d.isKcalExtrapolated ? null : d.kcal_avg
|
||||
}))
|
||||
|
||||
return (
|
||||
<ResponsiveContainer width="100%" height={220}>
|
||||
<LineChart data={withAvg} margin={{top:4,right:8,bottom:0,left:-16}}>
|
||||
<LineChart data={realData} margin={{top:4,right:8,bottom:0,left:-16}}>
|
||||
<CartesianGrid stroke="var(--border)" strokeDasharray="3 3"/>
|
||||
<XAxis dataKey="date" tick={{fontSize:9,fill:'var(--text3)'}} tickLine={false}
|
||||
interval={Math.max(0,Math.floor(withAvg.length/6)-1)}/>
|
||||
interval={Math.max(0,Math.floor(realData.length/6)-1)}/>
|
||||
<YAxis yAxisId="kcal" tick={{fontSize:9,fill:'var(--text3)'}} tickLine={false} domain={['auto','auto']}/>
|
||||
<YAxis yAxisId="weight" orientation="right" tick={{fontSize:9,fill:'var(--text3)'}} tickLine={false} domain={['auto','auto']}/>
|
||||
<Tooltip contentStyle={{background:'var(--surface)',border:'1px solid var(--border)',borderRadius:8,fontSize:11}}
|
||||
formatter={(v,n)=>[`${Math.round(v)} ${n==='weight'?'kg':'kcal'}`, n==='kcal_avg'?'Ø 7T Kalorien':n==='weight'?'Gewicht':'Kalorien']}/>
|
||||
<Line yAxisId="kcal" type="monotone" dataKey="kcal" stroke="#EF9F2744" strokeWidth={1} dot={false}/>
|
||||
<Line yAxisId="kcal" type="monotone" dataKey="kcal_avg" stroke="#EF9F27" strokeWidth={2} dot={false} name="kcal_avg"/>
|
||||
<Line yAxisId="weight" type="monotone" dataKey="weight" stroke="#378ADD" strokeWidth={2} dot={{r:3,fill:'#378ADD'}} name="weight"/>
|
||||
formatter={(v,n)=>[`${Math.round(v)} ${n==='weight'?'kg':'kcal'}`, n.includes('avg')?'Ø 7T Kalorien':n==='weight'?'Gewicht':'Kalorien']}/>
|
||||
|
||||
{/* Real kcal values - solid lines */}
|
||||
<Line yAxisId="kcal" type="monotone" dataKey="kcal" stroke="#EF9F2744" strokeWidth={1} dot={false} connectNulls={false}/>
|
||||
<Line yAxisId="kcal" type="monotone" dataKey="kcal_avg" stroke="#EF9F27" strokeWidth={2} dot={false} name="kcal_avg" connectNulls={false}/>
|
||||
|
||||
{/* Extrapolated kcal values - dashed lines */}
|
||||
<Line yAxisId="kcal" type="monotone" dataKey="kcal_extrap" stroke="#EF9F2744" strokeWidth={1} strokeDasharray="3 3" dot={false} connectNulls={false}/>
|
||||
<Line yAxisId="kcal" type="monotone" dataKey="kcal_avg_extrap" stroke="#EF9F27" strokeWidth={2} strokeDasharray="3 3" dot={false} connectNulls={false}/>
|
||||
|
||||
{/* Weight - always solid */}
|
||||
<Line yAxisId="weight" type="monotone" dataKey="weight" stroke="#378ADD" strokeWidth={2} dot={{r:3,fill:'#378ADD'}} name="weight" connectNulls={true}/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user