diff --git a/messages/de.json b/messages/de.json index c07f8cf1f..5db331c6c 100644 --- a/messages/de.json +++ b/messages/de.json @@ -6720,7 +6720,14 @@ "savedToast": "Biomarker gespeichert", "updatedToast": "Biomarker aktualisiert", "saveError": "Biomarker konnte nicht gespeichert werden" - } + }, + "hide": "Ausblenden", + "unhide": "Wiederherstellen", + "hiddenToast": "Biomarker ausgeblendet", + "unhiddenToast": "Biomarker wiederhergestellt", + "hideError": "Biomarker konnte nicht aktualisiert werden", + "allHidden": "Alle Biomarker sind ausgeblendet.", + "hiddenSection": "Ausgeblendet" }, "catalog": { "total-cholesterol": "Gesamtcholesterin", diff --git a/messages/en.json b/messages/en.json index 4e8e9c6f5..cf1ac2738 100644 --- a/messages/en.json +++ b/messages/en.json @@ -6720,7 +6720,14 @@ "savedToast": "Biomarker saved", "updatedToast": "Biomarker updated", "saveError": "Could not save the biomarker" - } + }, + "hide": "Hide", + "unhide": "Restore", + "hiddenToast": "Biomarker hidden", + "unhiddenToast": "Biomarker restored", + "hideError": "Could not update the biomarker", + "allHidden": "Every biomarker is hidden.", + "hiddenSection": "Hidden" }, "catalog": { "total-cholesterol": "Total cholesterol", diff --git a/src/components/labs/biomarker-manager.tsx b/src/components/labs/biomarker-manager.tsx index 1bcfce316..8608c0a8c 100644 --- a/src/components/labs/biomarker-manager.tsx +++ b/src/components/labs/biomarker-manager.tsx @@ -2,16 +2,15 @@ import { useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { FlaskConical, Pencil, Plus } from "lucide-react"; +import { Eye, EyeOff, FlaskConical, Pencil, Plus } from "lucide-react"; import { toast } from "sonner"; import { DeleteButton } from "@/components/data-list"; import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; import { EmptyState } from "@/components/ui/empty-state"; import { ResponsiveSheet } from "@/components/ui/responsive-sheet"; import { Skeleton } from "@/components/ui/skeleton"; -import { apiDelete, apiGet } from "@/lib/api/api-fetch"; +import { apiDelete, apiGet, apiPut } from "@/lib/api/api-fetch"; import { formatReferenceRange } from "@/lib/labs/reference-range"; import { formatLabValue } from "@/lib/labs/format-value"; import { useTranslations } from "@/lib/i18n/context"; @@ -21,12 +20,18 @@ import { BiomarkerForm } from "./biomarker-form"; import type { BiomarkerDto, BiomarkerListResponse } from "./types"; /** - * v1.18.1 — the Biomarker catalog manager. + * v1.18.1 — the Biomarker catalog manager. v1.22 — compact editable rows. * * Lives on the Labs page (not Settings) because the catalog IS the Labs - * feature's primary object. Lists every defined marker with its unit + - * reference range, opens a define-new / edit sheet, and wires delete (the - * `onDelete: SetNull` FK keeps existing readings, just unlinks them). + * feature's primary object. Each marker renders as a single compact row + * (name + unit inline, reference range / panel on a muted sub-line) with a + * hide toggle, an edit button (reusing the define/edit sheet), and a delete + * (the `onDelete: SetNull` FK keeps existing readings, just unlinks them). + * + * "Hide" is a soft remove: a marker the user no longer needs leaves the + * active list and the lab-entry pickers but keeps its readings + canonical + * unit/range. Hidden markers collect in a separate section where they can be + * restored or deleted outright. */ export function BiomarkerManager() { const { t } = useTranslations(); @@ -50,6 +55,20 @@ export function BiomarkerManager() { onError: () => toast.error(t("labs.biomarker.deleteError")), }); + const hiddenMutation = useMutation({ + mutationFn: ({ id, hidden }: { id: string; hidden: boolean }) => + apiPut(`/api/biomarkers/${id}`, { hidden }), + onSuccess: (_data, { hidden }) => { + toast.success( + hidden + ? t("labs.biomarker.hiddenToast") + : t("labs.biomarker.unhiddenToast"), + ); + queryClient.invalidateQueries({ queryKey: queryKeys.biomarkers() }); + }, + onError: () => toast.error(t("labs.biomarker.hideError")), + }); + function openNew() { setEditing(null); setFormOpen(true); @@ -68,6 +87,73 @@ export function BiomarkerManager() { } const markers = data?.biomarkers ?? []; + const visible = markers.filter((m) => !m.hidden); + const hidden = markers.filter((m) => m.hidden); + + function renderRow(marker: BiomarkerDto) { + const range = formatReferenceRange( + marker.lowerBound, + marker.upperBound, + formatLabValue, + ); + return ( +
+ {range + ? `${t("labs.referenceLabel")} ${range} ${marker.unit}` + : t("labs.biomarker.noRange")} + {marker.panel ? ` · ${marker.panel}` : ""} +
+- {range - ? `${t("labs.referenceLabel")} ${range} ${marker.unit}` - : t("labs.biomarker.noRange")} - {marker.panel ? ` · ${marker.panel}` : ""} -
-+ {t("labs.biomarker.allHidden")} +
+ )} + + {hidden.length > 0 ? ( ++ {t("labs.biomarker.hiddenSection")} +
+