Die Kachel verwies auf eine Adresse, die die Liste nicht lesen konnte

Die neue Kachel "Aktives Dienstverhaeltnis" verlinkte auf
?status=Aktiv&status=Karenz. Die Mitarbeiterliste liest den Parameter aber
als *eine* Zeichenkette und trennt selbst an Kommas — zweimal uebergeben
macht Next daraus ein Array, und `.split(",")` lief dagegen. Sichtbar war
nur "Diese Ansicht konnte nicht geladen werden".

Die Kachel schreibt jetzt status=Aktiv,Karenz. Dazu glaettet die Seite alle
ihre Parameter: eine Adresse kommt nicht nur aus der eigenen Anwendung, sie
steht in Lesezeichen und in E-Mails, und ?q=a&q=b haette sie genauso
gefaellt.

Zwei Anmerkungen von Max:

  * Die Reihenfolge der Wochentage wurde beim Speichern mitgenommen — "Mo,
    Di" und "Di, Mo" waren zwei Werte fuer dieselbe Aussage. Da
    change_employee_data die Arbeitstage als zusammengefuegte Zeichenkette
    vergleicht, erzeugte jedes Nachsehen und Wiederherstellen eine
    Vertragsaenderung in der Akte und einen Protokolleintrag — ueber nichts.
    Jetzt sortiert gespeichert (lib/wochentage.ts, an einer Stelle statt in
    vier Kopien), auch im Massenimport. Der Bestand richtet sich beim
    naechsten Speichern von selbst.
  * "Beguenstigt behindert" steht jetzt als eingerueckter Unterpunkt des
    Kuendigungsschutzes statt als eigener Block daneben. In der Datenbank
    bleiben es getrennte Felder, und das mit Absicht: eine Kopplung liesse
    jede Korrektur am Personenkreis scheitern, solange der Grad noch
    dransteht.
This commit is contained in:
2026-09-16 22:06:38 +02:00
parent 05d56bf3b9
commit 4dc27bf212
8 changed files with 202 additions and 60 deletions

View File

@@ -26,6 +26,22 @@ import type { EmploymentStatus } from "@/lib/types";
const PAGE_SIZE = 15;
/**
* Die Parameter, nachdem sie geglättet sind — je einer, oder keiner.
*
* Was Next tatsächlich liefert, steht in RohParams: derselbe Name zweimal in
* der Adresse wird dort zu einem Array. Diese Seite hat das nicht erwartet
* und ist daran gescheitert — eine Kachel der Übersicht verwies auf
* `?status=Aktiv&status=Karenz`, und `params.status.split(",")` lief gegen
* ein Array. Sichtbar war davon nur „Diese Ansicht konnte nicht geladen
* werden" mit einer Fehlerkennung.
*
* Die Kachel ist berichtigt (sie schreibt jetzt `status=Aktiv,Karenz`), aber
* eine Adresse kommt nicht nur aus der eigenen Anwendung: sie steht in
* Lesezeichen, in Verknüpfungen, in E-Mails. Deshalb wird hier geglättet
* statt sich darauf zu verlassen, dass niemand zweimal denselben Namen
* schreibt.
*/
type SearchParams = {
q?: string;
division?: string;
@@ -36,8 +52,27 @@ type SearchParams = {
page?: string;
};
type RohParams = Record<string, string | string[] | undefined>;
/** Der erste Wert eines Parameters — auch wenn er mehrfach in der Adresse steht. */
function einWert(wert: string | string[] | undefined): string | undefined {
return Array.isArray(wert) ? wert[0] : wert;
}
function glaetten(roh: RohParams): SearchParams {
return {
q: einWert(roh.q),
division: einWert(roh.division),
status: einWert(roh.status),
location: einWert(roh.location),
sort: einWert(roh.sort),
dir: einWert(roh.dir),
page: einWert(roh.page),
};
}
type EmployeesPageProps = {
searchParams: Promise<SearchParams>;
searchParams: Promise<RohParams>;
};
function pageHref(params: SearchParams, page: number): string {
@@ -72,7 +107,7 @@ function sortHref(params: SearchParams, feld: Sortierfeld, aktuell: Sortierfeld,
}
export default async function EmployeesPage({ searchParams }: EmployeesPageProps) {
const params = await searchParams;
const params = glaetten(await searchParams);
const page = Math.max(1, Number(params.page ?? "1") || 1);
const sortFeld = parseFeld(params.sort);
const sortRichtung = parseRichtung(params.dir);

View File

@@ -184,7 +184,10 @@ export default async function DashboardPage({
label: "Aktives Dienstverhältnis",
value: activeCount + karenzCount,
tone: "default",
href: "/employees?status=Aktiv&status=Karenz",
// Mit Komma, nicht zweimal `status=`: die Liste liest den Parameter als
// *eine* Zeichenkette und trennt selbst. Zweimal übergeben macht Next
// daraus ein Array, und die Seite scheiterte an `.split(",")`.
href: "/employees?status=Aktiv,Karenz",
},
// Geplante Eintritte ohne Zeitgrenze — anders als die Karte „Anstehend"
// darunter, die nur den eingestellten Vorschauzeitraum zeigt. Ein