diff --git a/components/employees/NotfallkontaktModal.tsx b/components/employees/NotfallkontaktModal.tsx new file mode 100644 index 0000000..346d257 --- /dev/null +++ b/components/employees/NotfallkontaktModal.tsx @@ -0,0 +1,108 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useState } from "react"; +import { changeEmployeeData } from "@/actions/employees"; +import { Button } from "@/components/ui/Button"; +import { TextField } from "@/components/ui/Field"; +import { Modal } from "@/components/ui/Modal"; +import { useToast } from "@/components/ui/Toast"; +import { todayIso } from "@/lib/format"; + +// Der Notfallkontakt, ohne den Umweg über „Daten ändern". +// +// Geschrieben wird über dieselbe Funktion wie dort: change_employee_data mit +// **nur** den drei Feldern im Abschnitt `person`. Das ist keine Abkürzung, +// sondern die Bedingung dafür, dass der Eintrag in der Historie und im +// Protokoll landet wie jede andere Stammdatenänderung. Die Datenbank fasst +// ausschliesslich die Felder an, die im Aufruf stehen — sie prüft auf das +// Vorhandensein des Schlüssels, nicht auf seinen Wert (Migration +// 20260917120000). Adresse, E-Mail und der Rest bleiben deshalb unberührt. + +export type Notfallkontakt = { + name: string | null; + telefon: string | null; + verhaeltnis: string | null; +}; + +export function NotfallkontaktModal({ + open, + onClose, + employeeId, + kontakt, +}: { + open: boolean; + onClose: () => void; + employeeId: string; + kontakt: Notfallkontakt; +}) { + const { showToast } = useToast(); + const router = useRouter(); + const [name, setName] = useState(kontakt.name ?? ""); + const [telefon, setTelefon] = useState(kontakt.telefon ?? ""); + const [verhaeltnis, setVerhaeltnis] = useState(kontakt.verhaeltnis ?? ""); + const [effectiveDate, setEffectiveDate] = useState(todayIso()); + const [pending, setPending] = useState(false); + + const vorhanden = Boolean(kontakt.name); + + async function handleSubmit() { + // Name und Telefonnummer gehören zusammen: ein Name ohne Nummer hilft im + // Ernstfall niemandem, eine Nummer ohne Namen sagt nicht, wen man dran + // hat. + if (!name.trim() || !telefon.trim()) { + showToast("Name und Telefonnummer sind nötig.", "error"); + return; + } + setPending(true); + const result = await changeEmployeeData({ + employee_id: employeeId, + effective_date: effectiveDate, + person: { + emergency_contact_name: name.trim(), + emergency_contact_phone: telefon.trim(), + emergency_contact_relation: verhaeltnis.trim(), + }, + contract: {}, + role: {}, + }); + setPending(false); + if (result.success) { + showToast(vorhanden ? "Notfallkontakt geändert." : "Notfallkontakt hinterlegt."); + router.refresh(); + onClose(); + } else { + showToast(result.error ?? "Fehler beim Speichern.", "error"); + } + } + + return ( + + + + + } + > +
+ + + + +
+
+ ); +} diff --git a/components/employees/NotfallkontaktSection.tsx b/components/employees/NotfallkontaktSection.tsx new file mode 100644 index 0000000..c94d992 --- /dev/null +++ b/components/employees/NotfallkontaktSection.tsx @@ -0,0 +1,127 @@ +"use client"; + +import { Pencil, Plus, Trash2 } from "lucide-react"; +import { useRouter } from "next/navigation"; +import { useState } from "react"; +import { changeEmployeeData } from "@/actions/employees"; +import { Button } from "@/components/ui/Button"; +import { useToast } from "@/components/ui/Toast"; +import { todayIso } from "@/lib/format"; +import { NotfallkontaktModal, type Notfallkontakt } from "./NotfallkontaktModal"; + +// Eigener Abschnitt statt einer Zelle im Raster, und unterhalb der +// Angehörigen: beides sind Personen im Umfeld, und der Notfallkontakt ist die +// Ausnahme davon — deshalb steht er zuletzt, nicht dazwischen. Im Ernstfall +// greift jemand in Eile danach; dann muss die Nummer sofort zu finden sein +// und wählbar. +// +// Der Knopf steht hier, weil er bei den Angehörigen darüber auch steht. Ohne +// ihn führte der einzige Weg über „Daten ändern" — ein Formular über alle +// Stammdaten, um eine Telefonnummer einzutragen. + +export function NotfallkontaktSection({ employeeId, kontakt }: { employeeId: string; kontakt: Notfallkontakt }) { + const { showToast } = useToast(); + const router = useRouter(); + const [modalOpen, setModalOpen] = useState(false); + const [entfernt, setEntfernt] = useState(false); + + const vorhanden = Boolean(kontakt.name); + + async function handleEntfernen() { + setEntfernt(true); + // Leere Zeichenketten, nicht ausgelassene Felder: die Datenbank macht + // daraus null. Würden die Schlüssel fehlen, bliebe der Kontakt stehen. + const result = await changeEmployeeData({ + employee_id: employeeId, + effective_date: todayIso(), + person: { emergency_contact_name: "", emergency_contact_phone: "", emergency_contact_relation: "" }, + contract: {}, + role: {}, + }); + setEntfernt(false); + if (result.success) { + showToast("Notfallkontakt entfernt."); + router.refresh(); + } else { + showToast(result.error ?? "Fehler beim Entfernen.", "error"); + } + } + + return ( +
+
+

