diff --git a/messages/de.json b/messages/de.json index d73d22df2..d768ca862 100644 --- a/messages/de.json +++ b/messages/de.json @@ -295,7 +295,43 @@ "immunizationsColDate": "Datum", "immunizationsColVaccine": "Impfstoff", "immunizationsColDose": "Dosis", - "immunizationsColLot": "Charge" + "immunizationsColLot": "Charge", + "emergency": { + "title": "Notfalldaten", + "subtitle": "Für den Einsatz im Notfall. Selbst angegeben; wenn möglich prüfen.", + "none": "Nicht erfasst", + "unreadable": "Gespeicherter Wert konnte nicht gelesen werden", + "bloodType": "Blutgruppe", + "bloodTypeUnknown": "Unbekannt", + "bloodTypeValues": { + "A_POS": "A positiv", + "A_NEG": "A negativ", + "B_POS": "B positiv", + "B_NEG": "B negativ", + "AB_POS": "AB positiv", + "AB_NEG": "AB negativ", + "O_POS": "0 positiv", + "O_NEG": "0 negativ" + }, + "severeAllergies": "Schwere Allergien", + "activeMedications": "Aktuelle Medikamente", + "chronicConditions": "Chronische Erkrankungen", + "implants": "Implantate und Geräte", + "advanceDirective": "Patientenverfügung", + "advanceDirectiveValues": { + "EXISTS": "Vorhanden", + "NONE": "Keine", + "UNKNOWN": "Keine Angabe" + }, + "organDonor": "Organspender", + "organDonorValues": { + "YES": "Ja", + "NO": "Nein", + "UNKNOWN": "Keine Angabe" + }, + "contacts": "Notfallkontakte", + "notes": "Weitere Hinweise" + } }, "errorBoundary": { "title": "Da ist etwas schiefgelaufen", @@ -9311,6 +9347,46 @@ "loadError": "Vorerkrankungen konnten nicht geladen werden.", "savedToast": "Erkrankungen gespeichert.", "saveError": "Speichern fehlgeschlagen. Bitte versuche es erneut." + }, + "emergency": { + "cardTitle": "Notfalldaten", + "cardDescription": "Was Rettungskräfte zuerst brauchen: Blutgruppe, Kontakte, Verfügungen.", + "bloodType": "Blutgruppe", + "organDonor": "Organspender", + "advanceDirective": "Patientenverfügung", + "contacts": "Notfallkontakte", + "implants": "Implantate und Geräte", + "note": "Weitere Hinweise", + "notRecorded": "Nicht erfasst", + "bloodTypeValues": { + "A_POS": "A positiv", + "A_NEG": "A negativ", + "B_POS": "B positiv", + "B_NEG": "B negativ", + "AB_POS": "AB positiv", + "AB_NEG": "AB negativ", + "O_POS": "0 positiv", + "O_NEG": "0 negativ", + "UNKNOWN": "Unbekannt" + }, + "organDonorValues": { + "YES": "Ja", + "NO": "Nein", + "UNKNOWN": "Keine Angabe" + }, + "advanceDirectiveValues": { + "EXISTS": "Vorhanden", + "NONE": "Keine", + "UNKNOWN": "Keine Angabe" + }, + "contactsPlaceholder": "Name und Telefonnummer für den Notfall", + "implantsPlaceholder": "z. B. Herzschrittmacher, Insulinpumpe, Metallimplantat", + "notePlaceholder": "Alles, was im Notfall wichtig sein könnte", + "reportHint": "Dies erscheint auf der ersten Seite deines Arztberichts.", + "save": "Speichern", + "savedToast": "Notfalldaten gespeichert", + "saveError": "Notfalldaten konnten nicht gespeichert werden.", + "loadError": "Notfalldaten konnten nicht geladen werden." } }, "environment": { @@ -9834,7 +9910,8 @@ "scopeCount": "{count} Einträge aus {groups} Bereichen", "scopeSensitive": "inkl. {names}", "leafVisits": "Arztbesuche", - "leafImmunizations": "Impfungen" + "leafImmunizations": "Impfungen", + "leafEmergency": "Notfalldaten (Blutgruppe, Kontakte, Verfügungen)" }, "recordSharing": { "banner": { diff --git a/messages/en.json b/messages/en.json index e4bf6f235..856b6bd93 100644 --- a/messages/en.json +++ b/messages/en.json @@ -150,6 +150,42 @@ "height": "Height", "period": "Reporting period", "createdOn": "Created on", + "emergency": { + "title": "Emergency information", + "subtitle": "For use in an acute situation. Self-reported; confirm where possible.", + "none": "Not recorded", + "unreadable": "Stored value could not be read", + "bloodType": "Blood type", + "bloodTypeUnknown": "Unknown", + "bloodTypeValues": { + "A_POS": "A positive", + "A_NEG": "A negative", + "B_POS": "B positive", + "B_NEG": "B negative", + "AB_POS": "AB positive", + "AB_NEG": "AB negative", + "O_POS": "O positive", + "O_NEG": "O negative" + }, + "severeAllergies": "Severe allergies", + "activeMedications": "Current medications", + "chronicConditions": "Chronic conditions", + "implants": "Implants and devices", + "advanceDirective": "Advance directive", + "advanceDirectiveValues": { + "EXISTS": "Exists", + "NONE": "None", + "UNKNOWN": "Not stated" + }, + "organDonor": "Organ donor", + "organDonorValues": { + "YES": "Yes", + "NO": "No", + "UNKNOWN": "Not stated" + }, + "contacts": "Emergency contacts", + "notes": "Additional notes" + }, "vitalsTitle": "Vital signs — Summary", "colParameter": "Parameter", "colCurrent": "Current", @@ -9311,6 +9347,46 @@ "loadError": "Couldn't load your conditions.", "savedToast": "Conditions saved.", "saveError": "Could not save. Please try again." + }, + "emergency": { + "cardTitle": "Emergency information", + "cardDescription": "What a first responder needs first: blood type, contacts, directives.", + "bloodType": "Blood type", + "organDonor": "Organ donor", + "advanceDirective": "Advance directive", + "contacts": "Emergency contacts", + "implants": "Implants and devices", + "note": "Additional notes", + "notRecorded": "Not recorded", + "bloodTypeValues": { + "A_POS": "A positive", + "A_NEG": "A negative", + "B_POS": "B positive", + "B_NEG": "B negative", + "AB_POS": "AB positive", + "AB_NEG": "AB negative", + "O_POS": "O positive", + "O_NEG": "O negative", + "UNKNOWN": "Unknown" + }, + "organDonorValues": { + "YES": "Yes", + "NO": "No", + "UNKNOWN": "Not stated" + }, + "advanceDirectiveValues": { + "EXISTS": "Exists", + "NONE": "None", + "UNKNOWN": "Not stated" + }, + "contactsPlaceholder": "Name and phone number of who to call", + "implantsPlaceholder": "e.g. pacemaker, insulin pump, metal implant", + "notePlaceholder": "Anything a clinician should know in an emergency", + "reportHint": "This appears on the first page of your doctor report.", + "save": "Save", + "savedToast": "Emergency information saved", + "saveError": "Couldn't save your emergency information.", + "loadError": "Couldn't load your emergency information." } }, "environment": { @@ -9834,7 +9910,8 @@ "scopeCount": "{count} entries from {groups} areas", "scopeSensitive": "incl. {names}", "leafVisits": "Visits", - "leafImmunizations": "Immunizations" + "leafImmunizations": "Immunizations", + "leafEmergency": "Emergency information (blood type, contacts, directives)" }, "recordSharing": { "banner": { diff --git a/messages/es.json b/messages/es.json index 70ab1793b..1848d62e2 100644 --- a/messages/es.json +++ b/messages/es.json @@ -295,7 +295,43 @@ "immunizationsColDate": "Fecha", "immunizationsColVaccine": "Vacuna", "immunizationsColDose": "Dosis", - "immunizationsColLot": "Lote" + "immunizationsColLot": "Lote", + "emergency": { + "title": "Información de emergencia", + "subtitle": "Para uso en una situación aguda. Autoinformado; confirmar cuando sea posible.", + "none": "No registrado", + "unreadable": "No se pudo leer el valor guardado", + "bloodType": "Grupo sanguíneo", + "bloodTypeUnknown": "Desconocido", + "bloodTypeValues": { + "A_POS": "A positivo", + "A_NEG": "A negativo", + "B_POS": "B positivo", + "B_NEG": "B negativo", + "AB_POS": "AB positivo", + "AB_NEG": "AB negativo", + "O_POS": "O positivo", + "O_NEG": "O negativo" + }, + "severeAllergies": "Alergias graves", + "activeMedications": "Medicación actual", + "chronicConditions": "Enfermedades crónicas", + "implants": "Implantes y dispositivos", + "advanceDirective": "Voluntades anticipadas", + "advanceDirectiveValues": { + "EXISTS": "Existe", + "NONE": "Ninguna", + "UNKNOWN": "Sin indicar" + }, + "organDonor": "Donante de órganos", + "organDonorValues": { + "YES": "Sí", + "NO": "No", + "UNKNOWN": "Sin indicar" + }, + "contacts": "Contactos de emergencia", + "notes": "Notas adicionales" + } }, "errorBoundary": { "title": "Algo ha salido mal", @@ -9311,6 +9347,46 @@ "loadError": "No se pudieron cargar tus enfermedades.", "savedToast": "Enfermedades guardadas.", "saveError": "No se pudo guardar. Inténtalo de nuevo." + }, + "emergency": { + "cardTitle": "Información de emergencia", + "cardDescription": "Lo que un servicio de emergencia necesita primero: grupo sanguíneo, contactos, voluntades.", + "bloodType": "Grupo sanguíneo", + "organDonor": "Donante de órganos", + "advanceDirective": "Voluntades anticipadas", + "contacts": "Contactos de emergencia", + "implants": "Implantes y dispositivos", + "note": "Notas adicionales", + "notRecorded": "No registrado", + "bloodTypeValues": { + "A_POS": "A positivo", + "A_NEG": "A negativo", + "B_POS": "B positivo", + "B_NEG": "B negativo", + "AB_POS": "AB positivo", + "AB_NEG": "AB negativo", + "O_POS": "O positivo", + "O_NEG": "O negativo", + "UNKNOWN": "Desconocido" + }, + "organDonorValues": { + "YES": "Sí", + "NO": "No", + "UNKNOWN": "Sin indicar" + }, + "advanceDirectiveValues": { + "EXISTS": "Existe", + "NONE": "Ninguna", + "UNKNOWN": "Sin indicar" + }, + "contactsPlaceholder": "Nombre y teléfono de a quién llamar", + "implantsPlaceholder": "p. ej. marcapasos, bomba de insulina, implante metálico", + "notePlaceholder": "Cualquier cosa que deba saber un profesional en una emergencia", + "reportHint": "Aparece en la primera página de tu informe médico.", + "save": "Guardar", + "savedToast": "Información de emergencia guardada", + "saveError": "No se pudo guardar la información de emergencia.", + "loadError": "No se pudo cargar la información de emergencia." } }, "environment": { @@ -9834,7 +9910,8 @@ "scopeCount": "{count} entradas de {groups} áreas", "scopeSensitive": "incl. {names}", "leafVisits": "Visitas médicas", - "leafImmunizations": "Vacunas" + "leafImmunizations": "Vacunas", + "leafEmergency": "Información de emergencia (grupo sanguíneo, contactos, voluntades)" }, "recordSharing": { "banner": { diff --git a/messages/fr.json b/messages/fr.json index 0747e74f0..b11b10ec5 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -295,7 +295,43 @@ "immunizationsColDate": "Date", "immunizationsColVaccine": "Vaccin", "immunizationsColDose": "Dose", - "immunizationsColLot": "Lot" + "immunizationsColLot": "Lot", + "emergency": { + "title": "Informations d'urgence", + "subtitle": "À utiliser en situation aiguë. Déclaré par le patient ; à confirmer si possible.", + "none": "Non renseigné", + "unreadable": "La valeur enregistrée n'a pas pu être lue", + "bloodType": "Groupe sanguin", + "bloodTypeUnknown": "Inconnu", + "bloodTypeValues": { + "A_POS": "A positif", + "A_NEG": "A négatif", + "B_POS": "B positif", + "B_NEG": "B négatif", + "AB_POS": "AB positif", + "AB_NEG": "AB négatif", + "O_POS": "O positif", + "O_NEG": "O négatif" + }, + "severeAllergies": "Allergies graves", + "activeMedications": "Médicaments actuels", + "chronicConditions": "Maladies chroniques", + "implants": "Implants et dispositifs", + "advanceDirective": "Directives anticipées", + "advanceDirectiveValues": { + "EXISTS": "Existent", + "NONE": "Aucune", + "UNKNOWN": "Non précisé" + }, + "organDonor": "Don d'organes", + "organDonorValues": { + "YES": "Oui", + "NO": "Non", + "UNKNOWN": "Non précisé" + }, + "contacts": "Contacts d'urgence", + "notes": "Notes complémentaires" + } }, "errorBoundary": { "title": "Une erreur est survenue", @@ -9311,6 +9347,46 @@ "loadError": "Impossible de charger vos antécédents.", "savedToast": "Affections enregistrées.", "saveError": "Impossible d'enregistrer. Veuillez réessayer." + }, + "emergency": { + "cardTitle": "Informations d'urgence", + "cardDescription": "Ce qu'un secouriste doit savoir d'abord : groupe sanguin, contacts, directives.", + "bloodType": "Groupe sanguin", + "organDonor": "Don d'organes", + "advanceDirective": "Directives anticipées", + "contacts": "Contacts d'urgence", + "implants": "Implants et dispositifs", + "note": "Notes complémentaires", + "notRecorded": "Non renseigné", + "bloodTypeValues": { + "A_POS": "A positif", + "A_NEG": "A négatif", + "B_POS": "B positif", + "B_NEG": "B négatif", + "AB_POS": "AB positif", + "AB_NEG": "AB négatif", + "O_POS": "O positif", + "O_NEG": "O négatif", + "UNKNOWN": "Inconnu" + }, + "organDonorValues": { + "YES": "Oui", + "NO": "Non", + "UNKNOWN": "Non précisé" + }, + "advanceDirectiveValues": { + "EXISTS": "Existent", + "NONE": "Aucune", + "UNKNOWN": "Non précisé" + }, + "contactsPlaceholder": "Nom et numéro de téléphone à appeler", + "implantsPlaceholder": "ex. stimulateur cardiaque, pompe à insuline, implant métallique", + "notePlaceholder": "Tout ce qu'un soignant devrait savoir en urgence", + "reportHint": "Ceci apparaît sur la première page de votre rapport médical.", + "save": "Enregistrer", + "savedToast": "Informations d'urgence enregistrées", + "saveError": "Impossible d'enregistrer vos informations d'urgence.", + "loadError": "Impossible de charger vos informations d'urgence." } }, "environment": { @@ -9834,7 +9910,8 @@ "scopeCount": "{count} éléments issus de {groups} domaines", "scopeSensitive": "dont {names}", "leafVisits": "Consultations", - "leafImmunizations": "Vaccinations" + "leafImmunizations": "Vaccinations", + "leafEmergency": "Informations d'urgence (groupe sanguin, contacts, directives)" }, "recordSharing": { "banner": { diff --git a/messages/it.json b/messages/it.json index f9a95873d..25df4a7ab 100644 --- a/messages/it.json +++ b/messages/it.json @@ -295,7 +295,43 @@ "immunizationsColDate": "Data", "immunizationsColVaccine": "Vaccino", "immunizationsColDose": "Dose", - "immunizationsColLot": "Lotto" + "immunizationsColLot": "Lotto", + "emergency": { + "title": "Informazioni di emergenza", + "subtitle": "Da usare in situazioni acute. Autodichiarato; confermare se possibile.", + "none": "Non registrato", + "unreadable": "Impossibile leggere il valore salvato", + "bloodType": "Gruppo sanguigno", + "bloodTypeUnknown": "Sconosciuto", + "bloodTypeValues": { + "A_POS": "A positivo", + "A_NEG": "A negativo", + "B_POS": "B positivo", + "B_NEG": "B negativo", + "AB_POS": "AB positivo", + "AB_NEG": "AB negativo", + "O_POS": "0 positivo", + "O_NEG": "0 negativo" + }, + "severeAllergies": "Allergie gravi", + "activeMedications": "Farmaci attuali", + "chronicConditions": "Malattie croniche", + "implants": "Impianti e dispositivi", + "advanceDirective": "Disposizioni anticipate di trattamento", + "advanceDirectiveValues": { + "EXISTS": "Presenti", + "NONE": "Nessuna", + "UNKNOWN": "Non indicato" + }, + "organDonor": "Donatore di organi", + "organDonorValues": { + "YES": "Sì", + "NO": "No", + "UNKNOWN": "Non indicato" + }, + "contacts": "Contatti di emergenza", + "notes": "Note aggiuntive" + } }, "errorBoundary": { "title": "Qualcosa è andato storto", @@ -9311,6 +9347,46 @@ "loadError": "Impossibile caricare le tue patologie.", "savedToast": "Patologie salvate.", "saveError": "Impossibile salvare. Riprova." + }, + "emergency": { + "cardTitle": "Informazioni di emergenza", + "cardDescription": "Ciò che serve subito ai soccorritori: gruppo sanguigno, contatti, disposizioni.", + "bloodType": "Gruppo sanguigno", + "organDonor": "Donatore di organi", + "advanceDirective": "Disposizioni anticipate di trattamento", + "contacts": "Contatti di emergenza", + "implants": "Impianti e dispositivi", + "note": "Note aggiuntive", + "notRecorded": "Non registrato", + "bloodTypeValues": { + "A_POS": "A positivo", + "A_NEG": "A negativo", + "B_POS": "B positivo", + "B_NEG": "B negativo", + "AB_POS": "AB positivo", + "AB_NEG": "AB negativo", + "O_POS": "0 positivo", + "O_NEG": "0 negativo", + "UNKNOWN": "Sconosciuto" + }, + "organDonorValues": { + "YES": "Sì", + "NO": "No", + "UNKNOWN": "Non indicato" + }, + "advanceDirectiveValues": { + "EXISTS": "Presenti", + "NONE": "Nessuna", + "UNKNOWN": "Non indicato" + }, + "contactsPlaceholder": "Nome e numero di telefono di chi chiamare", + "implantsPlaceholder": "es. pacemaker, microinfusore, impianto metallico", + "notePlaceholder": "Qualsiasi cosa un medico dovrebbe sapere in emergenza", + "reportHint": "Compare sulla prima pagina del referto medico.", + "save": "Salva", + "savedToast": "Informazioni di emergenza salvate", + "saveError": "Impossibile salvare le informazioni di emergenza.", + "loadError": "Impossibile caricare le informazioni di emergenza." } }, "environment": { @@ -9834,7 +9910,8 @@ "scopeCount": "{count} voci da {groups} aree", "scopeSensitive": "incl. {names}", "leafVisits": "Visite mediche", - "leafImmunizations": "Vaccinazioni" + "leafImmunizations": "Vaccinazioni", + "leafEmergency": "Informazioni di emergenza (gruppo sanguigno, contatti, disposizioni)" }, "recordSharing": { "banner": { diff --git a/messages/pl.json b/messages/pl.json index 3d1f1b0c3..d27c7ecd8 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -295,7 +295,43 @@ "immunizationsColDate": "Data", "immunizationsColVaccine": "Szczepionka", "immunizationsColDose": "Dawka", - "immunizationsColLot": "Seria" + "immunizationsColLot": "Seria", + "emergency": { + "title": "Informacje na wypadek nagły", + "subtitle": "Do użycia w sytuacji nagłej. Dane deklarowane; potwierdź, jeśli to możliwe.", + "none": "Nie podano", + "unreadable": "Nie udało się odczytać zapisanej wartości", + "bloodType": "Grupa krwi", + "bloodTypeUnknown": "Nieznana", + "bloodTypeValues": { + "A_POS": "A dodatnia", + "A_NEG": "A ujemna", + "B_POS": "B dodatnia", + "B_NEG": "B ujemna", + "AB_POS": "AB dodatnia", + "AB_NEG": "AB ujemna", + "O_POS": "0 dodatnia", + "O_NEG": "0 ujemna" + }, + "severeAllergies": "Ciężkie alergie", + "activeMedications": "Aktualne leki", + "chronicConditions": "Choroby przewlekłe", + "implants": "Implanty i urządzenia", + "advanceDirective": "Oświadczenie woli pacjenta", + "advanceDirectiveValues": { + "EXISTS": "Istnieje", + "NONE": "Brak", + "UNKNOWN": "Nie podano" + }, + "organDonor": "Dawca narządów", + "organDonorValues": { + "YES": "Tak", + "NO": "Nie", + "UNKNOWN": "Nie podano" + }, + "contacts": "Kontakty w nagłych wypadkach", + "notes": "Dodatkowe uwagi" + } }, "errorBoundary": { "title": "Coś poszło nie tak", @@ -9311,6 +9347,46 @@ "loadError": "Nie udało się wczytać Twoich chorób.", "savedToast": "Choroby zapisane.", "saveError": "Nie udało się zapisać. Spróbuj ponownie." + }, + "emergency": { + "cardTitle": "Informacje na wypadek nagły", + "cardDescription": "To, czego ratownik potrzebuje najpierw: grupa krwi, kontakty, oświadczenia.", + "bloodType": "Grupa krwi", + "organDonor": "Dawca narządów", + "advanceDirective": "Oświadczenie woli pacjenta", + "contacts": "Kontakty w nagłych wypadkach", + "implants": "Implanty i urządzenia", + "note": "Dodatkowe uwagi", + "notRecorded": "Nie podano", + "bloodTypeValues": { + "A_POS": "A dodatnia", + "A_NEG": "A ujemna", + "B_POS": "B dodatnia", + "B_NEG": "B ujemna", + "AB_POS": "AB dodatnia", + "AB_NEG": "AB ujemna", + "O_POS": "0 dodatnia", + "O_NEG": "0 ujemna", + "UNKNOWN": "Nieznana" + }, + "organDonorValues": { + "YES": "Tak", + "NO": "Nie", + "UNKNOWN": "Nie podano" + }, + "advanceDirectiveValues": { + "EXISTS": "Istnieje", + "NONE": "Brak", + "UNKNOWN": "Nie podano" + }, + "contactsPlaceholder": "Imię i numer telefonu osoby do kontaktu", + "implantsPlaceholder": "np. rozrusznik serca, pompa insulinowa, implant metalowy", + "notePlaceholder": "Wszystko, co lekarz powinien wiedzieć w nagłym wypadku", + "reportHint": "Pojawia się na pierwszej stronie raportu dla lekarza.", + "save": "Zapisz", + "savedToast": "Informacje na wypadek nagły zapisane", + "saveError": "Nie udało się zapisać informacji na wypadek nagły.", + "loadError": "Nie udało się wczytać informacji na wypadek nagły." } }, "environment": { @@ -9834,7 +9910,8 @@ "scopeCount": "{count} pozycji z {groups} obszarów", "scopeSensitive": "w tym {names}", "leafVisits": "Wizyty lekarskie", - "leafImmunizations": "Szczepienia" + "leafImmunizations": "Szczepienia", + "leafEmergency": "Informacje na wypadek nagły (grupa krwi, kontakty, oświadczenia)" }, "recordSharing": { "banner": { diff --git a/src/components/records/emergency-profile-manager.tsx b/src/components/records/emergency-profile-manager.tsx new file mode 100644 index 000000000..ef27daa44 --- /dev/null +++ b/src/components/records/emergency-profile-manager.tsx @@ -0,0 +1,192 @@ +"use client"; + +import { useState } from "react"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { Loader2 } from "lucide-react"; +import { toast } from "sonner"; + +import { Button } from "@/components/ui/button"; +import { Label } from "@/components/ui/label"; +import { QueryErrorCard } from "@/components/ui/query-error-card"; +import { Textarea } from "@/components/ui/textarea"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { toastWrittenOutcome } from "@/components/outcome/outcome-toast"; +import { apiGet, apiPatch } from "@/lib/api/api-fetch"; +import { useTranslations } from "@/lib/i18n/context"; +import { queryKeys } from "@/lib/query-keys"; +import { + ADVANCE_DIRECTIVE_STATUS_VALUES, + EMERGENCY_BLOOD_TYPE_VALUES, + EMERGENCY_CONTACTS_MAX, + EMERGENCY_IMPLANTS_MAX, + EMERGENCY_NOTE_MAX, + ORGAN_DONOR_STATUS_VALUES, + type EmergencyProfileDto, +} from "@/lib/validations/emergency-profile"; + +interface Draft { + bloodType: string; + organDonor: string; + advanceDirective: string; + contacts: string; + implants: string; + note: string; +} + +function draftFromDto(dto: EmergencyProfileDto): Draft { + return { + bloodType: dto.bloodType ?? "", + organDonor: dto.organDonor ?? "", + advanceDirective: dto.advanceDirective ?? "", + contacts: dto.contacts ?? "", + implants: dto.implants ?? "", + note: dto.note ?? "", + }; +} + +export function EmergencyProfileManager() { + const { t } = useTranslations(); + const queryClient = useQueryClient(); + const [draft, setDraft] = useState(null); + + const query = useQuery({ + queryKey: queryKeys.emergencyProfile(), + queryFn: () => apiGet("/api/anamnesis/emergency"), + }); + + const current = draft ?? (query.data ? draftFromDto(query.data) : null); + + const save = useMutation({ + mutationKey: queryKeys.emergencyProfile(), + mutationFn: (input: Draft) => + apiPatch("/api/anamnesis/emergency", { + // A select left at "" is "not recorded" and is omitted so a partial + // save leaves the column untouched; the free-text fields always ride, + // with an emptied field clearing its column server-side. + ...(input.bloodType ? { bloodType: input.bloodType } : {}), + ...(input.organDonor ? { organDonor: input.organDonor } : {}), + ...(input.advanceDirective + ? { advanceDirective: input.advanceDirective } + : {}), + contacts: input.contacts, + implants: input.implants, + note: input.note, + }), + onSuccess: (data) => { + setDraft(draftFromDto(data)); + queryClient.setQueryData(queryKeys.emergencyProfile(), data); + toastWrittenOutcome("success", t("records.emergency.savedToast")); + }, + onError: () => toast.error(t("records.emergency.saveError")), + }); + + if (query.isError) { + return ( + void query.refetch()} + /> + ); + } + + const disabled = query.isLoading || save.isPending || current === null; + const set = (patch: Partial) => + setDraft((prev) => ({ ...(prev ?? draftFromDto(query.data!)), ...patch })); + + const enumField = ( + key: "bloodType" | "organDonor" | "advanceDirective", + values: readonly string[], + valuePrefix: string, + ) => ( +
+ + +
+ ); + + const textField = ( + key: "contacts" | "implants" | "note", + max: number, + rows: number, + ) => ( +
+ +