fix(insights): correct the active-energy assessment id and share the status card

The active-energy page passed `ACTIVE_ENERGY_BURNED` as `statusMetric`, but
that is the DB MeasurementType, not the registry id the metric-status route
accepts. The route's closed enum only knows `ACTIVE_ENERGY`, so every fetch
422'd and the assessment card silently fell back to its empty body.

Point the page at the `ACTIVE_ENERGY` registry id and type `statusMetric`
(plus the `useInsightMetricStatus` metric param) to the closed
`MetricStatusMetricId` union instead of a bare string, so a future
MeasurementType-vs-registry-id mismatch is a compile error rather than a
silent 422. A typecheck pass over all 29 pages confirms active-energy was the
only diverging one.

Extract a shared `MetricStatusCard` that owns the `useInsightMetricStatus`
hook and the assessment-card wiring, collapsing the duplicated mount block in
the HealthKit metric scaffold and the bespoke sleep page to a single line
each (only the icon differs). Behaviour is unchanged: the card mounts only on
the data-bearing branch, so a source-less account never fires an assessment
round-trip. Add a test asserting the active-energy page wires an accepted
registry id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit 6e371aaeb9698f7b4251c22e1d8f381ddfa70a00)
This commit is contained in:
Marc-André Bombeck committed 2026-06-02 14:03:00 +02:00
1 parent 5827ef58cb
commit 58b793ee4a
6 files changed
+112 -48

No files matched your search

+1 -1
View File
@@ -17,7 +17,7 @@ export default function InsightsActiveEnergyPage() {
return (
<HealthKitMetricPage
measurementType="ACTIVE_ENERGY_BURNED"
statusMetric="ACTIVE_ENERGY_BURNED"
statusMetric="ACTIVE_ENERGY"
insightMetric="ACTIVE_ENERGY_BURNED"
chartKey="activeEnergy"
i18nPrefix="insights.activeEnergy"
+8 -22
View File
@@ -3,11 +3,10 @@
import Link from "next/link";
import { Moon } from "lucide-react";
import { useInsightMetricStatus } from "@/hooks/use-insight-status";
import { useInsightsAnalytics } from "@/hooks/use-insights-analytics";
import { useTranslations } from "@/lib/i18n/context";
import { Button } from "@/components/ui/button";
import { InsightStatusCard } from "@/components/insights/insight-status-card";
import { MetricStatusCard } from "@/components/insights/metric-status-card";
import { MetricEmptyState } from "@/components/insights/metric-empty-state";
import { MetricTargetSummary } from "@/components/insights/metric-target-summary";
import { SleepOverview } from "@/components/insights/sleep-overview";
@@ -34,16 +33,6 @@ export default function InsightsSchlafPage() {
const { isEmpty } = useInsightsAnalytics("SLEEP_DURATION");
// v1.8.7.1 — the per-section sleep assessment now rides the generic
// metric-status route, keyed by `SLEEP_DURATION`. The hook runs on every
// render but only fetches once the page has data (the empty branch below
// short-circuits before the card mounts), so a source-less account never
// fires an assessment round-trip.
const { data: status, isLoading: isStatusLoading } = useInsightMetricStatus(
"SLEEP_DURATION",
!isEmpty,
);
if (isEmpty) {
return (
<SubPageShell
@@ -82,18 +71,15 @@ export default function InsightsSchlafPage() {
{/*
v1.8.7.1 — the per-section sleep assessment lands via the generic
metric-status route (`?metric=SLEEP_DURATION`), closing the slot
the v1.4.28 deferral left open. The card consumes the same
`InsightStatusData` envelope every sibling sub-page reads.
the v1.4.28 deferral left open. The shared `<MetricStatusCard>`
owns the hook + card; only the icon differs from the HealthKit
scaffold (Moon vs Sparkles). The card mounts only on this
data-bearing branch, so a source-less account never fetches.
*/}
<InsightStatusCard
title={t("insights.assessmentTitle")}
<MetricStatusCard
metric="SLEEP_DURATION"
icon={<Moon className="h-5 w-5" />}
text={status?.text ?? null}
hasProvider={status?.hasProvider ?? false}
cached={status?.cached ?? false}
updatedAt={status?.updatedAt ?? null}
loading={isStatusLoading}
preparing={status?.preparing ?? false}
enabled={!isEmpty}
/>
</SubPageShell>
);