diff --git a/frontend/src/components/ui/StatCard.jsx b/frontend/src/components/ui/StatCard.jsx index 927dfd5..973c0ac 100644 --- a/frontend/src/components/ui/StatCard.jsx +++ b/frontend/src/components/ui/StatCard.jsx @@ -9,7 +9,7 @@ const accentColors = { export default function StatCard({ label, value, accent = 'default', sub }) { return ( -
{label}
{value}
{sub &&{sub}
} diff --git a/frontend/src/pages/DashboardPage.jsx b/frontend/src/pages/DashboardPage.jsx index 14cb395..3347d77 100644 --- a/frontend/src/pages/DashboardPage.jsx +++ b/frontend/src/pages/DashboardPage.jsx @@ -13,7 +13,7 @@ import StatCard from '../components/ui/StatCard' import ActivityMap from '../components/activity/ActivityMap' import { formatDuration, formatDistance, formatHeartRate, formatElevation, - formatDate, sportIcon, formatSleep, + formatDate, sportIcon, sportColor, formatSleep, } from '../utils/format' import { BB_INFERRED_COLOR, BB_INFERRED_LABEL, bbLevelColor, inferBBType } from '../utils/bodyBattery' @@ -278,35 +278,62 @@ function SleepDetail({ health }) { ) } +const sportLabel = s => (s ? s.charAt(0).toUpperCase() + s.slice(1) : 'Other') + function WeeklyChart({ activities }) { const navigate = useNavigate() - const data = useMemo(() => { - if (!activities?.length) return [] + const { data, sports } = useMemo(() => { + if (!activities?.length) return { data: [], sports: [] } + // Sports present, ordered by total distance (largest stacks at the bottom). + const totals = {} + for (const a of activities) totals[a.sport_type] = (totals[a.sport_type] || 0) + (a.distance_m || 0) + const sports = Object.keys(totals).sort((x, y) => totals[y] - totals[x]) const now = new Date() const weeks = eachWeekOfInterval({ start: subWeeks(startOfWeek(now), 7), end: startOfWeek(now) }) - return weeks.map(weekStart => { + const data = weeks.map(weekStart => { const weekEnd = addDays(weekStart, 7) - const km = activities - .filter(a => { const t = new Date(a.start_time); return t >= weekStart && t < weekEnd }) - .reduce((s, a) => s + (a.distance_m || 0) / 1000, 0) - return { week: format(weekStart, 'MMM d'), km: parseFloat(km.toFixed(2)), weekStartISO: format(weekStart, 'yyyy-MM-dd'), weekEndISO: format(weekEnd, 'yyyy-MM-dd') } + const row = { week: format(weekStart, 'MMM d'), weekStartISO: format(weekStart, 'yyyy-MM-dd'), weekEndISO: format(weekEnd, 'yyyy-MM-dd') } + for (const s of sports) row[s] = 0 + for (const a of activities) { + const t = new Date(a.start_time) + if (t >= weekStart && t < weekEnd) row[a.sport_type] += (a.distance_m || 0) / 1000 + } + for (const s of sports) row[s] = +row[s].toFixed(2) + return row }) + return { data, sports } }, [activities]) return (