diff --git a/src/app/__tests__/dashboard-tile-strip-skeleton.test.ts b/src/app/__tests__/dashboard-tile-strip-skeleton.test.ts index 856ec16e1..95d1926f2 100644 --- a/src/app/__tests__/dashboard-tile-strip-skeleton.test.ts +++ b/src/app/__tests__/dashboard-tile-strip-skeleton.test.ts @@ -105,10 +105,11 @@ describe("resolveDashboardFirstPaintGate", () => { describe("resolveConfiguredTileCount (v1.16.8)", () => { it("counts only widgets that paint a strip tile, with bp counting double", () => { // Default layout: weight, bp, pulse, bodyFat, mood, bpInTarget, vo2Max - // are tile-visible AND tile-capable; medications + recentWorkouts are - // tile-visible in the stored layout but paint NO strip tile, so - // they must not inflate the silhouette. bp paints sys + dia = 2. - expect(resolveConfiguredTileCount(DEFAULT_DASHBOARD_LAYOUT)).toBe(8); + // plus the v1.20.0 sleep / steps / glucose flips are tile-visible AND + // tile-capable; medications + recentWorkouts are tile-visible in the + // stored layout but paint NO strip tile, so they must not inflate the + // silhouette. bp paints sys + dia = 2. + expect(resolveConfiguredTileCount(DEFAULT_DASHBOARD_LAYOUT)).toBe(11); }); it("ignores chart-only and iOS-pin-only widget ids", () => { @@ -139,9 +140,10 @@ describe("resolveConfiguredTileCount (v1.16.8)", () => { describe("resolveChartRowPlaceholderCount (v1.16.8)", () => { it("reserves one cell per chart-visible chart-capable widget", () => { // Default layout chart row: weight, bp, pulse, bodyFat, mood, - // medications are `visible`; bpInTarget / achievements / - // recentWorkouts carry no chart-shaped footprint. - expect(resolveChartRowPlaceholderCount(DEFAULT_DASHBOARD_LAYOUT)).toBe(6); + // medications are `visible`, plus the v1.20.0 vorsorge flip + // (chart-row only); bpInTarget / achievements / recentWorkouts carry + // no chart-shaped footprint. + expect(resolveChartRowPlaceholderCount(DEFAULT_DASHBOARD_LAYOUT)).toBe(7); }); it("adds the BMI cell riding the weight gate when a height is known", () => { @@ -149,7 +151,7 @@ describe("resolveChartRowPlaceholderCount (v1.16.8)", () => { resolveChartRowPlaceholderCount(DEFAULT_DASHBOARD_LAYOUT, { hasHeightCm: true, }), - ).toBe(7); + ).toBe(8); }); it("respects a trimmed layout", () => { diff --git a/src/lib/__tests__/dashboard-layout.test.ts b/src/lib/__tests__/dashboard-layout.test.ts index 9ccf98a25..8772cca2f 100644 --- a/src/lib/__tests__/dashboard-layout.test.ts +++ b/src/lib/__tests__/dashboard-layout.test.ts @@ -469,16 +469,29 @@ describe("DASHBOARD_WIDGET_CATALOGUE_IDS — 27-id catalogue", () => { expect(new Set(DASHBOARD_WIDGET_CATALOGUE_IDS).size).toBe(36); }); - it("registers the Vorsorge widget default-off on both surfaces", () => { - // v1.18.2 — Vorsorge becomes a first-class dashboard widget like - // medications: chart-row only, default-invisible so existing - // dashboards are unchanged until the user opts in. + it("ships the sleep / steps / glucose strip tiles default-on (v1.20.0)", () => { + // These modules are on by default and their tiles self-gate on having + // data in page.tsx, so accounts that sync sleep / step / glucose data + // discover the tiles on / without hunting through Settings. The chart + // rows stay off because those charts live on the /insights sub-pages. + for (const id of ["sleep", "steps", "glucose"]) { + const widget = DEFAULT_DASHBOARD_LAYOUT.widgets.find((w) => w.id === id); + expect(widget).toBeDefined(); + expect(widget?.tileVisible).toBe(true); + expect(widget?.visible).toBe(false); + } + }); + + it("registers the Vorsorge widget chart-row default-on (v1.20.0)", () => { + // v1.18.2 — Vorsorge is a first-class chart-row widget (no strip tile). + // v1.20.0 flipped it default-visible so preventive-care reminders + // surface on /; it self-gates and renders nothing without due reminders. expect(DASHBOARD_WIDGET_IDS).toContain("vorsorge"); const entry = DEFAULT_DASHBOARD_LAYOUT.widgets.find( (w) => w.id === "vorsorge", ); expect(entry).toBeDefined(); - expect(entry?.visible).toBe(false); + expect(entry?.visible).toBe(true); expect(entry?.tileVisible).toBe(false); }); diff --git a/src/lib/dashboard-layout.ts b/src/lib/dashboard-layout.ts index a6ff10679..40d16536f 100644 --- a/src/lib/dashboard-layout.ts +++ b/src/lib/dashboard-layout.ts @@ -367,9 +367,21 @@ export const DEFAULT_DASHBOARD_LAYOUT: DashboardLayout = { { id: "mood", visible: true, tileVisible: true, order: 4 }, { id: "bpInTarget", visible: true, tileVisible: true, order: 5 }, { id: "medications", visible: true, tileVisible: true, order: 6 }, - { id: "sleep", visible: false, tileVisible: false, order: 7 }, - { id: "steps", visible: false, tileVisible: false, order: 8 }, - { id: "glucose", visible: false, tileVisible: false, order: 9 }, + // v1.20.0 — sleep / steps / glucose strip tiles default-on so accounts + // that sync these signals discover them on / without hunting through + // Settings → Dashboard. Each follows the VO2max precedent: the strip + // tile is on (`tileVisible: true`) and self-gates on having data + // (`hasSleep` / `hasSteps` / `showGlucoseCards` in page.tsx), so an + // empty account still gets a clean dashboard. The chart row stays off + // (`visible: false`) — those charts live on the /insights sub-pages. + { id: "sleep", visible: false, tileVisible: true, order: 7 }, + { id: "steps", visible: false, tileVisible: true, order: 8 }, + { id: "glucose", visible: false, tileVisible: true, order: 9 }, + // totalBodyWater / boneMass / oxygenSaturation carry as catalogue ids + // for the iOS layout round-trip only — they have no web render block or + // data-floor flag in page.tsx, so flipping their defaults would surface + // nothing on web. Their data IS discoverable via the /insights sub-pages. + // Kept false until a web render path lands (see .planning/v1200-backlog.md). { id: "totalBodyWater", visible: false, tileVisible: false, order: 10 }, { id: "boneMass", visible: false, tileVisible: false, order: 11 }, { id: "oxygenSaturation", visible: false, tileVisible: false, order: 12 }, @@ -411,8 +423,10 @@ export const DEFAULT_DASHBOARD_LAYOUT: DashboardLayout = { { id: "falls", visible: false, tileVisible: false, order: 22 }, { id: "walkingSteadiness", visible: false, tileVisible: false, order: 23 }, // v1.18.2 — Vorsorge summary card. Chart-row only (no strip tile), so - // `tileVisible` is forced false; default-invisible until opt-in. - { id: "vorsorge", visible: false, tileVisible: false, order: 24 }, + // `tileVisible` is forced false. v1.20.0 — flipped `visible: true` so + // preventive-care reminders surface on / by default; the card self-gates + // (see page.tsx) and shows nothing for accounts without due reminders. + { id: "vorsorge", visible: true, tileVisible: false, order: 24 }, ], };