employees.email ist die private Adresse (20260811140000). Sie taugt nicht als Dienstadresse und darf auch nicht als solche benutzt werden: der Honestly-Export geht an einen fremden Anbieter, der damit im Namen des Arbeitgebers einlaedt. Die Spalte "Email" stand dort deshalb seit jeher leer, mit einem Vermerk in lib/honestly.ts, dass die Firmenadresse im Datenmodell fehlt. Jetzt gibt es sie, und die Spalte fuellt sich. Eindeutig, aber freiwillig -- mehrere Personen ohne Adresse stoeren den Index nicht, weil null nie gleich null ist. Geschrieben wird ueber `case when ? then nullif` statt `coalesce`: eine Dienstadresse muss sich auch wieder entfernen lassen. Vier SQL-Funktionen mussten mit, weil `create or replace` die ganze Fassung ersetzt und ein ausgelassenes Feld dort still verschwindet: hire_employee und rehire_employee (beide teilen sich den Schritt "Person" -- das Formular haette das Feld gezeigt und den Wert weggeworfen), change_employee_data (sonst nicht aenderbar), apply_due_pending_changes (sonst verfiele eine auf spaeter datierte Aenderung) und die Feldkarte (sonst waere der Eintrag in der Historie nicht korrigierbar). Die Selbstpruefung am Ende prueft jede einzeln.
90 lines
3.7 KiB
TypeScript
90 lines
3.7 KiB
TypeScript
import { SvNummerField } from "@/components/employees/SvNummerField";
|
|
import { TitleFields } from "@/components/employees/TitleFields";
|
|
import { SelectField, TextField } from "@/components/ui/Field";
|
|
import { PersonalnummerField } from "./PersonalnummerField";
|
|
import type { HireDraftData } from "./types";
|
|
|
|
type StepPersonProps = {
|
|
draft: HireDraftData;
|
|
update: (patch: Partial<HireDraftData>) => void;
|
|
locations: { id: string; name: string; country: string }[];
|
|
/** Meldet die geprüfte Personalnummer und ihr Ergebnis — steuert „Weiter". */
|
|
onNummerBefund?: (befund: { nummer: number; vergeben: boolean }) => void;
|
|
/**
|
|
* Beim Wiedereintritt: die Nummer steht fest und wird nur gezeigt.
|
|
*
|
|
* Zwei Gründe. Es ist dieselbe Person und sie behält ihre Nummer — und die
|
|
* Prüfung auf Dubletten fände hier zwangsläufig einen Treffer, nämlich sie
|
|
* selbst, und sperrte das Formular mit einer Meldung, die stimmt und
|
|
* trotzdem in die Irre führt.
|
|
*/
|
|
nummerGesperrt?: boolean;
|
|
};
|
|
|
|
export function StepPerson({ draft, update, locations, onNummerBefund, nummerGesperrt }: StepPersonProps) {
|
|
return (
|
|
<div className="flex flex-col gap-4">
|
|
{nummerGesperrt ? (
|
|
<TextField
|
|
label="Personalnummer"
|
|
value={draft.personnelNumber}
|
|
onChange={() => {}}
|
|
disabled
|
|
hint="Bleibt bei einem Wiedereintritt dieselbe."
|
|
/>
|
|
) : (
|
|
<PersonalnummerField
|
|
wert={draft.personnelNumber}
|
|
onChange={(personnelNumber) => update({ personnelNumber })}
|
|
onBefund={onNummerBefund ?? (() => {})}
|
|
/>
|
|
)}
|
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
|
<TextField label="Vorname" required value={draft.firstName} onChange={(firstName) => update({ firstName })} />
|
|
<TextField label="Nachname" required value={draft.lastName} onChange={(lastName) => update({ lastName })} />
|
|
</div>
|
|
<TitleFields value={draft} onChange={update} />
|
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
|
<SelectField
|
|
label="Geschlecht"
|
|
required
|
|
value={draft.gender}
|
|
onChange={(gender) => update({ gender: gender as HireDraftData["gender"] })}
|
|
options={[
|
|
{ value: "m", label: "männlich" },
|
|
{ value: "w", label: "weiblich" },
|
|
]}
|
|
/>
|
|
<TextField label="Geburtsdatum" required type="date" value={draft.birthDate} onChange={(birthDate) => update({ birthDate })} />
|
|
</div>
|
|
<SvNummerField
|
|
value={draft.svNummer}
|
|
onChange={(svNummer) => update({ svNummer })}
|
|
locationCountry={locations.find((l) => l.id === draft.locationId)?.country}
|
|
birthDate={draft.birthDate || null}
|
|
/>
|
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
|
{/* Die private Adresse, nicht die Firmenadresse — die entsteht erst
|
|
mit dem Eintritt. Freiwillig: wer keine hat oder keine angeben
|
|
will, soll nicht gezwungen sein, eine zu erfinden. */}
|
|
<TextField label="Private E-Mail" type="email" value={draft.email} onChange={(email) => update({ email })} />
|
|
<TextField
|
|
label="Firmen-E-Mail"
|
|
type="email"
|
|
value={draft.companyEmail}
|
|
onChange={(companyEmail) => update({ companyEmail })}
|
|
/>
|
|
<TextField label="Private Telefonnummer" type="tel" value={draft.phone} onChange={(phone) => update({ phone })} />
|
|
</div>
|
|
<SelectField
|
|
label="Standort"
|
|
required
|
|
value={draft.locationId}
|
|
onChange={(locationId) => update({ locationId })}
|
|
placeholder="Bitte wählen…"
|
|
options={locations.map((l) => ({ value: l.id, label: `${l.name} (${l.country})` }))}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|