mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 14:40:52 +00:00
feat(dashboard): the daily-overview band becomes opt-in
The hero renders only when the layout carries the literal heroVisible: true. Legacy blobs without the field, malformed values, and fresh accounts all keep it off; the Settings toggle persists an explicit opt-in through the existing layout PUT.
This commit is contained in:
1 parent
7eeab2ae98
commit
8a5a26b49a
8 files changed
+51
-50
No files matched your search
@@ -7,9 +7,9 @@ import { join } from "node:path";
|
||||
*
|
||||
* The hero band mounts between the page header and the tile strip:
|
||||
*
|
||||
* - it gates on the layout's `heroVisible` flag (anything but the
|
||||
* literal `false` renders — the resolver's clamp) AND on snapshot
|
||||
* mode (the verdict needs the snapshot payload);
|
||||
* - it gates on the layout's `heroVisible` flag (only the literal
|
||||
* `true` renders — the hero is opt-in) AND on snapshot mode (the
|
||||
* verdict needs the snapshot payload);
|
||||
* - while `primaryLoading` is true (same `!mounted ||` pin the tile
|
||||
* silhouettes use) a footprint-identical skeleton holds the band,
|
||||
* so the hero and the tiles swap to content in the SAME render
|
||||
@@ -30,7 +30,7 @@ describe("dashboard hero — page wiring", () => {
|
||||
|
||||
it("gates the hero on snapshot mode + the layout's heroVisible flag", () => {
|
||||
expect(src).toMatch(
|
||||
/const\s+heroVisible\s*=\s*snapshotEnabled\s*&&\s*layout\.heroVisible\s*!==\s*false;/,
|
||||
/const\s+heroVisible\s*=\s*snapshotEnabled\s*&&\s*layout\.heroVisible\s*===\s*true;/,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -477,7 +477,7 @@ describe("PUT /api/dashboard/widgets — heroVisible thread-through", () => {
|
||||
expect(updateArg.data.dashboardWidgetsJson.heroVisible).toBe(false);
|
||||
});
|
||||
|
||||
it("defaults heroVisible to true for a first save with no stored layout", async () => {
|
||||
it("defaults heroVisible to false for a first save with no stored layout", async () => {
|
||||
vi.mocked(prisma.user.findUnique).mockResolvedValue({
|
||||
dashboardWidgetsJson: null,
|
||||
} as never);
|
||||
@@ -495,7 +495,7 @@ describe("PUT /api/dashboard/widgets — heroVisible thread-through", () => {
|
||||
.calls[0]?.[0] as unknown as {
|
||||
data: { dashboardWidgetsJson: { heroVisible: boolean } };
|
||||
};
|
||||
expect(updateArg.data.dashboardWidgetsJson.heroVisible).toBe(true);
|
||||
expect(updateArg.data.dashboardWidgetsJson.heroVisible).toBe(false);
|
||||
});
|
||||
|
||||
it("422s on a non-boolean heroVisible", async () => {
|
||||
|
||||
@@ -283,7 +283,7 @@ export const PUT = apiHandler(async (request: NextRequest) => {
|
||||
mergedChartOverlayPrefs = existingLayout.chartOverlayPrefs ?? {};
|
||||
}
|
||||
if (mergedHeroVisible === undefined) {
|
||||
mergedHeroVisible = existingLayout.heroVisible !== false;
|
||||
mergedHeroVisible = existingLayout.heroVisible === true;
|
||||
}
|
||||
}
|
||||
const normalized = serializeDashboardLayout({
|
||||
|
||||
+2
-2
@@ -709,13 +709,13 @@ export default function DashboardPage() {
|
||||
// hero band (it derives from the snapshot's server-computed
|
||||
// `greetingHour`, so the old client-side Intl hour walk retired
|
||||
// with it). The hero gates on the layout's `heroVisible` flag
|
||||
// (default on; anything but the literal `false` renders) and holds
|
||||
// (opt-in; only the literal `true` renders) and holds
|
||||
// a footprint-identical skeleton while the snapshot is in flight,
|
||||
// so the band swaps in place — no growth, no greeting flash. When
|
||||
// the hero does NOT render (toggle off, or snapshot flag off) the
|
||||
// header takes the greeting back — it must never disappear with the
|
||||
// band.
|
||||
const heroVisible = snapshotEnabled && layout.heroVisible !== false;
|
||||
const heroVisible = snapshotEnabled && layout.heroVisible === true;
|
||||
const heroSnapshot = snapshotQuery.data;
|
||||
|
||||
return (
|
||||
|
||||
Reference in new issue
Block a user