mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
chore(release): v1.28.44 — loose ends: broken link, API contract, module guards
From the campaign's dead-code + code-health audits (grep-verified; the custom-metrics query-key finding was verified-false and excluded): - sleep-overview empty-state CTA linked to /settings/devices, not a valid settings slug (dynamicParams=false → 404). Repointed to /settings/integrations (where every device OAuth callback already lands). - six live, iOS-consumed routes were absent from docs/api/openapi.yaml — auth/check-user, insights/cards, integrations/healthkit (GET+PATCH), measurement-categories, medications/intake/bulk, mood-entries/bulk — registered in the Zod OpenAPI registry mirroring each handler's real shape. - mood/labs/medications module pages lacked the redirect-when-off self-guard their siblings have; added, mirroring cycle/achievements exactly. No migration. Verifier REJECTED the custom-metrics bare-key finding (they are invalidateQueries prefix filters, not colliding useQuery keys).
This commit is contained in:
1 parent
8b6024f0d7
commit
cd0fbddd1d
17 files changed
+1433
-16
No files matched your search
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* The sleep-overview empty-state CTA must point at a REAL settings slug.
|
||||
* It previously linked to `/settings/devices`, which is not in
|
||||
* `SETTINGS_SECTION_SLUGS`, so the dynamic `[section]` route (dynamicParams
|
||||
* = false) calls `notFound()` → a hard 404 dead-end. This pins the href to
|
||||
* the `integrations` slug (where every device OAuth callback lands) and
|
||||
* guards against a regression to any non-existent slug.
|
||||
*/
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { isSettingsSectionSlug } from "@/components/settings/section-slugs";
|
||||
|
||||
describe("sleep-overview empty-state CTA href", () => {
|
||||
it("links to /settings/integrations (a real settings slug)", () => {
|
||||
const source = readFileSync(
|
||||
join(process.cwd(), "src/components/insights/sleep-overview.tsx"),
|
||||
"utf8",
|
||||
);
|
||||
const match = source.match(/href="\/settings\/([a-z-]+)"/);
|
||||
expect(
|
||||
match,
|
||||
"expected a /settings/<slug> href in the sleep overview",
|
||||
).not.toBeNull();
|
||||
const slug = match![1];
|
||||
expect(slug).toBe("integrations");
|
||||
expect(isSettingsSectionSlug(slug)).toBe(true);
|
||||
});
|
||||
|
||||
it("never links to the non-existent /settings/devices slug", () => {
|
||||
const source = readFileSync(
|
||||
join(process.cwd(), "src/components/insights/sleep-overview.tsx"),
|
||||
"utf8",
|
||||
);
|
||||
expect(source).not.toContain("/settings/devices");
|
||||
});
|
||||
});
|
||||
@@ -66,9 +66,9 @@ function SleepStageStackedBar(
|
||||
*
|
||||
* Empty state: no SLEEP_DURATION rows yet → render the "Apple Health
|
||||
* sync is coming in v1.5" message with a deep-link to Settings →
|
||||
* Devices so the user can prepare. We do NOT render any of the three
|
||||
* blocks in that case — half-rendered empty cards would be worse than
|
||||
* a single clean CTA.
|
||||
* Integrations so the user can connect a sleep source. We do NOT render
|
||||
* any of the three blocks in that case — half-rendered empty cards would
|
||||
* be worse than a single clean CTA.
|
||||
*/
|
||||
|
||||
interface SleepAnalyticsSummary {
|
||||
@@ -111,7 +111,7 @@ export function SleepOverview() {
|
||||
description={t("insights.sleep.empty.description")}
|
||||
action={
|
||||
<Button size="sm" variant="outline" asChild>
|
||||
<Link href="/settings/devices">
|
||||
<Link href="/settings/integrations">
|
||||
{t("insights.sleep.empty.action")}
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
Reference in new issue
Block a user