"use client"; import { useState } from "react"; import { HistorieBearbeiten } from "@/components/employees/HistorieBearbeiten"; import { HistorieLoeschen } from "@/components/employees/HistorieLoeschen"; import { AenderungsTabelle } from "@/components/ui/AenderungsTabelle"; import { TextField } from "@/components/ui/Field"; import { SegmentedControl } from "@/components/ui/SegmentedControl"; import { actionBadgeStyle } from "@/lib/colors"; import { fmtDate, todayIso } from "@/lib/format"; import { darfBearbeitetWerden, darfKorrigiertWerden, loeschVorschau } from "@/lib/history"; import type { Database } from "@/lib/types"; type HistoryRow = Database["public"]["Tables"]["employee_history"]["Row"]; // Die Geschichte einer Person — aufklappbar bis auf die Werte, filterbar, und // dort, wo ein Eintrag irrtümlich entstanden ist, auch zurücknehmbar. // // Vorher stand hier nur „Geänderte Felder: Adresse, Ort". Damit liess sich // zwar sehen, *dass* jemand die Anschrift angefasst hat, aber nicht, was // vorher dort stand. Die alte Adresse lag allein im Protokoll, und das ist // eine andere Seite, nach Zeitpunkt sortiert statt nach Person — man hätte // also erst wissen müssen, wonach man sucht. // // Aufgeklappt wird mit
, nicht mit einem Zustand im Browser: die // Werte stehen dann schon in der Seite, sind durchsuchbar (Strg+F) und im // Ausdruck sichtbar, und es braucht kein Skript dafür. // // Die Knöpfe erscheinen nur an Einträgen, wo sie etwas bewirken können. An // allen anderen steht stattdessen der Grund — leise, aber lesbar. Ein Knopf, // der erst nach dem Klick sagt „geht nicht", wäre eine Falle; ein fehlender // Knopf ohne Erklärung wäre ein Rätsel. type Sicht = "alle" | "anstehend" | "erledigt"; const SICHTEN: { value: Sicht; label: string }[] = [ { value: "alle", label: "Alle" }, { value: "anstehend", label: "Anstehend" }, { value: "erledigt", label: "Gelaufen" }, ]; export function HistorieTab({ history, employeeId }: { history: HistoryRow[]; employeeId: string }) { const today = todayIso(); const [sicht, setSicht] = useState("alle"); const [von, setVon] = useState(""); const [bis, setBis] = useState(""); // Ereignistypen, die in dieser Akte überhaupt vorkommen — eine Auswahl aus // elf Typen, von denen zehn nie auftauchen, wäre nur Suchaufwand. const vorhandeneTypen = [...new Set(history.map((h) => h.event_type))]; const [typen, setTypen] = useState>(new Set()); const gefiltert = history.filter((h) => { if (sicht === "anstehend" && h.event_date <= today) return false; if (sicht === "erledigt" && h.event_date > today) return false; if (von && h.event_date < von) return false; if (bis && h.event_date > bis) return false; if (typen.size > 0 && !typen.has(h.event_type)) return false; return true; }); const anstehend = history.filter((h) => h.event_date > today).length; const eingeschraenkt = sicht !== "alle" || Boolean(von) || Boolean(bis) || typen.size > 0; function typUmschalten(typ: string) { setTypen((prev) => { const next = new Set(prev); if (next.has(typ)) next.delete(typ); else next.add(typ); return next; }); } function zuruecksetzen() { setSicht("alle"); setVon(""); setBis(""); setTypen(new Set()); } if (history.length === 0) { return

Keine Historieneinträge vorhanden.

; } return (
value={sicht} onChange={setSicht} options={SICHTEN} /> {/* Was noch kommt, ist der häufigste Grund, hier hereinzusehen — deshalb steht die Zahl da, auch ohne dass jemand filtert. */} {anstehend > 0 && ( {anstehend} anstehend )}
{vorhandeneTypen.length > 1 && (
{vorhandeneTypen.map((typ) => ( ))} {eingeschraenkt && ( )}
)}
{gefiltert.length === 0 ? (

Kein Eintrag passt zu dieser Auswahl. {history.length} {history.length === 1 ? "Eintrag" : "Einträge"} sind vorhanden.

) : (
    {gefiltert.map((h) => { const isFuture = h.event_date > today; const changes = h.changes ?? []; // Die ganze Historie mitgeben, nicht die gefilterte: ob eine // Abwesenheit gelöscht werden darf, hängt an einer späteren // Rückkehr — auch wenn die gerade ausgeblendet ist. const loeschbar = darfKorrigiertWerden(h, today, history); const bearbeitbar = darfBearbeitetWerden(h, today, history); return (
  • {h.event_type} {fmtDate(h.event_date)} {isFuture && ( ⏱ zukünftig – wirksam ab {fmtDate(h.event_date)} )} {bearbeitbar.erlaubt && ( )} {loeschbar.erlaubt && ( )}

    {h.description}

    {changes.length > 0 && (
    {changes.length} {changes.length === 1 ? "Feld" : "Felder"} im Detail
    {!loeschbar.erlaubt &&

    {loeschbar.grund}

    }
    )}
  • ); })}
)}
); }