fix(charts): split medication-compliance empty-state copy on scheduled doses

Mirrors the health-chart and mood-chart fixes. The compliance payload
already carries `scheduled` per day; summing it yields the raw
scheduled-dose count for the window. When the chart aggregates to
< 3 daily buckets but the raw count is ≥ 3, paint the new
"More distinct days needed" copy so the next action matches reality.

Pin both branches with an SSR test that mocks the compliance fetch.
This commit is contained in:
Marc-André Bombeck committed 2026-05-21 21:45:32 +02:00
1 parent ceabcf8a47
commit 6196d68ed1
2 files changed
+125 -4

No files matched your search

@@ -0,0 +1,93 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
/**
* v1.4.43 W2-CHART-GATE — medication-compliance empty-state copy split.
*
* The chart aggregates per-day compliance buckets, so a user with 20
* scheduled doses on 2 calendar days collapses to `chartData.length =
* 2`. The pre-v1.4.43 "log more measurements" hint misled — they
* logged plenty, just on too few days. The gate now keys on
* `rawCount = Σ scheduled` so the second message paints whenever the
* user has enough raw doses but the chart is < 3 buckets wide.
*/
vi.mock("@/hooks/use-auth", () => ({
useAuth: () => ({
isAuthenticated: true,
user: null,
isLoading: false,
}),
}));
describe("<MedicationComplianceChart> — empty-state gate by raw count", () => {
beforeEach(() => {
vi.resetModules();
});
it("renders need-more-days copy when chartData.length < 3 but rawCount >= 3", async () => {
const data = [
{ date: "2026-05-19", scheduled: 10, taken: 8 },
{ date: "2026-05-20", scheduled: 10, taken: 9 },
];
vi.doMock("@tanstack/react-query", () => ({
useQuery: () => ({ data, isLoading: false }),
useQueryClient: () => ({
cancelQueries: () => Promise.resolve(),
getQueryData: () => undefined,
setQueryData: () => undefined,
invalidateQueries: () => Promise.resolve(),
}),
useMutation: () => ({ mutate: () => undefined, isPending: false }),
}));
const { I18nProvider } = await import("@/lib/i18n/context");
const { MedicationComplianceChart } = await import(
"../medication-compliance-chart"
);
const html = renderToStaticMarkup(
<I18nProvider initialLocale="de">
<MedicationComplianceChart />
</I18nProvider>,
);
expect(html).toContain("Mehr Messtage erforderlich");
expect(html).not.toContain("Erfasse mindestens 3 Einträge");
vi.doUnmock("@tanstack/react-query");
});
it("renders no-data copy when rawCount < 3", async () => {
const data = [{ date: "2026-05-20", scheduled: 1, taken: 1 }];
vi.doMock("@tanstack/react-query", () => ({
useQuery: () => ({ data, isLoading: false }),
useQueryClient: () => ({
cancelQueries: () => Promise.resolve(),
getQueryData: () => undefined,
setQueryData: () => undefined,
invalidateQueries: () => Promise.resolve(),
}),
useMutation: () => ({ mutate: () => undefined, isPending: false }),
}));
const { I18nProvider } = await import("@/lib/i18n/context");
const { MedicationComplianceChart } = await import(
"../medication-compliance-chart"
);
const html = renderToStaticMarkup(
<I18nProvider initialLocale="de">
<MedicationComplianceChart />
</I18nProvider>,
);
expect(html).toContain("Erfasse mindestens 3 Einträge");
expect(html).not.toContain("Mehr Messtage erforderlich");
vi.doUnmock("@tanstack/react-query");
});
});
@@ -252,6 +252,21 @@ export function MedicationComplianceChart({
[data, tzFmt],
);
// v1.4.43 W2-CHART-GATE — raw scheduled-dose count across every day
// in the window. The chart bucket aggregates per-day compliance, so
// a user with 20 scheduled doses on 2 calendar days collapses to
// `chartData.length = 2`. Sum the `scheduled` field across the raw
// daily points so the empty-state gate can distinguish "no doses
// tracked" from "doses tracked but on too few days".
const rawCount = useMemo<number>(() => {
if (!data?.length) return 0;
return data.reduce(
(acc, point) =>
acc + (Number.isFinite(point.scheduled) ? point.scheduled : 0),
0,
);
}, [data]);
// v1.4.16 A6 — 7-day trend chip. Computed off the *full* range so a
// user toggled to "7 days" still sees a trend (which would otherwise
// be empty if we only used the visible window). The 14-day cap inside
@@ -391,10 +406,23 @@ export function MedicationComplianceChart({
) : chartData.length < 3 ? (
// v1.4.16 B1a — sparse-data placeholder consistent with the
// BP/weight/pulse/mood charts.
<ChartEmptyState
title={t("charts.emptyStateTitle")}
description={t("charts.emptyStateDescription")}
/>
//
// v1.4.43 W2-CHART-GATE — split the copy on the raw scheduled-
// dose count. A user with 20 scheduled doses on 2 calendar
// days has `chartData.length = 2`; the legacy "log more" hint
// misled — they logged plenty, just on too few days. Surface
// "need more days" when the raw count is already enough.
rawCount >= 3 ? (
<ChartEmptyState
title={t("charts.needMoreDistinctDaysTitle")}
description={t("charts.needMoreDistinctDaysDescription")}
/>
) : (
<ChartEmptyState
title={t("charts.emptyStateTitle")}
description={t("charts.emptyStateDescription")}
/>
)
) : (
<div className="h-[var(--chart-height,240px)] md:h-[var(--chart-height-md,280px)] touch-pan-y">
<ResponsiveContainer width="100%" height="100%">