"use client"; import { useRouter } from "next/navigation"; import { useState } from "react"; import { adjustKarenzReturn, recordKarenzReturn, startKarenz } from "@/actions/employees"; import { Button } from "@/components/ui/Button"; import { SelectField, TextField, TextareaField } from "@/components/ui/Field"; import { SegmentedControl } from "@/components/ui/SegmentedControl"; import { SlideOver } from "@/components/ui/SlideOver"; import { useToast } from "@/components/ui/Toast"; import { ABSENCE_TYPES, absenceLabel, RUECKKEHR_GRUENDE } from "@/lib/absence"; import { fmtDate, fmtName } from "@/lib/format"; import type { Database, EmploymentStatus } from "@/lib/types"; type EmployeeRow = Database["public"]["Tables"]["employees"]["Row"]; type Mode = "adjust" | "return"; type EmploymentMode = "unverändert" | "Vollzeit" | "Teilzeit"; export function KarenzPanel({ open, onClose, employee, status, }: { open: boolean; onClose: () => void; employee: EmployeeRow; /** Der zum heutigen Tag abgeleitete Status — nicht `employee.status`, die Spalte hängt nach. */ status: EmploymentStatus; }) { const { showToast } = useToast(); const router = useRouter(); const isOnKarenz = status === "Karenz"; const [mode, setMode] = useState("adjust"); const [pending, setPending] = useState(false); const [karenzStart, setKarenzStart] = useState(""); const [plannedReturn, setPlannedReturn] = useState(""); const [absenceType, setAbsenceType] = useState(ABSENCE_TYPES[0]); const [startNote, setStartNote] = useState(""); const [newReturnDate, setNewReturnDate] = useState(employee.karenz_return_date ?? ""); const [adjustNote, setAdjustNote] = useState(""); const [returnDate, setReturnDate] = useState(""); const [employmentMode, setEmploymentMode] = useState("unverändert"); // Warum weniger Stunden: Wiedereingliederungs- oder Elternteilzeit. Beide // beginnen typischerweise genau dann, wenn die Abwesenheit endet — deshalb // steht die Frage hier und nicht in einem zweiten Vorgang danach. const [reduktionsgrund, setReduktionsgrund] = useState(""); const [teilzeitBis, setTeilzeitBis] = useState(""); // Die Stunden, die vor der Abwesenheit galten — mit Komma, wie man sie // hierzulande schreibt. const stundenText = String(employee.weekly_hours).replace(".", ","); // Absichtlich leer statt vorbelegt: eine Zahl, die schon dasteht, wird // bestätigt statt erfasst. Die reduzierten Stunden stehen in einer // Vereinbarung, und die muss jemand ablesen. const [weeklyHours, setWeeklyHours] = useState(""); const diffDays = isOnKarenz && employee.karenz_return_date && newReturnDate ? Math.round((new Date(newReturnDate).getTime() - new Date(employee.karenz_return_date).getTime()) / 86400000) : 0; async function handleStart() { if (!karenzStart || !plannedReturn) { showToast("Bitte beide Daten angeben.", "error"); return; } setPending(true); const result = await startKarenz({ employee_id: employee.id, karenz_start_date: karenzStart, planned_return_date: plannedReturn, absence_type: absenceType, note: startNote, }); setPending(false); if (result.success) { showToast("Langzeitabwesenheit erfasst."); router.refresh(); onClose(); } else { showToast(result.error ?? "Fehler.", "error"); } } async function handleAdjust() { if (!newReturnDate || newReturnDate === employee.karenz_return_date) { showToast("Bitte ein neues Rückkehrdatum angeben.", "error"); return; } if (new Date(newReturnDate) <= new Date()) { showToast("Rückkehrdatum muss in der Zukunft liegen.", "error"); return; } setPending(true); const result = await adjustKarenzReturn({ employee_id: employee.id, new_return_date: newReturnDate, note: adjustNote }); setPending(false); if (result.success) { showToast("Rückkehrdatum angepasst."); router.refresh(); onClose(); } else { showToast(result.error ?? "Fehler.", "error"); } } async function handleReturn() { if (!returnDate) { showToast("Bitte Rückkehrdatum angeben.", "error"); return; } if (employmentMode === "Teilzeit") { if (!weeklyHours.trim()) { showToast("Bitte die reduzierten Wochenstunden erfassen.", "error"); return; } if (Number(weeklyHours) <= 0 || Number(weeklyHours) >= 38.5) { showToast("Wochenstunden müssen zwischen 0 und 38,5 liegen.", "error"); return; } } setPending(true); const result = await recordKarenzReturn({ employee_id: employee.id, return_date: returnDate, employment_mode: employmentMode, weekly_hours: employmentMode === "Teilzeit" ? Number(weeklyHours) : undefined, reduction_reason: employmentMode === "Teilzeit" ? reduktionsgrund || undefined : undefined, teilzeit_bis: employmentMode === "Teilzeit" && reduktionsgrund ? teilzeitBis || undefined : undefined, }); setPending(false); if (result.success) { showToast("Wiedereintritt erfasst."); router.refresh(); onClose(); } else { showToast(result.error ?? "Fehler.", "error"); } } return ( {/* Long-term absence keeps the warning tone it uses elsewhere. */} {!isOnKarenz && ( )} {isOnKarenz && mode === "adjust" && ( )} {isOnKarenz && mode === "return" && ( )} } > {!isOnKarenz && (
({ value: t, label: t }))} />
)} {isOnKarenz && (
value={mode} onChange={setMode} options={[ { value: "adjust", label: "Rückkehr anpassen" }, { value: "return", label: "Wiedereintritt erfassen" }, ]} /> {mode === "adjust" && ( <>

{absenceLabel(status, employee.absence_type)} {" · Rückkehr "} {fmtDate(employee.karenz_return_date)}

{diffDays !== 0 && (
0 ? "bg-warning-bg text-warning-text" : "bg-success-bg text-success-text"}`}> {diffDays > 0 ? `Verlängerung um ${diffDays} Tage` : `Verkürzung um ${Math.abs(diffDays)} Tage`}
)} )} {mode === "return" && ( <> setEmploymentMode(v as EmploymentMode)} options={[ // Die Stunden, die zuletzt gearbeitet wurden, stehen in der // Beschriftung. „unverändert" allein zwang dazu, in der // Akte nachzusehen, worauf man sich da einlässt. { value: "unverändert", label: `Wie vor Abwesenheit (${stundenText} h)` }, { value: "Teilzeit", label: "Reduziert" }, ]} /> {employmentMode === "Teilzeit" && ( <> ({ value: g, label: g })), ]} hint="Steht danach am Profil und lässt sich auswerten." /> {reduktionsgrund && ( )} )} )}
)}
); }