"use client"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { useEffect, useState } from "react"; import { FILTER_SELECT_CLASS } from "@/components/ui/Field"; import { SearchInput } from "@/components/ui/SearchInput"; type EmployeeFiltersProps = { /** Der ganze Baum, in Tiefensuche-Reihenfolge. */ units: { id: string; name: string; unit_type: string }[]; depthOf: Map; locations: { id: string; name: string }[]; }; // Aktiv and Langzeitabwesenheit are separate statuses — somebody on a // long-term absence is employed but not active. The combined entry is // offered explicitly, named after the two it selects rather than calling // the pair "aktiv". The stored value is still 'Karenz' (see lib/absence.ts). const STATUS_OPTIONS = [ { value: "Aktiv", label: "Aktiv" }, { value: "Karenz", label: "Langzeitabwesenheit" }, // Der Name der Kachel zuerst, die Bestandteile in Klammern dahinter: die // Kachel „Aktives Dienstverhältnis" verlinkt genau auf diese Auswahl, und // wer ihr folgt, soll oben dieselbe Bezeichnung wiederfinden statt eine // zweite für dieselbe Sache. { value: "Aktiv,Karenz", label: "Aktives Dienstverhältnis (Aktiv + Langzeitabwesenheit)" }, { value: "Geplant", label: "Geplant" }, { value: "Ausgetreten", label: "Ausgetreten" }, ] as const; export function EmployeeFilters({ units, depthOf, locations }: EmployeeFiltersProps) { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); const [q, setQ] = useState(searchParams.get("q") ?? ""); useEffect(() => { const handle = setTimeout(() => { const current = new URLSearchParams(searchParams.toString()); if (q) current.set("q", q); else current.delete("q"); current.delete("page"); const next = current.toString(); if (next !== searchParams.toString()) router.push(`${pathname}?${next}`); }, 300); return () => clearTimeout(handle); // eslint-disable-next-line react-hooks/exhaustive-deps }, [q]); function updateParam(key: string, value: string) { const params = new URLSearchParams(searchParams.toString()); if (value) params.set(key, value); else params.delete(key); params.delete("page"); router.push(`${pathname}?${params.toString()}`); } return (
{/* aria-label rather than a visible label: the filter bar is a single horizontal row, and each select's first option already names it on screen. */} {/* Der ganze Baum, nicht nur die oberste Ebene: die Auswahl greift jeweils auf die Einheit *und alles darunter*, weshalb sich damit auch nach einer einzelnen Abteilung oder einem Team filtern lässt. Eingerückt statt gruppiert, weil optgroup keine Verschachtelung kennt und die Tiefe hier beliebig ist. */} {/* Sortiert wird nicht hier, sondern an den Spaltenköpfen der Liste. Diese Leiste schränkt ein, *was* zu sehen ist; die Reihenfolge gehört an die Spalte, die sie bestimmt. */} {/* Der Dienstwagen stand hier einmal als eigenes Auswahlfeld. Er ist jetzt eines von rund zwanzig Kriterien unter Berichte, zusammen mit Vertragsart, Kollektivvertrag, Eintrittszeitraum und dem Rest — dort lässt sich die Auswahl auch exportieren, was der eigentliche Zweck der Frage war. In dieser Leiste, die vor allem zum Suchen da ist, wäre er ein Sonderfall unter vielen gleichrangigen. */}
); }