mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 22:26:13 +00:00
perf(insights): mount the medication efficacy summary when near
Insights > Medications sent two requests per medication on entry: the compliance calendar inside each card and the efficacy read behind the summary card, which sits below every card and shows one line per medication. The summary now mounts through `DeferUntilNear`, like the overview's sections, so the efficacy reads go out only when the reader scrolls toward it. The cards and what the summary shows are unchanged. The comment that called the summary "never a second computation" goes: the efficacy route builds the view on every request.
This commit is contained in:
1 parent
d310058bc5
commit
6a1c91d5d4
2 files changed
+88
-6
No files matched your search
@@ -0,0 +1,81 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
/**
|
||||
* Insights > Medications: the efficacy summary sits below every medication
|
||||
* card and asks one efficacy read per medication. On entry it holds its slot
|
||||
* with a sentinel and mounts only when scrolled near, so opening the page
|
||||
* sends the cards' reads and not the summary's.
|
||||
*/
|
||||
|
||||
vi.mock("@tanstack/react-query", () => ({
|
||||
useQuery: ({ queryKey }: { queryKey: readonly unknown[] }) =>
|
||||
queryKey[1] === "comprehensive"
|
||||
? {
|
||||
data: {
|
||||
medications: [
|
||||
{
|
||||
id: "m1",
|
||||
name: "Ramipril",
|
||||
dose: "5 mg",
|
||||
category: "BLOOD_PRESSURE",
|
||||
compliance7: 100,
|
||||
compliance30: 95,
|
||||
streak: 7,
|
||||
taken7: 7,
|
||||
skipped7: 0,
|
||||
missed7: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
}
|
||||
: { data: undefined, isLoading: false, isError: false },
|
||||
}));
|
||||
vi.mock("@/hooks/use-auth", () => ({
|
||||
useAuth: () => ({ isAuthenticated: true }),
|
||||
}));
|
||||
vi.mock("@/hooks/use-ai-capability", () => ({
|
||||
useAiCapability: () => ({ available: false }),
|
||||
useAiProviderState: () => ({ responseTimeoutMs: null }),
|
||||
}));
|
||||
vi.mock("@/components/insights/medication-efficacy-summary", () => ({
|
||||
MedicationEfficacySummary: () => <div data-slot="efficacy-summary-mounted" />,
|
||||
}));
|
||||
vi.mock("@/components/insights/sub-page-shell", () => ({
|
||||
SubPageShell: ({ children }: { children: ReactNode }) => <>{children}</>,
|
||||
}));
|
||||
vi.mock("@/components/insights/glp1-substance-curve-summary", () => ({
|
||||
Glp1SubstanceCurveSummary: () => null,
|
||||
}));
|
||||
vi.mock("@/components/insights/metric-target-summary", () => ({
|
||||
MetricTargetSummary: () => null,
|
||||
}));
|
||||
vi.mock("@/components/insights/insight-status-card", () => ({
|
||||
InsightStatusCard: () => null,
|
||||
}));
|
||||
vi.mock("@/components/insights/coach-launch-button", () => ({
|
||||
CoachLaunchButton: () => null,
|
||||
}));
|
||||
vi.mock("@/components/charts/compliance-heatmap", () => ({
|
||||
ComplianceHeatmap: () => null,
|
||||
}));
|
||||
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
import InsightsMedikamentePage from "../page";
|
||||
|
||||
describe("/insights/medications on entry", () => {
|
||||
it("renders the cards and holds the efficacy summary until scrolled near", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<I18nProvider initialLocale="en">
|
||||
<InsightsMedikamentePage />
|
||||
</I18nProvider>,
|
||||
);
|
||||
|
||||
expect(html).toContain("Ramipril");
|
||||
expect(html).toContain('data-deferred-section="medication-efficacy"');
|
||||
expect(html).not.toContain("efficacy-summary-mounted");
|
||||
});
|
||||
});
|
||||
@@ -24,6 +24,7 @@ import { CoachLaunchButton } from "@/components/insights/coach-launch-button";
|
||||
import { InsightStatusCard } from "@/components/insights/insight-status-card";
|
||||
import { MetricTargetSummary } from "@/components/insights/metric-target-summary";
|
||||
import { MedicationEfficacySummary } from "@/components/insights/medication-efficacy-summary";
|
||||
import { DeferUntilNear } from "@/components/insights/defer-until-near";
|
||||
import { Glp1SubstanceCurveSummary } from "@/components/insights/glp1-substance-curve-summary";
|
||||
import { SubPageShell } from "@/components/insights/sub-page-shell";
|
||||
import { TileHeader } from "@/components/insights/tile-header";
|
||||
@@ -321,12 +322,12 @@ export default function InsightsMedikamentePage() {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* v1.28 — compact efficacy summary: reuses the same server-computed
|
||||
efficacy DTO the detail-page "Wirkung" tab reads (never a second
|
||||
computation), association-only, linking through to the full view. */}
|
||||
<MedicationEfficacySummary
|
||||
medications={medications.map((m) => ({ id: m.id, name: m.name }))}
|
||||
/>
|
||||
{/* v1.28 — one efficacy read per medication, below every card: mounted when near. */}
|
||||
<DeferUntilNear id="medication-efficacy">
|
||||
<MedicationEfficacySummary
|
||||
medications={medications.map((m) => ({ id: m.id, name: m.name }))}
|
||||
/>
|
||||
</DeferUntilNear>
|
||||
|
||||
{/* v1.28.20 — estimated active-substance curve for GLP-1 medications
|
||||
(additive; renders nothing when the user has no GLP-1 medication). */}
|
||||
|
||||
Reference in new issue
Block a user