mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 23:12:04 +00:00
feat(cycle): surface a gated cycle summary card on the insights page
Add a compact cycle teaser to the main Insights overview for accounts with cycle tracking enabled. The card shows the current phase, cycle day, and the single headline phase finding, and deep-links into the full cycle insights tab so the cycle tab stays the single source of truth. The card mounts only when cycleTrackingEnabled resolves true from /api/auth/me — the same gate the sidebar cycle entry uses — and renders nothing for every other account. Phase and cycle day derive from the same calendar read plus deriveWheelState the cycle wheel uses, and the headline reuses the shared CyclePhaseHeadline, including its honest empty line when nothing has cleared the significance check. The cycle view now opens the insights tab when the URL carries ?tab=insights, validated against the known tab values; CycleView is wrapped in a Suspense boundary for the search-params read.
This commit is contained in:
1 parent
9d68b07b9e
commit
c1d8ff9db9
11 files changed
+410
-3
No files matched your search
+15
-2
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { Suspense, useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Loader2 } from "lucide-react";
|
||||
|
||||
@@ -40,5 +40,18 @@ export default function CyclePage() {
|
||||
);
|
||||
}
|
||||
|
||||
return <CycleView />;
|
||||
// `<CycleView>` reads `useSearchParams` for the `?tab=` deep-link; wrap it in
|
||||
// a Suspense boundary so the client-search-params bailout never de-opts the
|
||||
// build (Next's `missing-suspense-with-csr-bailout`).
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="flex h-64 items-center justify-center">
|
||||
<Loader2 className="text-primary h-8 w-8 animate-spin motion-reduce:animate-none" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<CycleView />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
@@ -153,6 +153,20 @@ const PeriodNarrativeCard = dynamic(
|
||||
},
|
||||
);
|
||||
|
||||
// v1.15.2 — the gated cycle-insights summary teaser. Mounted ONLY when
|
||||
// `user.cycleTrackingEnabled` is true (the same /api/auth/me signal the
|
||||
// sidebar nav entry gates on), so the cycle reads never fire for an account
|
||||
// without the feature. Deferred behind `next/dynamic` like the other
|
||||
// below-the-hero blocks; it owns its own calendar + insights reads and renders
|
||||
// nothing while resolving / on error, so it carries no loading placeholder.
|
||||
const CycleInsightSummaryCard = dynamic(
|
||||
() =>
|
||||
import("@/components/cycle/cycle-insight-summary-card").then((mod) => ({
|
||||
default: mod.CycleInsightSummaryCard,
|
||||
})),
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
/**
|
||||
* v1.4.25 W4d — Insights mother page.
|
||||
*
|
||||
@@ -384,6 +398,11 @@ export default function InsightsPage() {
|
||||
|
||||
{flags.briefing && <PeriodNarrativeCard enabled={isAuthenticated} />}
|
||||
|
||||
{/* v1.15.2 — gated cycle teaser. Render only for a cycle-tracking
|
||||
account; for everyone else this is nothing (no card, no layout gap).
|
||||
The card itself stays silent until its reads resolve. */}
|
||||
{user?.cycleTrackingEnabled ? <CycleInsightSummaryCard /> : null}
|
||||
|
||||
<CoincidentDeviationCard enabled={isAuthenticated} />
|
||||
|
||||
<RhythmEventsCard enabled={isAuthenticated} />
|
||||
|
||||
Reference in new issue
Block a user