diff --git a/src/app/insights/blood-glucose/page.tsx b/src/app/insights/blood-glucose/page.tsx index 9f8cb64ff..d8dcdddb2 100644 --- a/src/app/insights/blood-glucose/page.tsx +++ b/src/app/insights/blood-glucose/page.tsx @@ -7,7 +7,7 @@ import { GlucoseClinicalPanel } from "@/components/insights/glucose/glucose-clin import { useAuth } from "@/hooks/use-auth"; import { useModulePageGuard } from "@/hooks/use-module-page-guard"; import { useTranslations } from "@/lib/i18n/context"; -import { resolveGlucoseUnit } from "@/lib/glucose"; +import { MGDL_PER_MMOL, resolveGlucoseUnit } from "@/lib/glucose"; /** * v1.7.0 — `/insights/blood-glucose`. @@ -25,8 +25,6 @@ import { resolveGlucoseUnit } from "@/lib/glucose"; * exports. mg/dL-preference users are unaffected (scale = 1, integer * precision). */ -const MGDL_PER_MMOL = 18.0182; - export default function InsightsBlutzuckerPage() { const { user } = useAuth(); const { t } = useTranslations(); diff --git a/src/lib/glucose.ts b/src/lib/glucose.ts index 96cb33ab7..14d2dee5b 100644 --- a/src/lib/glucose.ts +++ b/src/lib/glucose.ts @@ -9,7 +9,15 @@ export type GlucoseUnit = "mg/dL" | "mmol/L"; -const MGDL_PER_MMOL = 18.0182; +/** + * mg/dL per mmol/L, per the DGIM / DDG S3 guideline. Exported because it is + * the one factor for this conversion in the tree: the inbound alias resolver + * normalises a mmol/L cell with it, the glucose insight page scales its chart + * by its reciprocal, and the helpers below round with it. Two nearly-equal + * copies of a health conversion is how the same reading comes out as two + * different numbers on two screens. + */ +export const MGDL_PER_MMOL = 18.0182; export function mgdlToMmol(mgdl: number): number { return Math.round((mgdl / MGDL_PER_MMOL) * 10) / 10; diff --git a/src/lib/measurements/__tests__/unit-aliases.test.ts b/src/lib/measurements/__tests__/unit-aliases.test.ts index a12f4d860..dcf49f9ac 100644 --- a/src/lib/measurements/__tests__/unit-aliases.test.ts +++ b/src/lib/measurements/__tests__/unit-aliases.test.ts @@ -1,6 +1,7 @@ import { describe, it, expect } from "vitest"; import { resolveToCanonicalUnit } from "../unit-aliases"; +import { MGDL_PER_MMOL, mgdlToMmol } from "@/lib/glucose"; describe("resolveToCanonicalUnit", () => { it("passes the canonical unit through case-insensitively", () => { @@ -53,10 +54,17 @@ describe("resolveToCanonicalUnit", () => { }); }); - it("converts glucose mmol/L to canonical mg/dL", () => { + it("converts glucose mmol/L to canonical mg/dL on the app's one factor", () => { + // This used to assert 18.016 while every display path divided by + // 18.0182, so a reading imported as mmol/L and read back as mmol/L did + // not return the number it went in as. Both ends take the same factor + // now, and the assertion names it rather than repeating a literal — + // pinning the constant twice is how the two drifted apart. const out = resolveToCanonicalUnit("BLOOD_GLUCOSE", 5.3, "mmol/L"); expect(out?.unit).toBe("mg/dL"); - expect(out?.value).toBeCloseTo(5.3 * 18.016, 3); + expect(out?.value).toBeCloseTo(5.3 * MGDL_PER_MMOL, 3); + // The round trip a mmol/L reader actually experiences. + expect(mgdlToMmol(out?.value ?? 0)).toBe(5.3); }); it("refuses an unrecognised or type-mismatched unit (never mis-stores)", () => { diff --git a/src/lib/measurements/unit-aliases.ts b/src/lib/measurements/unit-aliases.ts index bb43693ed..e068187d2 100644 --- a/src/lib/measurements/unit-aliases.ts +++ b/src/lib/measurements/unit-aliases.ts @@ -17,9 +17,7 @@ * Pure + side-effect-free; safe to import from an API route or a script. */ import { getUnitForType } from "@/lib/validations/measurement"; - -/** Glucose mmol/L → mg/dL. */ -const GLUCOSE_MMOL_TO_MGDL = 18.016; +import { MGDL_PER_MMOL } from "@/lib/glucose"; /** Exact pound → kilogram (1 lb = 0.45359237 kg). */ const LB_TO_KG = 0.45359237; /** Exact inch → centimetre (1 in = 2.54 cm). */ @@ -87,7 +85,7 @@ export function resolveToCanonicalUnit( // Glucose: mmol/L → mg/dL. if (type === "BLOOD_GLUCOSE" && MMOL_ALIASES.has(lower)) { - return { value: value * GLUCOSE_MMOL_TO_MGDL, unit: canonical }; + return { value: value * MGDL_PER_MMOL, unit: canonical }; } // Body mass: lb → kg.