mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
53 lines
2.4 KiB
TypeScript
53 lines
2.4 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* S2 — client cell for the unified daily digest (`GET /api/daily/digest`).
|
|
*
|
|
* The Today hero reads the ALREADY-CACHED `DailyDigest` DTO S1 assembled
|
|
* server-side. This hook is a plain GET of that cached route — it never
|
|
* warms a provider, never triggers a fresh AI call (the whole daily-value
|
|
* system's warm-on-mount ban extends here); the route composes from the
|
|
* nightly-cached briefing + dashboard snapshot ingredients.
|
|
*
|
|
* Gating: `enabled` is caller-supplied so the page can fold in the
|
|
* `insights` module flag (the digest is the AI-narrative daily layer;
|
|
* the route returns 403 `module.disabled` when insights is off) and the
|
|
* auth state. Freshness mirrors the dashboard snapshot cadence — a warm
|
|
* return-to-dashboard within the `staleTime` is a free cache hit, and a
|
|
* background sync surfaces on focus/poll — so the two above-the-fold
|
|
* cells refresh in lockstep without a second request storm.
|
|
*
|
|
* The read unwraps the `{ data, error }` envelope through `apiGet`
|
|
* (`(await res.json()).data`), and the queryKey is the centralised
|
|
* factory entry `queryKeys.dailyDigest()`.
|
|
*/
|
|
import { useQuery } from "@tanstack/react-query";
|
|
|
|
import { apiGet } from "@/lib/api/api-fetch";
|
|
import { queryKeys } from "@/lib/query-keys";
|
|
import { DASHBOARD_REFETCH_INTERVAL_MS } from "@/lib/queries/refetch-interval";
|
|
import { retryOnceOnTransientError } from "@/lib/queries/retry-transient";
|
|
import type { DailyDigest } from "@/lib/daily/digest";
|
|
|
|
export function useDailyDigest(enabled = true) {
|
|
return useQuery({
|
|
queryKey: queryKeys.dailyDigest(),
|
|
queryFn: () => apiGet<DailyDigest>("/api/daily/digest"),
|
|
enabled,
|
|
// Match the dashboard snapshot's freshness so the hero and the tile
|
|
// strip share one refresh cadence. Every real window-focus transition
|
|
// refetches even inside the minute freshness window: arrival markers are
|
|
// written out-of-band by sync workers, so the browser has no mutation it
|
|
// could use to invalidate this cache. The 120 s foreground poll remains the
|
|
// fallback while the tab stays open.
|
|
staleTime: 60_000,
|
|
refetchOnMount: false,
|
|
refetchOnWindowFocus: "always",
|
|
refetchInterval: DASHBOARD_REFETCH_INTERVAL_MS,
|
|
refetchIntervalInBackground: false,
|
|
// One retry on transient network / 5xx (never 401/403) so a single
|
|
// blip doesn't collapse the hero to its empty degrade.
|
|
retry: retryOnceOnTransientError,
|
|
});
|
|
}
|