mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 06:52:04 +00:00
fix(targets): convert glucose targets back to mg/dL on save
The per-metric target editor receives a glucose range already projected into the user's display unit (mmol/L) along with `unit="mmol/L"`, but it seeded, validated and saved that value verbatim. HealthLog stores glucose canonically in mg/dL, so a user on the mmol/L preference either had a valid target (e.g. 3.9–5.5 mmol/L) rejected by the 40–400 mg/dL bounds, or — when an override already existed — saw a mg/dL number rendered as if it were mmol/L and wrote it straight back. Add `mmolToMgdl` / `toCanonicalMgdl` (the inverse of `convertGlucose`) and teach the edit sheet to treat the display unit at its boundary: seed the persisted mg/dL override into the display unit, validate against bounds expressed in the display unit, and convert the typed value back to canonical mg/dL before the PUT. A no-op for every non-glucose metric and for users on the mg/dL preference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> (cherry picked from commit 0cc0361058a85f32d7135e5f2fd425c98f62d885)
This commit is contained in:
1 parent
09af60303d
commit
170862fdf8
4 files changed
+101
-4
No files matched your search
@@ -1,7 +1,9 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
mgdlToMmol,
|
||||
mmolToMgdl,
|
||||
convertGlucose,
|
||||
toCanonicalMgdl,
|
||||
resolveGlucoseUnit,
|
||||
thresholdMetricForContext,
|
||||
} from "../glucose";
|
||||
@@ -50,4 +52,25 @@ describe("glucose conversion", () => {
|
||||
expect(convertGlucose(fastingMax, "mmol/L")).toBe(5.5);
|
||||
expect(convertGlucose(ada126, "mmol/L")).toBe(7);
|
||||
});
|
||||
|
||||
// The target-editor write path: a value the user typed in their
|
||||
// display unit must persist as canonical mg/dL. Before the fix the
|
||||
// editor saved the mmol/L number verbatim (a 5.5 mmol/L target stored
|
||||
// as 5.5 mg/dL, or rejected outright by the 40–400 mg/dL bounds).
|
||||
it("converts a display-unit value back to canonical mg/dL", () => {
|
||||
expect(mmolToMgdl(5.5)).toBe(99);
|
||||
expect(mmolToMgdl(7.0)).toBe(126); // ADA diabetes threshold
|
||||
expect(mmolToMgdl(3.9)).toBe(70); // hypoglycemia threshold
|
||||
});
|
||||
|
||||
it("toCanonicalMgdl is the inverse of convertGlucose at the editor boundary", () => {
|
||||
// mg/dL display unit is already canonical — only rounds.
|
||||
expect(toCanonicalMgdl(126, "mg/dL")).toBe(126);
|
||||
expect(toCanonicalMgdl(99.4, "mg/dL")).toBe(99);
|
||||
// mmol/L display unit converts back; the round-trip is stable to the
|
||||
// 1-decimal mmol/L the UI shows (≤1 mg/dL drift is unavoidable).
|
||||
expect(toCanonicalMgdl(7.0, "mmol/L")).toBe(126);
|
||||
expect(toCanonicalMgdl(mgdlToMmol(126), "mmol/L")).toBeCloseTo(126, -0.5);
|
||||
expect(toCanonicalMgdl(mgdlToMmol(70), "mmol/L")).toBe(70);
|
||||
});
|
||||
});
|
||||
@@ -15,10 +15,25 @@ export function mgdlToMmol(mgdl: number): number {
|
||||
return Math.round((mgdl / MGDL_PER_MMOL) * 10) / 10;
|
||||
}
|
||||
|
||||
export function mmolToMgdl(mmol: number): number {
|
||||
return Math.round(mmol * MGDL_PER_MMOL);
|
||||
}
|
||||
|
||||
export function convertGlucose(value: number, to: GlucoseUnit): number {
|
||||
return to === "mmol/L" ? mgdlToMmol(value) : Math.round(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a value the user typed in their display unit back to the
|
||||
* canonical mg/dL HealthLog stores. The inverse of {@link convertGlucose}
|
||||
* for the editor write path: a `5.5 mmol/L` target the user enters must
|
||||
* persist as `99 mg/dL`, not as the literal `5.5`. A `mg/dL` display unit
|
||||
* is already canonical, so it only rounds.
|
||||
*/
|
||||
export function toCanonicalMgdl(value: number, from: GlucoseUnit): number {
|
||||
return from === "mmol/L" ? mmolToMgdl(value) : Math.round(value);
|
||||
}
|
||||
|
||||
export function resolveGlucoseUnit(
|
||||
userPreference: string | null | undefined,
|
||||
): GlucoseUnit {
|
||||
|
||||
Reference in new issue
Block a user