diff --git a/src/hooks/use-insight-status.ts b/src/hooks/use-insight-status.ts index 8b404d355..0ac0bc3ef 100644 --- a/src/hooks/use-insight-status.ts +++ b/src/hooks/use-insight-status.ts @@ -163,3 +163,59 @@ export function useInsightStatus(metric: InsightStatusMetric) { ), }); } + +/** + * v1.8.7.1 — generic per-metric assessment loader for the HealthKit + * metric sub-pages. The seven bespoke metrics above (`weight`, `pulse`, + * …) each own a hand-written `/api/insights/-status` route; the + * ~29 HealthKit pages instead share one generic route keyed by the + * metric id: + * + * GET /api/insights/metric-status?metric=&locale= + * + * where METRIC_ID is the existing HealthKit measurement identifier + * (`HEART_RATE_VARIABILITY`, `RESTING_HEART_RATE`, `SLEEP_DURATION`, …). + * The response envelope, the 8 s client ceiling, the no-retry policy and + * the bounded `preparing` poll are identical to `useInsightStatus` — the + * card consumes the same `InsightStatusData` shape for every scope. + * + * `enabled` lets the page suppress the fetch entirely when the metric has + * no data (the page renders the insufficient-data empty state instead of + * the card), so a brand-new account never fires an assessment round-trip. + */ +export function useInsightMetricStatus(metric: string, enabled = true) { + const { isAuthenticated } = useAuth(); + const { locale } = useTranslations(); + + return useQuery({ + queryKey: queryKeys.insightsMetricStatus(metric, locale), + queryFn: async (): Promise => { + const controller = new AbortController(); + const timeoutHandle = setTimeout( + () => controller.abort(), + STATUS_TIMEOUT_MS, + ); + try { + const res = await fetch( + `/api/insights/metric-status?metric=${encodeURIComponent( + metric, + )}&locale=${locale}`, + { signal: controller.signal }, + ); + if (!res.ok) throw new Error("Failed"); + const json = (await res.json()) as { data: InsightStatusData }; + return json.data; + } finally { + clearTimeout(timeoutHandle); + } + }, + enabled: isAuthenticated && enabled, + staleTime: 60 * 1000, + retry: 0, + refetchInterval: (query) => + nextStatusPollInterval( + query.state.data?.preparing, + query.state.dataUpdateCount, + ), + }); +} diff --git a/src/lib/query-keys.ts b/src/lib/query-keys.ts index dc967e3aa..0aeae6832 100644 --- a/src/lib/query-keys.ts +++ b/src/lib/query-keys.ts @@ -103,6 +103,16 @@ export const queryKeys = { ["insights", "mood-status", locale] as const, insightsMedicationComplianceStatus: (locale: string) => ["insights", "medication-compliance-status", locale] as const, + /** + * v1.8.7.1 — per-metric insight assessment for the HealthKit metric + * sub-pages. One generic route (`/api/insights/metric-status?metric=…`) + * backs every HealthKit metric, so the key is parameterised by the + * metric id alongside the locale rather than minting a bespoke factory + * entry per metric. The seven bespoke `*-status` routes above keep + * their own keys; this one covers the ~29 generic HealthKit pages. + */ + insightsMetricStatus: (metric: string, locale: string) => + ["insights", "metric-status", metric, locale] as const, medications: () => ["medications"] as const, medicationDetail: (id: string) => ["medications", id] as const,