Notfallkontakt

+
+ + {vorhanden && ( + + )} +
+
+ + {vorhanden ? ( +
+
+
Name
+
{kontakt.name}
+
+
+
Telefon
+
+ {kontakt.telefon ? ( + + {kontakt.telefon} + + ) : ( + "–" + )} +
+
+
+
Verhältnis
+
{kontakt.verhaeltnis || "–"}
+
+
+ ) : ( +

Kein Notfallkontakt hinterlegt.

+ )} + + {/* `key` setzt die Felder auf den gespeicherten Stand zurück, sobald + sich der Kontakt geändert hat — das Fenster bleibt sonst montiert + und zeigte beim zweiten Öffnen den alten Entwurf. */} + setModalOpen(false)} + employeeId={employeeId} + kontakt={kontakt} + /> +
+ ); +} diff --git a/components/employees/tabs/StammdatenTab.tsx b/components/employees/tabs/StammdatenTab.tsx index a265b17..9524345 100644 --- a/components/employees/tabs/StammdatenTab.tsx +++ b/components/employees/tabs/StammdatenTab.tsx @@ -1,4 +1,5 @@ import { AngehoerigeSection } from "@/components/employees/AngehoerigeSection"; +import { NotfallkontaktSection } from "@/components/employees/NotfallkontaktSection"; import { brauchtAufenthaltstitel } from "@/lib/countries"; import { fmtAge, fmtDate } from "@/lib/format"; import type { Database } from "@/lib/types"; @@ -71,43 +72,14 @@ export function StammdatenTab({ employee, location, dependents }: { employee: Em - {/* Eigener Abschnitt statt einer Zelle im Raster, und unterhalb der - Angehörigen: beides sind Personen im Umfeld, und der Notfallkontakt - ist die Ausnahme davon — deshalb steht er zuletzt, nicht dazwischen. - Im Ernstfall greift jemand in Eile danach; dann muss die Nummer - sofort zu finden sein und wählbar. */} -
-

Notfallkontakt

- {employee.emergency_contact_name ? ( -
-
-
Name
-
{employee.emergency_contact_name}
-
-
-
Telefon
-
- {employee.emergency_contact_phone ? ( - - {employee.emergency_contact_phone} - - ) : ( - "–" - )} -
-
-
-
Verhältnis
-
{employee.emergency_contact_relation || "–"}
-
-
- ) : ( -

Kein Notfallkontakt hinterlegt.

- )} -
+ ); }