feat(insights): cycle ring in the wellness strip, bound mood/medication calendar height

Surface the cycle phase ring in the main Insights health-scores strip as a
gated sibling tile. It reuses the cycle wheel SVG, sized to a score-ring
tile, and sources day-of-cycle + phase from the same calendar read +
deriveWheelState the cycle page wheel uses, so the two surfaces never
disagree. Mounted only for a cycle-tracking account (the same /api/auth/me
gate the sidebar nav and the cycle summary card use), so its calendar read
never fires otherwise; it renders nothing while resolving, on error, and
when there is no active cycle — no gap, no placeholder.

Cap the adaptive cell size in the mood and medication compliance heatmaps.
A short window (a single medication, a 30-day mood calendar) left only a
few columns, so the container-width cell sizing ballooned and the square
grid blew the tile to roughly three times its neighbours' height. The cell
ceiling keeps the grid dense and left-aligned within the tile-height rhythm
at mobile and desktop.
This commit is contained in:
Marc-André Bombeck committed 2026-06-06 20:47:47 +02:00
1 parent 2b9d2370e9
commit a9f57af602
12 files changed
+363 -11

No files matched your search

+19
View File
@@ -167,6 +167,19 @@ const CycleInsightSummaryCard = dynamic(
{ ssr: false },
);
// v1.15.3 — the compact cycle RING, dropped into the wellness-score strip as a
// gated sibling tile (NOT the summary teaser — that stays further down). Mounted
// only for a cycle-tracking account, so its calendar read never fires otherwise.
// Deferred behind `next/dynamic`; it renders nothing while resolving / on error /
// when there is no active cycle, so it carries no loading placeholder.
const CycleRingTile = dynamic(
() =>
import("@/components/cycle/cycle-ring-tile").then((mod) => ({
default: mod.CycleRingTile,
})),
{ ssr: false },
);
/**
* v1.4.25 W4d — Insights mother page.
*
@@ -376,6 +389,12 @@ export default function InsightsPage() {
isLoading={dashboardDerived.isLoading}
isError={dashboardDerived.isError}
refetch={dashboardDerived.refetch}
// v1.15.3 — the cycle ring rides the scores strip as a gated sibling
// tile, only for a cycle-tracking account, so its calendar read never
// fires otherwise (the same `/api/auth/me` gate the sidebar nav uses).
extraTile={
user?.cycleTrackingEnabled ? <CycleRingTile /> : undefined
}
/>
{flags.briefing && (