import Link from "next/link"; import { Plus, Upload, User } from "lucide-react"; import { MitarbeiterAnlegen } from "@/components/mitarbeiter-anlegen"; import { MitarbeiterImportieren } from "@/components/mitarbeiter-importieren"; import { MitarbeiterSuche } from "@/components/mitarbeiter-suche"; import { StammdatenReiter } from "@/components/stammdaten-reiter"; import { Herkunft } from "@/generated/prisma/enums"; import { darf } from "@/server/auth/rollen"; import { sitzungErforderlich } from "@/server/auth/sitzungspflicht"; import { kundenEbeneSichtbar } from "@/server/mandant"; import { kundenListe } from "@/server/queries/kunden"; import { abteilungsNamen, mitarbeiterListe, type MitarbeiterZeile } from "@/server/queries/mitarbeiter"; import { MITARBEITER_IMPORT_HOECHSTZEILEN, MITARBEITER_IMPORT_SPALTEN } from "@/server/services/mitarbeiter"; /** * Mitarbeiterliste (#011). * * Gesucht wird ueber Anzeigename, Mail, UPN und `sam` — im Ticket steht mal das * eine, mal das andere. Standardmaessig erscheinen nur aktive Personen; fuers * Offboarding gibt es den Umschalter. * * Die Filter laufen als GET-Formular ueber die Adresse: ein gesetzter Filter ist * dann verlinkbar, der Zurueck-Knopf tut das Erwartete, und die Seite bleibt * eine Server-Komponente, die nur die sichtbaren Zeilen laedt. */ function Zeile({ zeile, kundenEbene }: { zeile: MitarbeiterZeile; kundenEbene: boolean }) { const kennungen = [zeile.mail, zeile.upn === zeile.mail ? null : zeile.upn, zeile.sam] .filter(Boolean) .join(" · "); return (
  • {kennungen ?

    {kennungen}

    : null}

    {[ zeile.abteilung, zeile.titel, `${zeile.anzahlGeraete} ${zeile.anzahlGeraete === 1 ? "Gerät" : "Geräte"}`, `${zeile.anzahlLaeufe} ${zeile.anzahlLaeufe === 1 ? "Lauf" : "Läufe"}`, ] .filter(Boolean) .join(" · ")}

  • ); } export default async function MitarbeiterSeite({ searchParams, }: { searchParams: Promise>; }) { const { benutzer } = await sitzungErforderlich("lesen", "/mitarbeiter"); const parameter = await searchParams; const einzeln = (name: string): string => (Array.isArray(parameter[name]) ? parameter[name][0] : parameter[name])?.trim() ?? ""; const filter = { suche: einzeln("suche"), abteilung: einzeln("abteilung"), auchDeaktivierte: einzeln("deaktivierte") === "1", }; const darfBearbeiten = darf(benutzer.rolle, "mitarbeiterBearbeiten"); const [zeilen, abteilungen, kundenEbene] = await Promise.all([ mitarbeiterListe(benutzer, filter), abteilungsNamen(benutzer), kundenEbeneSichtbar(), ]); const kunden = kundenEbene && darfBearbeiten ? await kundenListe(benutzer) : []; return ( <>

    {kundenEbene ? "Personen" : "Mitarbeiter"}

    Personen werden nie gelöscht, nur deaktiviert — ein archivierter Lauf muss auch in zehn Jahren noch sagen können, für wen er lief.

    {zeilen.length === 0 ? (

    Keine Person passt zu diesen Filtern.

    ) : ( )} {darfBearbeiten ? (

    Für das Onboarding, bevor der nächste Verzeichnisabgleich gelaufen ist. Eine so angelegte Person bleibt vollständig änderbar.

    ({ id, name }))} abteilungen={abteilungen} />
    ) : null} {darfBearbeiten ? ( /* * Der CSV-Import steht neben dem Formular und verlangt dasselbe Recht * (#016): wer eine Person eintragen darf, darf auch zwanzig auf einmal * eintragen. Zugeklappt, weil die tägliche Arbeit die Liste ist. */
    namen[0])} kunden={kunden.map(({ id, name }) => ({ id, name }))} />
    ) : null} ); }