globaler Filter für Qualitätsgates von Trainings #41

Merged
Lars merged 8 commits from develop into main 2026-03-24 08:44:22 +01:00
Showing only changes of commit 5796c6a21a - Show all commits

View File

@ -589,23 +589,13 @@ function NutritionSection({ nutrition, weights, profile, insights, onRequest, lo
// Activity Section // Activity Section
function ActivitySection({ activities, insights, onRequest, loadingSlug, filterActiveSlugs, globalQualityLevel }) { function ActivitySection({ activities, insights, onRequest, loadingSlug, filterActiveSlugs, globalQualityLevel }) {
const [period, setPeriod] = useState(30) const [period, setPeriod] = useState(30)
// Issue #31: Use global quality filter from profile as default
const [qualityLevel, setQualityLevel] = useState(globalQualityLevel || 'all')
if (!activities?.length) return ( if (!activities?.length) return (
<EmptySection text="Noch keine Aktivitätsdaten." to="/activity" toLabel="Aktivität erfassen"/> <EmptySection text="Noch keine Aktivitätsdaten." to="/activity" toLabel="Aktivität erfassen"/>
) )
const cutoff = dayjs().subtract(period,'day').format('YYYY-MM-DD') const cutoff = dayjs().subtract(period,'day').format('YYYY-MM-DD')
// Issue #24: Mehrstufiger Quality-Filter // Issue #31: Backend already filters by global quality level - only filter by period here
const filtA = activities.filter(d => { const filtA = activities.filter(d => period === 9999 || d.date >= cutoff)
if (period !== 9999 && d.date < cutoff) return false
if (qualityLevel === 'all') return true
if (qualityLevel === 'quality') return ['excellent', 'good', 'acceptable'].includes(d.quality_label)
if (qualityLevel === 'very_good') return ['excellent', 'good'].includes(d.quality_label)
if (qualityLevel === 'excellent') return d.quality_label === 'excellent'
return true
})
const byDate={} const byDate={}
filtA.forEach(a=>{ byDate[a.date]=(byDate[a.date]||0)+(a.kcal_active||0) }) filtA.forEach(a=>{ byDate[a.date]=(byDate[a.date]||0)+(a.kcal_active||0) })
@ -634,36 +624,26 @@ function ActivitySection({ activities, insights, onRequest, loadingSlug, filterA
<SectionHeader title="🏋️ Aktivität" to="/activity" toLabel="Alle Einträge" lastUpdated={activities[0]?.date}/> <SectionHeader title="🏋️ Aktivität" to="/activity" toLabel="Alle Einträge" lastUpdated={activities[0]?.date}/>
<PeriodSelector value={period} onChange={setPeriod}/> <PeriodSelector value={period} onChange={setPeriod}/>
{/* Issue #24: Mehrstufiger Quality-Filter */} {/* Issue #31: Show active global quality filter */}
<div style={{marginBottom:12}}> {globalQualityLevel && globalQualityLevel !== 'all' && (
<div style={{fontSize:11,fontWeight:600,color:'var(--text3)',marginBottom:6}}>QUALITÄTSFILTER</div> <div style={{
<div style={{display:'flex',gap:4}}> marginBottom:12, padding:'8px 12px', borderRadius:8,
{[ background:'var(--surface2)', border:'1px solid var(--border)',
{v:'all', l:'Alle', icon:'📊'}, fontSize:12, color:'var(--text2)', display:'flex', alignItems:'center', gap:8
{v:'quality', l:'Hochwertig', icon:'✓'}, }}>
{v:'very_good', l:'Sehr gut', icon:'✓✓'}, <span>
{v:'excellent', l:'Exzellent', icon:'⭐'} {globalQualityLevel === 'quality' && '✓ Filter: Hochwertig (excellent, good, acceptable)'}
].map(o => ( {globalQualityLevel === 'very_good' && '✓✓ Filter: Sehr gut (excellent, good)'}
<button key={o.v} onClick={() => setQualityLevel(o.v)} {globalQualityLevel === 'excellent' && '⭐ Filter: Exzellent (nur excellent)'}
style={{flex:1,padding:'6px 8px',borderRadius:8,fontSize:11,fontWeight:500, </span>
border:'1.5px solid',cursor:'pointer',fontFamily:'var(--font)',transition:'all 0.2s', <a href="/settings" style={{
background:qualityLevel===o.v?'var(--accent)':'transparent', marginLeft:'auto', color:'var(--accent)', textDecoration:'none',
borderColor:qualityLevel===o.v?'var(--accent)':'var(--border2)', fontSize:11, fontWeight:500, whiteSpace:'nowrap'
color:qualityLevel===o.v?'white':'var(--text2)'}}> }}>
<span style={{marginRight:4}}>{o.icon}</span> Hier ändern
{o.l} </a>
</button>
))}
</div>
{qualityLevel !== 'all' && (
<div style={{fontSize:10,color:'var(--text3)',marginTop:6}}>
{filtA.length} von {activities.filter(d=>period===9999||d.date>=cutoff).length} Aktivitäten
{qualityLevel === 'quality' && ' (excellent, good, acceptable)'}
{qualityLevel === 'very_good' && ' (excellent, good)'}
{qualityLevel === 'excellent' && ' (nur excellent)'}
</div> </div>
)} )}
</div>
<div style={{display:'flex',gap:6,marginBottom:12}}> <div style={{display:'flex',gap:6,marginBottom:12}}>
{[['Trainings',filtA.length,'var(--text1)'],['Kcal',totalKcal,'#EF9F27'], {[['Trainings',filtA.length,'var(--text1)'],['Kcal',totalKcal,'#EF9F27'],