Angehoerige liessen sich bisher nur anlegen und entfernen. Ein Tippfehler im Namen war nur zu beheben, indem man die Person loeschte und neu anlegte -- zwei Eintraege in der Akte fuer eine Korrektur, und der erste sagte "entfernt", was nicht stimmte. Jetzt steht in jeder Zeile ein Stift, wie beim Notfallkontakt. update_employee_dependent kommt bewusst **ohne** Stichtag. Hinzufuegen und Entfernen tragen einen, dort passiert etwas zu einem Zeitpunkt. Eine Berichtigung nicht: der Wert war schon vorher falsch, und ein "wirksam ab" hiesse, die Person habe bis dahin anders geheissen. Der Eintrag in der Akte nennt deshalb Vorher und Nachher statt eines Datums. In "Daten aendern" standen fuer den Notfallkontakt drei Eingabefelder, waehrend die Angehoerigen darueber als Tabelle mit Knoepfen erscheinen -- zwei Bauformen fuer denselben Zweck, direkt untereinander. Dort steht jetzt derselbe Abschnitt wie im Reiter "Stammdaten"; beide laufen ueber das "Wirksam ab" des Formulars, wie die Angehoerigen es schon taten. Damit schreibt auch nur noch eine Stelle diese drei Spalten. Vorher schickte das Formular sie zusaetzlich im eigenen Aufruf mit.
157 lines
6.2 KiB
TypeScript
157 lines
6.2 KiB
TypeScript
"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,
|
||
effectiveDate,
|
||
}: {
|
||
employeeId: string;
|
||
kontakt: Notfallkontakt;
|
||
/**
|
||
* Nur, wenn der Abschnitt in „Daten ändern" steht: dann treibt dessen
|
||
* „Wirksam ab" auch diesen Vorgang — wie bei den Angehörigen darüber.
|
||
* Ohne Angabe gilt heute.
|
||
*/
|
||
effectiveDate?: string;
|
||
}) {
|
||
const { showToast } = useToast();
|
||
const router = useRouter();
|
||
const [modalOpen, setModalOpen] = useState(false);
|
||
const [entfernt, setEntfernt] = useState(false);
|
||
const stichtag = effectiveDate || todayIso();
|
||
|
||
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: stichtag,
|
||
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 (
|
||
<div className="border-t border-border pt-6">
|
||
<div className="mb-3 flex items-center justify-between">
|
||
<h3 className="text-xs font-bold uppercase tracking-wide text-brand-700">Notfallkontakt</h3>
|
||
{/* Nur, solange keiner hinterlegt ist: es gibt genau einen. Ein
|
||
zweites „Hinzufügen" daneben verspräche eine Liste, die es hier
|
||
nicht gibt — geändert und entfernt wird in der Zeile selbst. */}
|
||
{!vorhanden && (
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={() => setModalOpen(true)}
|
||
className="!px-1 text-brand-700 hover:!bg-transparent hover:underline"
|
||
>
|
||
<Plus className="h-3.5 w-3.5" /> Hinzufügen
|
||
</Button>
|
||
)}
|
||
</div>
|
||
|
||
{/* Dieselbe Tabelle wie bei den Angehörigen darüber, Zeile für Zeile
|
||
derselbe Aufbau. Vorher stand hier eine Beschreibungsliste — fachlich
|
||
dasselbe, optisch ein zweiter Baustil im selben Reiter. Zwei Listen
|
||
von Personen im Umfeld sollen gleich aussehen. */}
|
||
{vorhanden ? (
|
||
<div className="overflow-x-auto rounded border border-border">
|
||
<table className="w-full min-w-[600px] text-sm">
|
||
<thead>
|
||
<tr className="border-b border-border bg-accent-50 text-left text-xs font-semibold uppercase tracking-wide text-ink-muted">
|
||
<th className="px-4 py-2.5">Name</th>
|
||
<th className="px-4 py-2.5">Telefon</th>
|
||
<th className="px-4 py-2.5">Verhältnis</th>
|
||
<th className="px-4 py-2.5" />
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr className="border-b border-border last:border-0">
|
||
<td className="px-4 py-2.5 font-semibold text-ink">{kontakt.name}</td>
|
||
<td className="px-4 py-2.5 text-ink-body">
|
||
{kontakt.telefon ? (
|
||
// Wählbar: im Ernstfall greift jemand in Eile danach.
|
||
<a
|
||
href={`tel:${kontakt.telefon.replace(/\s/g, "")}`}
|
||
className="rounded font-semibold hover:text-brand-700 hover:underline
|
||
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-500"
|
||
>
|
||
{kontakt.telefon}
|
||
</a>
|
||
) : (
|
||
"–"
|
||
)}
|
||
</td>
|
||
<td className="px-4 py-2.5 text-ink-body">{kontakt.verhaeltnis || "–"}</td>
|
||
<td className="px-4 py-2.5 text-right">
|
||
<Button
|
||
variant="icon"
|
||
onClick={() => setModalOpen(true)}
|
||
aria-label="Notfallkontakt ändern"
|
||
className="hover:!text-brand-700"
|
||
>
|
||
<Pencil className="h-3.5 w-3.5" />
|
||
</Button>
|
||
<Button
|
||
variant="icon"
|
||
onClick={handleEntfernen}
|
||
pending={entfernt}
|
||
aria-label="Notfallkontakt entfernen"
|
||
className="hover:!text-danger-solid"
|
||
>
|
||
<Trash2 className="h-3.5 w-3.5" />
|
||
</Button>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
) : (
|
||
<p className="text-sm text-ink-muted">Kein Notfallkontakt hinterlegt.</p>
|
||
)}
|
||
|
||
{/* `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. */}
|
||
<NotfallkontaktModal
|
||
key={`${kontakt.name ?? ""}|${kontakt.telefon ?? ""}|${kontakt.verhaeltnis ?? ""}`}
|
||
open={modalOpen}
|
||
onClose={() => setModalOpen(false)}
|
||
employeeId={employeeId}
|
||
kontakt={kontakt}
|
||
effectiveDate={stichtag}
|
||
/>
|
||
</div>
|
||
);
|
||
}
|