feat(v9d): integrate training type UI components
Phase 1b - UI Integration: =========================== ActivityPage: - Replace old activity type dropdown with TrainingTypeSelect - Add training_type_id, training_category, training_subcategory to form - Two-level selection (category → subcategory) Dashboard: - Add TrainingTypeDistribution card (pie chart) - Shows last 28 days activity distribution by type - Conditional rendering (only if activities exist) Still TODO: - History: Add type badge display (next commit) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
df01ee3de3
commit
08cead49fe
|
|
@ -3,6 +3,7 @@ import { Upload, Pencil, Trash2, Check, X, CheckCircle } from 'lucide-react'
|
|||
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid } from 'recharts'
|
||||
import { api } from '../utils/api'
|
||||
import UsageBadge from '../components/UsageBadge'
|
||||
import TrainingTypeSelect from '../components/TrainingTypeSelect'
|
||||
import dayjs from 'dayjs'
|
||||
import 'dayjs/locale/de'
|
||||
dayjs.locale('de')
|
||||
|
|
@ -18,7 +19,10 @@ function empty() {
|
|||
date: dayjs().format('YYYY-MM-DD'),
|
||||
activity_type: 'Traditionelles Krafttraining',
|
||||
duration_min: '', kcal_active: '',
|
||||
hr_avg: '', hr_max: '', rpe: '', notes: ''
|
||||
hr_avg: '', hr_max: '', rpe: '', notes: '',
|
||||
training_type_id: null,
|
||||
training_category: null,
|
||||
training_subcategory: null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,11 +93,19 @@ function EntryForm({ form, setForm, onSave, onCancel, saveLabel='Speichern', sav
|
|||
<input type="date" className="form-input" style={{width:140}} value={form.date} onChange={e=>set('date',e.target.value)}/>
|
||||
<span className="form-unit"/>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label className="form-label">Trainingsart</label>
|
||||
<select className="form-select" value={form.activity_type} onChange={e=>set('activity_type',e.target.value)}>
|
||||
{ACTIVITY_TYPES.map(t=><option key={t} value={t}>{t}</option>)}
|
||||
</select>
|
||||
<div style={{marginBottom:12}}>
|
||||
<TrainingTypeSelect
|
||||
value={form.training_type_id}
|
||||
onChange={(typeId, category, subcategory) => {
|
||||
setForm(f => ({
|
||||
...f,
|
||||
training_type_id: typeId,
|
||||
training_category: category,
|
||||
training_subcategory: subcategory
|
||||
}))
|
||||
}}
|
||||
required={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label className="form-label">Dauer</label>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { useProfile } from '../context/ProfileContext'
|
|||
import { getBfCategory } from '../utils/calc'
|
||||
import TrialBanner from '../components/TrialBanner'
|
||||
import EmailVerificationBanner from '../components/EmailVerificationBanner'
|
||||
import TrainingTypeDistribution from '../components/TrainingTypeDistribution'
|
||||
import { getInterpretation, getStatusColor, getStatusBg } from '../utils/interpret'
|
||||
import Markdown from '../utils/Markdown'
|
||||
import dayjs from 'dayjs'
|
||||
|
|
@ -470,6 +471,20 @@ export default function Dashboard() {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* Training Type Distribution */}
|
||||
{activities.length > 0 && (
|
||||
<div className="card section-gap" style={{marginBottom:16}}>
|
||||
<div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:12}}>
|
||||
<div style={{fontWeight:600,fontSize:13}}>🏋️ Trainingstyp-Verteilung</div>
|
||||
<button style={{background:'none',border:'none',fontSize:12,color:'var(--accent)',cursor:'pointer'}}
|
||||
onClick={()=>nav('/activity')}>
|
||||
Details →
|
||||
</button>
|
||||
</div>
|
||||
<TrainingTypeDistribution days={28} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Latest AI insight */}
|
||||
<div className="card section-gap">
|
||||
<div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:8}}>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user