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.
120 lines
5.2 KiB
TypeScript
120 lines
5.2 KiB
TypeScript
"use client";
|
||
|
||
import { Pencil, Plus, Trash2 } from "lucide-react";
|
||
import { useRouter } from "next/navigation";
|
||
import { useState } from "react";
|
||
import { deleteEmployeeDependent } from "@/actions/employees";
|
||
import { Button } from "@/components/ui/Button";
|
||
import { useToast } from "@/components/ui/Toast";
|
||
import { fmtDate, todayIso } from "@/lib/format";
|
||
import type { Database } from "@/lib/types";
|
||
import { AddDependentModal } from "./AddDependentModal";
|
||
|
||
type Dependent = Database["public"]["Tables"]["employee_dependents"]["Row"];
|
||
|
||
// `effectiveDate` lets DatenAendernPanel embed this section and drive
|
||
// add/remove off its own "Wirksam ab" field; standalone usage (Stammdaten
|
||
// tab) omits it and defaults to today, i.e. immediate.
|
||
export function AngehoerigeSection({ employeeId, dependents, effectiveDate }: { employeeId: string; dependents: Dependent[]; effectiveDate?: string }) {
|
||
const { showToast } = useToast();
|
||
const router = useRouter();
|
||
const [modalOpen, setModalOpen] = useState(false);
|
||
const [bearbeitet, setBearbeitet] = useState<Dependent | null>(null);
|
||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||
const resolvedEffectiveDate = effectiveDate || todayIso();
|
||
|
||
async function handleDelete(dependentId: string) {
|
||
setDeletingId(dependentId);
|
||
const result = await deleteEmployeeDependent({ dependent_id: dependentId, employee_id: employeeId, effective_date: resolvedEffectiveDate });
|
||
setDeletingId(null);
|
||
if (result.success) {
|
||
showToast("Angehörige:r 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">Angehörige</h3>
|
||
<div className="flex items-center gap-4">
|
||
<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>
|
||
<span className="text-xs text-ink-muted">{dependents.length} Personen</span>
|
||
</div>
|
||
</div>
|
||
|
||
{dependents.length === 0 ? (
|
||
<p className="text-sm text-ink-muted">Keine Angehörigen hinterlegt.</p>
|
||
) : (
|
||
<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">Verhältnis</th>
|
||
<th className="px-4 py-2.5">SVNR</th>
|
||
<th className="px-4 py-2.5">Geburtsdatum</th>
|
||
<th className="px-4 py-2.5" />
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{dependents.map((d) => (
|
||
<tr key={d.id} className="border-b border-border last:border-0">
|
||
<td className="px-4 py-2.5 font-semibold text-ink">
|
||
{d.first_name} {d.last_name}
|
||
</td>
|
||
<td className="px-4 py-2.5 text-ink-body">{d.relationship}</td>
|
||
<td className="px-4 py-2.5 text-ink-body">{d.sv_nummer ?? "–"}</td>
|
||
<td className="px-4 py-2.5 text-ink-body">{fmtDate(d.birth_date)}</td>
|
||
<td className="px-4 py-2.5 text-right">
|
||
{/* Berichtigen statt löschen-und-neu-anlegen: ein
|
||
Tippfehler hinterliess sonst zwei Einträge in der
|
||
Akte, und der erste sagte „entfernt", was nicht
|
||
stimmte. */}
|
||
<Button
|
||
variant="icon"
|
||
onClick={() => setBearbeitet(d)}
|
||
aria-label={`${d.first_name} ${d.last_name} berichtigen`}
|
||
className="hover:!text-brand-700"
|
||
>
|
||
<Pencil className="h-3.5 w-3.5" />
|
||
</Button>
|
||
<Button
|
||
variant="icon"
|
||
onClick={() => handleDelete(d.id)}
|
||
pending={deletingId === d.id}
|
||
aria-label={`${d.first_name} ${d.last_name} als Angehörige:n entfernen`}
|
||
className="hover:!text-danger-solid"
|
||
>
|
||
<Trash2 className="h-3.5 w-3.5" />
|
||
</Button>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
)}
|
||
|
||
<AddDependentModal open={modalOpen} onClose={() => setModalOpen(false)} employeeId={employeeId} defaultEffectiveDate={resolvedEffectiveDate} />
|
||
|
||
{/* Eigene Einbindung mit `key`: das Fenster bleibt sonst montiert und
|
||
zeigte beim zweiten Öffnen die Felder der zuvor bearbeiteten
|
||
Person. */}
|
||
{bearbeitet && (
|
||
<AddDependentModal
|
||
key={bearbeitet.id}
|
||
open
|
||
onClose={() => setBearbeitet(null)}
|
||
employeeId={employeeId}
|
||
dependent={bearbeitet}
|
||
/>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|