mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 04:32:42 +00:00
fix(clinician): write the shared view's numbers in the owner's locale
The clinician view rounded numbers and printed them bare, so a German record showed 24.5 where every other surface shows 24,5. Its number formatter now goes through the locale formatter it already builds, at most two decimals.
This commit is contained in:
1 parent
fdd34f2c5e
commit
358ef23239
6 files changed
+42
-12
No files matched your search
@@ -253,3 +253,31 @@ describe("<ClinicianView> resolves every label in every locale", () => {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("<ClinicianView> numbers follow the owner's locale", () => {
|
||||
function text(locale: "de" | "en") {
|
||||
const { t } = getServerTranslator(locale);
|
||||
return renderToStaticMarkup(
|
||||
ClinicianView({
|
||||
t: (key, vars) => t(key, vars),
|
||||
label: "Clinic",
|
||||
expiresAt: "2026-03-01T00:00:00.000Z",
|
||||
report: FULL_RECORD,
|
||||
selection: selectionFromLeaves(ALL_LEAF_IDS),
|
||||
locale,
|
||||
timeFormat: "AUTO",
|
||||
dateFormat: "AUTO",
|
||||
}),
|
||||
).replace(/<[^>]*>/g, " ");
|
||||
}
|
||||
|
||||
it("writes a German decimal with a comma", () => {
|
||||
// BMI 24.5 in the fixture.
|
||||
expect(text("de")).toContain("24,5");
|
||||
expect(text("de")).not.toContain("24.5");
|
||||
});
|
||||
|
||||
it("keeps the point for an English reader", () => {
|
||||
expect(text("en")).toContain("24.5");
|
||||
});
|
||||
});
|
||||
@@ -149,7 +149,9 @@ export function ClinicianView({
|
||||
const fmt = makeFormatters(locale, timezone, timeFormat, dateFormat);
|
||||
const fmtDate = (iso: string) => fmt.date(new Date(iso));
|
||||
const fmtDateTime = (iso: string) => fmt.dateTime(new Date(iso));
|
||||
const fmtNum = (n: number) => Math.round(n * 100) / 100;
|
||||
// Two decimals at most, in the owner's locale: a German reader gets
|
||||
// "80,5", not the "80.5" a bare number prints.
|
||||
const fmtNum = (n: number) => fmt.number(Math.round(n * 100) / 100);
|
||||
const scope = makeLeafScope(selection, unavailableLeaves);
|
||||
|
||||
return (
|
||||
@@ -207,7 +209,7 @@ export function ClinicianView({
|
||||
>
|
||||
<StatRow
|
||||
label={t("clinicianView.bmi")}
|
||||
value={String(fmtNum(report.bmi))}
|
||||
value={fmtNum(report.bmi)}
|
||||
/>
|
||||
</Section>
|
||||
) : null}
|
||||
|
||||
@@ -53,7 +53,7 @@ export function LabResultsSection({
|
||||
report: DoctorReportData;
|
||||
scope: LeafScope;
|
||||
fmtDate: (iso: string) => string;
|
||||
fmtNum: (n: number) => number;
|
||||
fmtNum: (n: number) => string;
|
||||
}) {
|
||||
const results = report.labResults ?? [];
|
||||
|
||||
@@ -73,7 +73,7 @@ export function LabResultsSection({
|
||||
? lab.valueText
|
||||
: `${fmtNum(lab.value as number)} ${lab.unit}`.trim();
|
||||
const range = (low: number | null, high: number | null) =>
|
||||
formatReferenceRange(low, high, (value) => String(fmtNum(value)), {
|
||||
formatReferenceRange(low, high, fmtNum, {
|
||||
emptyText: "",
|
||||
});
|
||||
// The window the reading was judged against, printed as the source
|
||||
|
||||
@@ -204,7 +204,7 @@ export function MeasurementGroups({
|
||||
t: Translate;
|
||||
report: DoctorReportData;
|
||||
scope: LeafScope;
|
||||
fmtNum: (n: number) => number;
|
||||
fmtNum: (n: number) => string;
|
||||
}) {
|
||||
const groups = REPORT_GROUPS.map((group) => ({
|
||||
labelKey: group.labelKey,
|
||||
@@ -257,7 +257,7 @@ export function MeasurementGroups({
|
||||
function statSummary(
|
||||
t: Translate,
|
||||
unit: string,
|
||||
values: { latest: number; avg: number; min: number; max: number },
|
||||
values: { latest: string; avg: string; min: string; max: string },
|
||||
): string {
|
||||
return unit
|
||||
? t("clinicianView.statSummaryWithUnit", { ...values, unit })
|
||||
@@ -279,7 +279,7 @@ export function GlucoseSection({
|
||||
t: Translate;
|
||||
report: DoctorReportData;
|
||||
scope: LeafScope;
|
||||
fmtNum: (n: number) => number;
|
||||
fmtNum: (n: number) => string;
|
||||
}) {
|
||||
const entries = Object.entries(report.glucoseStats).filter(
|
||||
([, s]) => s.count > 0,
|
||||
@@ -506,7 +506,7 @@ export function WellnessSection({
|
||||
t: Translate;
|
||||
report: DoctorReportData;
|
||||
scope: LeafScope;
|
||||
fmtNum: (n: number) => number;
|
||||
fmtNum: (n: number) => string;
|
||||
}) {
|
||||
const wellness =
|
||||
report.wellnessScores?.filter(
|
||||
|
||||
@@ -89,7 +89,7 @@ export function MoodSection({
|
||||
t: Translate;
|
||||
report: DoctorReportData;
|
||||
scope: LeafScope;
|
||||
fmtNum: (n: number) => number;
|
||||
fmtNum: (n: number) => string;
|
||||
}) {
|
||||
const mood = report.mood ?? null;
|
||||
const buckets = mood ? Object.entries(mood.distribution) : [];
|
||||
@@ -145,7 +145,7 @@ export function CycleSection({
|
||||
report: DoctorReportData;
|
||||
scope: LeafScope;
|
||||
fmtDate: (iso: string) => string;
|
||||
fmtNum: (n: number) => number;
|
||||
fmtNum: (n: number) => string;
|
||||
}) {
|
||||
const cycle = report.cycle ?? null;
|
||||
// The summary carries plain dates (YYYY-MM-DD); midday keeps the rendered
|
||||
|
||||
@@ -47,7 +47,7 @@ export function Glp1Section({
|
||||
report: DoctorReportData;
|
||||
scope: LeafScope;
|
||||
fmtDate: (iso: string) => string;
|
||||
fmtNum: (n: number) => number;
|
||||
fmtNum: (n: number) => string;
|
||||
}) {
|
||||
const glp1 = report.glp1 ?? null;
|
||||
const medications = glp1?.medications ?? [];
|
||||
@@ -173,7 +173,7 @@ export function DoseLogSection({
|
||||
report: DoctorReportData;
|
||||
scope: LeafScope;
|
||||
fmtDateTime: (iso: string) => string;
|
||||
fmtNum: (n: number) => number;
|
||||
fmtNum: (n: number) => string;
|
||||
}) {
|
||||
const administrations = report.medicationAdministrations ?? [];
|
||||
// Newest first: a clinician reads "when did they last take it", not "when
|
||||
|
||||
Reference in new issue
Block a user