From 3a35dbcf37b45b728b7bc5c8a5c982708e8fbac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 3 Oct 2026 18:22:55 +0200 Subject: [PATCH] i18n(labs): say why a biomarker's unit cannot change once it has readings --- messages/de.json | 6 ++ messages/en.json | 6 ++ messages/es.json | 6 ++ messages/fr.json | 6 ++ messages/it.json | 6 ++ messages/ko.json | 6 ++ messages/pl.json | 6 ++ .../labs/__tests__/biomarker-form.test.tsx | 80 +++++++++++++++++++ 8 files changed, 122 insertions(+) create mode 100644 src/components/labs/__tests__/biomarker-form.test.tsx diff --git a/messages/de.json b/messages/de.json index 64e5a0e0b..f6fb39d6b 100644 --- a/messages/de.json +++ b/messages/de.json @@ -135,6 +135,11 @@ "required": "Bestätige dein aktuelles Passwort, um das zu ändern.", "failed": "Die Bestätigung ist fehlgeschlagen. Es wurde nichts geändert." } + }, + "biomarkers": { + "unit": { + "locked": "Dieser Marker hat schon Werte, deshalb kannst du seine Einheit nicht ändern. Die gespeicherten Werte würden sonst in der neuen Einheit angezeigt, ohne umgerechnet zu werden." + } } }, "doctorReport": { @@ -8917,6 +8922,7 @@ "namePlaceholder": "z. B. LDL-Cholesterin", "unit": "Einheit", "unitPlaceholder": "z. B. mg/dl", + "unitLockedHint": "Sobald dieser Marker Werte hat, bleibt seine Einheit, wie sie ist. Sonst würden die gespeicherten Werte in einer neuen Einheit angezeigt, ohne umgerechnet zu werden.", "panel": "Panel", "panelPlaceholder": "z. B. Lipide", "lowerBound": "Referenz unten", diff --git a/messages/en.json b/messages/en.json index 2f5660ba4..a8907d336 100644 --- a/messages/en.json +++ b/messages/en.json @@ -135,6 +135,11 @@ "required": "Confirm your current password to change this.", "failed": "That did not verify. Nothing was changed." } + }, + "biomarkers": { + "unit": { + "locked": "This marker already has readings, so its unit can't be changed. The stored values would be shown in the new unit without being converted." + } } }, "doctorReport": { @@ -8917,6 +8922,7 @@ "namePlaceholder": "e.g. LDL cholesterol", "unit": "Unit", "unitPlaceholder": "e.g. mg/dL", + "unitLockedHint": "Once this marker has readings, its unit stays as it is. The stored values would otherwise be shown in a new unit without being converted.", "panel": "Panel", "panelPlaceholder": "e.g. Lipids", "lowerBound": "Reference low", diff --git a/messages/es.json b/messages/es.json index 8917fa569..ff74d35ae 100644 --- a/messages/es.json +++ b/messages/es.json @@ -135,6 +135,11 @@ "required": "Confirma tu contraseña actual para cambiar esto.", "failed": "La verificación ha fallado. No se ha cambiado nada." } + }, + "biomarkers": { + "unit": { + "locked": "Este marcador ya tiene valores, así que no puedes cambiar su unidad. Los valores guardados se mostrarían en la nueva unidad sin convertirse." + } } }, "doctorReport": { @@ -8917,6 +8922,7 @@ "namePlaceholder": "p. ej. Colesterol LDL", "unit": "Unidad", "unitPlaceholder": "p. ej. mg/dL", + "unitLockedHint": "Cuando este marcador ya tiene valores, su unidad no cambia. De lo contrario, los valores guardados se mostrarían en una unidad nueva sin convertirse.", "panel": "Panel", "panelPlaceholder": "p. ej. Lípidos", "lowerBound": "Referencia mínima", diff --git a/messages/fr.json b/messages/fr.json index c7b83d06a..a52b3f3f4 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -135,6 +135,11 @@ "required": "Confirmez votre mot de passe actuel pour modifier ceci.", "failed": "La vérification a échoué. Rien n'a été modifié." } + }, + "biomarkers": { + "unit": { + "locked": "Ce marqueur a déjà des valeurs, son unité ne peut donc pas être modifiée. Les valeurs enregistrées s'afficheraient dans la nouvelle unité sans être converties." + } } }, "doctorReport": { @@ -8917,6 +8922,7 @@ "namePlaceholder": "ex. Cholestérol LDL", "unit": "Unité", "unitPlaceholder": "ex. mg/dL", + "unitLockedHint": "Dès que ce marqueur a des valeurs, son unité reste la même. Sinon, les valeurs enregistrées s'afficheraient dans une nouvelle unité sans être converties.", "panel": "Panel", "panelPlaceholder": "ex. Lipides", "lowerBound": "Référence basse", diff --git a/messages/it.json b/messages/it.json index dc823ccee..db9a2d087 100644 --- a/messages/it.json +++ b/messages/it.json @@ -135,6 +135,11 @@ "required": "Conferma la password attuale per modificarlo.", "failed": "La verifica non è riuscita. Non è stato modificato nulla." } + }, + "biomarkers": { + "unit": { + "locked": "Questo marcatore ha già dei valori, quindi non puoi cambiarne l'unità. I valori salvati verrebbero mostrati nella nuova unità senza essere convertiti." + } } }, "doctorReport": { @@ -8917,6 +8922,7 @@ "namePlaceholder": "es. Colesterolo LDL", "unit": "Unità", "unitPlaceholder": "es. mg/dL", + "unitLockedHint": "Quando questo marcatore ha già dei valori, la sua unità resta invariata. Altrimenti i valori salvati verrebbero mostrati in una nuova unità senza essere convertiti.", "panel": "Panel", "panelPlaceholder": "es. Lipidi", "lowerBound": "Riferimento minimo", diff --git a/messages/ko.json b/messages/ko.json index ad5942532..032cda26a 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -135,6 +135,11 @@ "required": "변경하려면 현재 비밀번호를 확인하세요.", "failed": "확인에 실패했습니다. 아무것도 변경되지 않았습니다." } + }, + "biomarkers": { + "unit": { + "locked": "이 마커에는 이미 기록된 값이 있어서 단위를 바꿀 수 없어요. 저장된 값이 변환되지 않은 채 새 단위로 표시되기 때문이에요." + } } }, "doctorReport": { @@ -8917,6 +8922,7 @@ "namePlaceholder": "예: LDL 콜레스테롤", "unit": "단위", "unitPlaceholder": "예: mg/dL", + "unitLockedHint": "이 마커에 기록된 값이 있으면 단위는 그대로 유지돼요. 그렇지 않으면 저장된 값이 변환되지 않은 채 새 단위로 표시돼요.", "panel": "패널", "panelPlaceholder": "예: 지질", "lowerBound": "참고 하한", diff --git a/messages/pl.json b/messages/pl.json index 8fead53ee..cc2ca36e2 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -135,6 +135,11 @@ "required": "Potwierdź obecne hasło, aby to zmienić.", "failed": "Weryfikacja nie powiodła się. Nic nie zostało zmienione." } + }, + "biomarkers": { + "unit": { + "locked": "Ten marker ma już wyniki, więc nie możesz zmienić jego jednostki. Zapisane wartości byłyby pokazywane w nowej jednostce bez przeliczenia." + } } }, "doctorReport": { @@ -8917,6 +8922,7 @@ "namePlaceholder": "np. Cholesterol LDL", "unit": "Jednostka", "unitPlaceholder": "np. mg/dl", + "unitLockedHint": "Gdy ten marker ma już wyniki, jego jednostka pozostaje bez zmian. W przeciwnym razie zapisane wartości byłyby pokazywane w nowej jednostce bez przeliczenia.", "panel": "Panel", "panelPlaceholder": "np. Lipidy", "lowerBound": "Dolna granica", diff --git a/src/components/labs/__tests__/biomarker-form.test.tsx b/src/components/labs/__tests__/biomarker-form.test.tsx new file mode 100644 index 000000000..43d77f898 --- /dev/null +++ b/src/components/labs/__tests__/biomarker-form.test.tsx @@ -0,0 +1,80 @@ +import { describe, it, expect, vi } from "vitest"; +import { renderToStaticMarkup } from "react-dom/server"; + +import { I18nProvider } from "@/lib/i18n/context"; +import { ApiError } from "@/lib/api/api-fetch"; +import { localizedApiError } from "@/lib/api/localized-error"; +import en from "../../../../messages/en.json"; + +/** + * The marker editor says, before a save, that a marker's unit stays as it is + * once readings exist, and the refusal the server sends for such a change + * reads as that sentence rather than the generic save error. + */ + +vi.mock("@/lib/api/api-fetch", async (importOriginal) => ({ + ...(await importOriginal()), + apiPost: vi.fn(), + apiPut: vi.fn(), +})); + +import { BiomarkerForm } from "../biomarker-form"; +import type { BiomarkerDto } from "../types"; + +const MARKER: BiomarkerDto = { + id: "bm-1", + name: "Glucose", + unit: "mg/dL", + lowerBound: 70, + upperBound: 99, + panel: null, + hasContext: false, + context: null, + hidden: false, + createdAt: "2026-01-01T00:00:00.000Z", + updatedAt: "2026-01-01T00:00:00.000Z", +}; + +function render(node: React.ReactNode) { + return renderToStaticMarkup( + {node}, + ); +} + +describe(" unit lock", () => { + const hint = en.labs.biomarker.form.unitLockedHint; + + it("tells the editor of an existing marker that the unit is locked by readings", () => { + const html = render(); + expect(hint.length).toBeGreaterThan(0); + expect(html).toContain(hint.replace(/'/g, "'")); + expect(html).toMatch(/aria-describedby="[^"]*-unit-hint"/); + }); + + it("says nothing of a lock while a new marker is defined", () => { + const html = render(); + expect(html).not.toContain(hint.replace(/'/g, "'")); + }); + + it("reads the server's refusal as its own sentence, not the save error", () => { + const err = new ApiError("locked", 422, { + errorCode: "biomarkers.unit.locked", + readingCount: 2, + }); + const t = (key: string) => { + const value = key + .split(".") + .reduce( + (node, part) => + node && typeof node === "object" + ? (node as Record)[part] + : undefined, + en, + ); + return typeof value === "string" ? value : key; + }; + expect(localizedApiError(err, t, "labs.biomarker.form.saveError")).toBe( + en.apiErrors.biomarkers.unit.locked, + ); + }); +});