feat(mitarbeiter): Vorgesetzter auch fuer Personen ohne Verzeichnis (#43)
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s

This commit was merged in pull request #43.
This commit is contained in:
2026-10-04 15:10:34 +00:00
parent 0fa41b9e08
commit 0060a55387
19 changed files with 683 additions and 49 deletions
@@ -0,0 +1,78 @@
"use client";
import { useActionState } from "react";
import { vorgesetztenSetzenAktion, type AktionsErgebnis } from "@/server/actions/mitarbeiter";
/**
* Vorgesetzten setzen oder entfernen (#020).
*
* Ein Auswahlfeld und ein Knopf, kein eigener Bearbeiten-Modus: die Zuordnung
* ist eine einzelne Angabe, und sie zu aendern soll nicht erst ein Formular
* aufklappen.
*
* Die leere Option heisst ausdruecklich „niemand“ und nicht „—“: sie ist eine
* Angabe, nicht das Fehlen einer. Wer sie waehlt und speichert, entfernt die
* Zuordnung.
*/
export function MitarbeiterVorgesetzter({
mitarbeiterId,
vorgesetzterId,
auswahl,
ausDemVerzeichnis,
}: {
mitarbeiterId: string;
vorgesetzterId: string | null;
auswahl: readonly { readonly id: string; readonly anzeigename: string }[];
ausDemVerzeichnis: boolean;
}) {
const [ergebnis, aktion, laeuft] = useActionState<AktionsErgebnis, FormData>(vorgesetztenSetzenAktion, {});
return (
<div>
<form action={aktion} className="flex flex-wrap items-end gap-2">
<input type="hidden" name="mitarbeiterId" value={mitarbeiterId} />
<label className="flex min-w-0 flex-1 flex-col gap-1 text-sm">
<span className="text-nebentext">Vorgesetzter</span>
<select
name="vorgesetzterId"
defaultValue={vorgesetzterId ?? ""}
className="min-h-11 w-full rounded-pille border border-linie bg-flaeche-hoch px-4 text-sm md:min-h-10"
>
<option value="">niemand</option>
{auswahl.map((person) => (
<option key={person.id} value={person.id}>
{person.anzeigename}
</option>
))}
</select>
</label>
<button
type="submit"
disabled={laeuft}
className="min-h-11 rounded-pille bg-akzent px-4 text-sm font-semibold text-grund md:min-h-10"
>
Speichern
</button>
</form>
{ausDemVerzeichnis ? (
<p className="mt-2 max-w-prose text-sm text-nebentext">
Diese Person kommt aus dem Verzeichnis. Liefert es einen Vorgesetzten, setzt der nächste Abgleich
die Zuordnung dort wieder nach seinem Stand; liefert es keinen, bleibt die hier gesetzte Zuordnung
stehen.
</p>
) : null}
{ergebnis.fehler ? (
<p role="alert" className="mt-2 max-w-prose text-sm text-fehler">
{ergebnis.fehler}
</p>
) : null}
{ergebnis.erfolg ? (
<p role="status" className="mt-2 text-sm text-erledigt">
{ergebnis.erfolg}
</p>
) : null}
</div>
);
}