mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 22:50:51 +00:00
fix(daily): refresh the Today digest after a dose, drop the hero ring cluster
The Today digest went stale after logging a dose: nothing invalidated the `["daily","digest"]` query, and it reads meds from the same server snapshot the intake routes already hard-evict — so the "dose due" rail item lingered until a hard reload. Add the digest key to the medication-dependent bundle and force the inactive digest (unmounted while the user is on the medication card) to refetch alongside the dashboard snapshot; the server snapshot eviction seam is reused, so the refetch returns post-write dose state immediately. Remove the score-ring cluster from the Today hero — it read as uneven and wasted tile space. The health-score ring is the hero's only ring now; the score-ring selection contract stays server-side for the native client. Tighten the hero's vertical rhythm so the worth-a-look rail sits close under the lead instead of floating below a half-empty column. Wire the remaining sleep transports into the morning-refresh trigger: Google Health, Fitbit, Oura, and Polar now enqueue the debounced morning refresh on a last-night segment landing, matching the Withings / WHOOP / Apple seams — those sources had no trigger at all. Make the trigger observable: each early-return gate now annotates a distinct `daily.morning_refresh.skipped` reason (the not-last-night gate also carries the samples' resolved local dates, today's key and the tz) so a real landing shows exactly which gate fired. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018V8V9qapgHi7fhgtMJ8SkM
This commit is contained in:
1 parent
f8c0ea5120
commit
65f90160c7
20 files changed
+350
-210
No files matched your search
+5
-29
@@ -27,11 +27,8 @@ import { convertGlucose, resolveGlucoseUnit } from "@/lib/glucose";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
resolveDashboardLayout,
|
||||
resolveHeroRingOrder,
|
||||
HEALTH_SCORE_RING_ID,
|
||||
type DashboardLayout,
|
||||
} from "@/lib/dashboard-layout";
|
||||
import type { DashboardScoreRing } from "@/lib/dashboard/score-rings";
|
||||
import type { DashboardAnalyticsData as AnalyticsData } from "@/types/analytics";
|
||||
import dynamic from "next/dynamic";
|
||||
import Link from "next/link";
|
||||
@@ -235,31 +232,10 @@ export default function DashboardPageClient() {
|
||||
const insightsEnabled = useModuleEnabled("insights");
|
||||
const digestQuery = useDailyDigest(isAuthenticated && insightsEnabled);
|
||||
|
||||
// v1.29.0 — the Settings-picked hero score rings, resurfaced on the Today
|
||||
// hero. The snapshot resolves the selection server-side (data- and
|
||||
// module-gated, selection order preserved); `resolveHeroRingOrder`
|
||||
// reconciles the user's persisted drag order against what actually
|
||||
// resolved — the SAME reconciler the Settings picker uses. The
|
||||
// health-score ring stays the hero's fixed anchor, so its position in the
|
||||
// stored order is skipped here; the legacy non-snapshot path carries no
|
||||
// resolved rings and degrades to the health ring alone.
|
||||
const heroScoreRings = useMemo<DashboardScoreRing[]>(() => {
|
||||
const snap = snapshotQuery.data;
|
||||
const rings = snap?.scoreRings ?? [];
|
||||
if (rings.length === 0) return [];
|
||||
const order = resolveHeroRingOrder(
|
||||
snap?.layout?.heroRingOrder,
|
||||
rings.map((r) => r.id),
|
||||
);
|
||||
const byId = new Map(rings.map((r) => [r.id, r]));
|
||||
const ordered: DashboardScoreRing[] = [];
|
||||
for (const id of order) {
|
||||
if (id === HEALTH_SCORE_RING_ID) continue;
|
||||
const ring = byId.get(id);
|
||||
if (ring) ordered.push(ring);
|
||||
}
|
||||
return ordered;
|
||||
}, [snapshotQuery.data]);
|
||||
// v1.29.1 — the v1.29.0 selected-score-ring cluster is removed from the web
|
||||
// hero (Marc, live-use: uneven, wasted tile space). The snapshot still
|
||||
// resolves `scoreRings` server-side for the iOS selection contract; the web
|
||||
// hero just no longer renders them, so no client-side ring ordering here.
|
||||
|
||||
const analyticsSlimQuery = useAnalyticsQuery({
|
||||
slice: "summaries",
|
||||
@@ -812,7 +788,7 @@ export default function DashboardPageClient() {
|
||||
(!mounted || digestQuery.isLoading ? (
|
||||
<TodayHeroSkeleton />
|
||||
) : digestQuery.data ? (
|
||||
<TodayHero digest={digestQuery.data} rings={heroScoreRings} />
|
||||
<TodayHero digest={digestQuery.data} />
|
||||
) : null)}
|
||||
|
||||
{/* v1.18.6 — the spotlight tour launcher moved to the app-shell
|
||||
|
||||
Reference in new issue
Block a user