"use client"; import { SelectField, TextField } from "@/components/ui/Field"; import { BEGUENSTIGUNG_AB_GRAD, GRUND_BEGUENSTIGT_BEHINDERT, KUENDIGUNGSSCHUTZ_GRUENDE, } from "@/lib/kuendigungsschutz"; import { MITARBEITERARTEN } from "@/lib/mitarbeiterart"; import { sortiereWochentage, WOCHENTAGE } from "@/lib/wochentage"; import type { CollectiveAgreement, DienstwagenArt, Mitarbeiterart, SourceType, Weekday, WorkerType } from "@/lib/types"; export type RoleEmploymentValue = { workerType: WorkerType; /** * Form der Beschäftigung — zweite Achse neben der Gruppe. Ein Praktikant * kann Arbeiter oder Angestellter sein; in einem Feld liesse sich nur eines * von beidem sagen. */ mitarbeiterart: Mitarbeiterart; /** * Extern oder intern besetzt. * * Wurde bisher nur bei der Neueinstellung gesetzt und war danach * unerreichbar — eine Angabe, die mit dem ersten Tag erstarrt, obwohl * gerade ihr Wechsel der Vorgang ist, um den es geht: von extern auf * intern ist eine **Übernahme** und wird als eigenes Ereignis protokolliert * (Migration 20260917120000). * * Nicht gesetzt heisst: dieses Formular fragt die Besetzungsart nicht. So * ist es im Einstellungsassistenten — dort steht sie im Schritt „Position", * wo sie hingehört, und zweimal danach zu fragen wäre eine Einladung, zwei * verschiedene Antworten zu geben. */ source?: SourceType; collectiveAgreement: CollectiveAgreement; workDays: Weekday[]; isBetriebsrat: boolean; hasDienstwagen: boolean; /** * Nur bedeutsam, solange hasDienstwagen gesetzt ist. * * Der Wert bleibt beim Abwählen stehen, statt zurückgesetzt zu werden — * wer versehentlich klickt und zurückklickt, findet seine Angabe wieder. * Beim Speichern setzen die Aufrufer ihn auf null, wie es der CHECK * verlangt. */ dienstwagenArt: DienstwagenArt; isLateraleFuehrung: boolean; isCLevel: boolean; /** Betriebsrat, Mutterschutz, Karenz, begünstigte Behinderung, Lehre. */ hasKuendigungsschutz: boolean; /** * Ende des Schutzes — freiwillig. Bei einem Betriebsratsmandat steht es * fest, bei einer Schwangerschaft nicht; ein Pflichtfeld zwänge dort zu * einer erfundenen Zahl. Leer heisst „bis auf Weiteres". */ kuendigungsschutzBis: string; /** * Der Personenkreis — freiwillig, aus demselben Grund wie das Enddatum: * der Bestand trägt das Kennzeichen seit 20260814120000 ohne Grund, und ein * Pflichtfeld hätte jede Änderung an diesen Zeilen blockiert. */ kuendigungsschutzGrund: string; /** Beginn des Schutzes — ebenfalls freiwillig. */ kuendigungsschutzAb: string; /** * Begünstigte Behinderung. Eigenes Kennzeichen und nicht aus dem * Personenkreis abgeleitet: die Begünstigung besteht unabhängig davon, ob * sie als Kündigungsschutz geführt wird. Die Oberfläche stellt den * Zusammenhang her, die Datenbank koppelt die beiden nicht. */ istBeguenstigtBehindert: boolean; /** Grad in Prozent laut Bescheid. Als Text, weil ein leeres Zahlenfeld sonst 0 wäre. */ behinderungGrad: string; behinderungAb: string; behinderungBis: string; }; // Shared by the hire wizard (StepVertrag) and DatenAendernPanel — both edit // the same set of employees columns, just against different local state. export function RoleEmploymentFields({ value, onChange }: { value: RoleEmploymentValue; onChange: (patch: Partial) => void }) { function toggleWorkDay(day: Weekday) { // Sortiert und nicht angehängt: sonst hinge die gespeicherte Reihenfolge // davon ab, in welcher die Knöpfe angeklickt wurden. „Mo, Di" und „Di, // Mo" waren damit zwei Werte für dieselbe Aussage, und wer die Tage nur // nachsah und wieder herstellte, erzeugte eine Vertragsänderung in der // Akte über nichts. Siehe lib/wochentage.ts. const neu = value.workDays.includes(day) ? value.workDays.filter((d) => d !== day) : [...value.workDays, day]; onChange({ workDays: sortiereWochentage(neu) }); } // Der Personenkreis zieht das Kennzeichen mit: wer „Begünstigte behinderte // ArbeitnehmerInnen" als Grund wählt, hat die Frage damit schon beantwortet. // Eine Hilfe der Oberfläche, keine Bedingung der Datenbank — abwählen lässt // es sich weiterhin. const istBehindert = value.istBeguenstigtBehindert || value.kuendigungsschutzGrund === GRUND_BEGUENSTIGT_BEHINDERT; return (
{/* „Beschäftigtengruppe" statt „Angestellte:r / Arbeiter:in": ein Feld, das nach seinen Werten heisst, wird falsch, sobald ein dritter dazukommt. Den Namen führt der Import schon länger. */} onChange({ workerType: v as WorkerType })} options={[ { value: "Angestellte:r", label: "Angestellte:r" }, { value: "Arbeiter:in", label: "Arbeiter:in" }, { value: "Lehrling", label: "Lehrling" }, ]} /> {/* Zweites Feld und nicht dieselbe Liste erweitert: die Gruppe sagt, *als was* jemand beschäftigt ist, die Art *in welcher Form*. Beides gilt gleichzeitig — ein Praktikant ist Arbeiter oder Angestellter, nicht statt dessen. */} onChange({ mitarbeiterart: v as Mitarbeiterart })} options={MITARBEITERARTEN.map((a) => ({ value: a, label: a }))} /> {/* Der Wechsel von extern auf intern ist eine Übernahme und wird als eigenes Ereignis protokolliert — der Hinweis steht am Feld, damit niemand ihn erst im Protokoll entdeckt. Der umgekehrte Weg erzeugt nichts; das ist Absicht und keine Lücke. */} {value.source !== undefined && ( onChange({ source: v as SourceType })} options={[ { value: "Extern", label: "Extern" }, { value: "Intern", label: "Intern" }, ]} hint={value.source === "Extern" ? "Ein Wechsel auf „Intern“ wird als Übernahme protokolliert." : undefined} /> )} onChange({ collectiveAgreement: v as CollectiveAgreement })} options={[ { value: "Handel", label: "Handel" }, { value: "Süßwaren", label: "Süßwaren" }, ]} />
{/* Toggle group, not a set of fields: a fieldset names the group, and aria-pressed is what tells a screen reader a day is selected — colour alone does not. */}
Arbeitstage
{WOCHENTAGE.map((day) => ( ))}
{/* Nur sichtbar, wenn es einen gibt: eine Antriebsart ohne Fahrzeug ist keine Angabe, sondern eine Frage ohne Gegenstand — und die Datenbank weist sie ab. */} {value.hasDienstwagen && ( onChange({ dienstwagenArt: v as DienstwagenArt })} options={[ { value: "Verbrenner", label: "Verbrenner" }, { value: "Elektro", label: "Elektro (E-KFZ)" }, ]} /> )} {/* Wie bei der Antriebsart: erst sichtbar, wenn es einen Gegenstand gibt. Anders als dort aber freiwillig — leer heisst „bis auf Weiteres", nicht „vergessen". */} {value.hasKuendigungsschutz && ( <> onChange({ kuendigungsschutzGrund: v })} options={[ { value: "", label: "Nicht erfasst" }, ...KUENDIGUNGSSCHUTZ_GRUENDE.map((g) => ({ value: g, label: g })), ]} hint="Bestimmt, wer einer Beendigung zustimmen muss." /> onChange({ kuendigungsschutzAb: v })} hint="Optional." /> onChange({ kuendigungsschutzBis: v })} hint="Optional. Leer lassen, solange das Ende nicht feststeht." /> {/* ── Begünstigte Behinderung ──────────────────────────── Als Unterpunkt des Kündigungsschutzes und eingerückt — sie ist einer der zwölf Personenkreise und stand vorher als eigener Block daneben, was sie wie ein zweites, unabhängiges Thema aussehen liess. * In der Datenbank bleibt sie trotzdem ein eigenes Kennzeichen mit eigenen Feldern, und das mit Absicht: eine Bedingung „Grad nur bei diesem Personenkreis" liesse jede Korrektur am Personenkreis scheitern, solange der Grad noch dransteht — also genau beim Geradebiegen eines Fehlers. Was hier zusammengehört, muss dort nicht aneinandergekettet sein. */}
{istBehindert && (
onChange({ behinderungGrad: v })} hint={`In Prozent laut Bescheid. Die Begünstigung beginnt bei ${BEGUENSTIGUNG_AB_GRAD}%.`} /> onChange({ behinderungAb: v })} /> onChange({ behinderungBis: v })} hint="Leer heisst unbefristet." />
)}
)}
); }