mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 06:52:04 +00:00
Merge pull request #1069 from MBombeck/fix/v1397-units
One unit system: every surface follows the reader's glucose and metric/imperial preference
This commit is contained in:
74 files changed
+2304
-292
No files matched your search
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* The settings threshold editor reads glucose in the reader's unit.
|
||||
*
|
||||
* It used to pass every glucose threshold through the identity path, so an
|
||||
* mmol/L account was shown "Default: 70–99 mg/dL" and mg/dL input fields
|
||||
* bounded at 40–400, while the insights sheet for the same threshold already
|
||||
* spoke mmol/L. The stored value stays canonical mg/dL either way.
|
||||
*/
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
|
||||
const authUser = vi.hoisted(() => ({
|
||||
current: { glucoseUnit: "mmol/L", unitPreference: "metric" } as Record<
|
||||
string,
|
||||
unknown
|
||||
>,
|
||||
}));
|
||||
|
||||
vi.mock("@/hooks/use-auth", () => ({
|
||||
useAuth: () => ({ user: authUser.current, isAuthenticated: true }),
|
||||
useAccountOnceMounted: () => authUser.current,
|
||||
}));
|
||||
|
||||
vi.mock("@tanstack/react-query", () => ({
|
||||
useQuery: () => ({
|
||||
isLoading: false,
|
||||
data: {
|
||||
effective: {
|
||||
BLOOD_GLUCOSE_FASTING: {
|
||||
range: { greenMin: 72, greenMax: 108 },
|
||||
isOverride: true,
|
||||
default: { greenMin: 70, greenMax: 99 },
|
||||
bounds: { min: 40, max: 400, unit: "mg/dL" },
|
||||
},
|
||||
},
|
||||
overrides: { BLOOD_GLUCOSE_FASTING: { min: 72, max: 108 } },
|
||||
},
|
||||
}),
|
||||
useMutation: () => ({ mutate: vi.fn(), isPending: false }),
|
||||
useQueryClient: () => ({ invalidateQueries: vi.fn() }),
|
||||
}));
|
||||
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
import { ThresholdsEditorSection } from "../thresholds-editor-section";
|
||||
|
||||
function render(): string {
|
||||
return renderToStaticMarkup(
|
||||
<I18nProvider initialLocale="en">
|
||||
<ThresholdsEditorSection id="thresholds" />
|
||||
</I18nProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
describe("<ThresholdsEditorSection> glucose unit", () => {
|
||||
it("states the default, the fields and the bounds in mmol/L", () => {
|
||||
authUser.current = { glucoseUnit: "mmol/L", unitPreference: "metric" };
|
||||
const html = render();
|
||||
// 70–99 mg/dL is 3.9–5.5 mmol/L.
|
||||
expect(html).toMatch(/3\.9–5\.5 mmol\/L/);
|
||||
expect(html).not.toMatch(/70(\.0)?–99(\.0)? mg\/dL/);
|
||||
// The stored 72–108 mg/dL override seeds 4–6 mmol/L.
|
||||
expect(html).toContain('value="4"');
|
||||
expect(html).toContain('value="6"');
|
||||
// Inward-rounded guardrail of 40–400 mg/dL.
|
||||
expect(html).toContain('min="2.3"');
|
||||
expect(html).toContain('max="22.1"');
|
||||
});
|
||||
|
||||
it("keeps mg/dL for an mg/dL reader", () => {
|
||||
authUser.current = { glucoseUnit: "mg/dL", unitPreference: "metric" };
|
||||
const html = render();
|
||||
expect(html).toMatch(/70(\.0)?–99(\.0)? mg\/dL/);
|
||||
expect(html).toContain('value="72"');
|
||||
expect(html).toContain('min="40"');
|
||||
});
|
||||
});
|
||||
@@ -237,7 +237,7 @@ function MetricRow({
|
||||
}: MetricRowProps) {
|
||||
const { t } = useTranslations();
|
||||
const fmt = useFormatters();
|
||||
const { preference } = useUnitDisplay();
|
||||
const { preference, glucoseUnit } = useUnitDisplay();
|
||||
const canonicalBounds = METRIC_BOUNDS[metric];
|
||||
|
||||
// v1.32.27 — the row reads and writes in the user's preferred unit
|
||||
@@ -246,12 +246,14 @@ function MetricRow({
|
||||
// canonical, so it converts on the way into the fields and inverts on
|
||||
// the way back out in `onSave`. Guardrails round inward so a value
|
||||
// typed at the displayed limit still passes the server's canonical
|
||||
// check. Metrics without a transform — and every metric for a metric
|
||||
// user — take the adapter's identity path untouched.
|
||||
// check. The glucose thresholds read in the reader's glucose unit the
|
||||
// same way. Metrics without a transform — and every metric on the default
|
||||
// preferences — take the adapter's identity path untouched.
|
||||
const units = resolveTargetUnitAdapter(
|
||||
metric,
|
||||
canonicalBounds.unit,
|
||||
preference,
|
||||
glucoseUnit,
|
||||
);
|
||||
const bounds = { ...units.bounds(canonicalBounds), unit: units.unit };
|
||||
|
||||
|
||||
Reference in new issue
Block a user