diff --git a/actions/employees.ts b/actions/employees.ts index d1ff052..3b828b0 100644 --- a/actions/employees.ts +++ b/actions/employees.ts @@ -4,7 +4,7 @@ import { revalidatePath } from "next/cache"; import { currentUserId } from "@/lib/auth/session"; import { withUser } from "@/lib/db"; import { callFunction, runMutation, type ActionResult, type MutationFn } from "@/lib/db/rpc"; -import type { CollectiveAgreement, NoteCategory, RelationshipType, Weekday, WorkerType } from "@/lib/supabase/types"; +import type { CollectiveAgreement, DienstwagenArt, NoteCategory, RelationshipType, Weekday, WorkerType } from "@/lib/supabase/types"; async function callRpc(fn: MutationFn, payload: Record, revalidate: string[]): Promise { const result = await runMutation(await currentUserId(), fn, payload); @@ -14,6 +14,14 @@ async function callRpc(fn: MutationFn, payload: Record, revalid } export async function hireEmployee(payload: { + /** + * Wird eingegeben, nicht vergeben. + * + * Sie muss mit Loga und Interflex übereinstimmen; eine hier selbst gezogene + * Nummer wäre dort unbekannt und die Person hätte in drei Systemen zwei + * Nummern. Die Datenbank weist eine bereits vergebene Nummer ab. + */ + personnel_number: number; first_name: string; last_name: string; title_prefix?: string[]; @@ -47,6 +55,10 @@ export async function hireEmployee(payload: { work_days?: Weekday[]; is_betriebsrat?: boolean; has_dienstwagen?: boolean; + dienstwagen_art?: DienstwagenArt | null; + emergency_contact_name?: string; + emergency_contact_phone?: string; + emergency_contact_relation?: string; is_laterale_fuehrung?: boolean; is_c_level?: boolean; }): Promise { diff --git a/app/(app)/employees/page.tsx b/app/(app)/employees/page.tsx index 97f8c86..8ad8438 100644 --- a/app/(app)/employees/page.tsx +++ b/app/(app)/employees/page.tsx @@ -15,7 +15,15 @@ import type { EmploymentStatus } from "@/lib/supabase/types"; const PAGE_SIZE = 15; -type SearchParams = { q?: string; division?: string; status?: string; location?: string; page?: string }; +type SearchParams = { + q?: string; + division?: string; + status?: string; + location?: string; + /** "ja" | "nein" | "elektro" | "verbrenner" — alles andere wird übergangen. */ + dienstwagen?: string; + page?: string; +}; type EmployeesPageProps = { searchParams: Promise; @@ -27,6 +35,7 @@ function pageHref(params: SearchParams, page: number): string { if (params.division) sp.set("division", params.division); if (params.status) sp.set("status", params.status); if (params.location) sp.set("location", params.location); + if (params.dienstwagen) sp.set("dienstwagen", params.dienstwagen); sp.set("page", String(page)); return `/employees?${sp.toString()}`; } @@ -126,6 +135,13 @@ export default async function EmployeesPage({ searchParams }: EmployeesPageProps } if (params.location) q = q.where("location_id", "=", params.location); + + // Auf die vier bekannten Werte eingeschränkt: der Parameter kommt aus + // der Adresszeile und ist damit fremdbestimmt. + if (params.dienstwagen === "ja") q = q.where("has_dienstwagen", "=", true); + else if (params.dienstwagen === "nein") q = q.where("has_dienstwagen", "=", false); + else if (params.dienstwagen === "elektro") q = q.where("dienstwagen_art", "=", "Elektro"); + else if (params.dienstwagen === "verbrenner") q = q.where("dienstwagen_art", "=", "Verbrenner"); return q; }; diff --git a/app/api/export/employees/route.ts b/app/api/export/employees/route.ts index d295868..037f92c 100644 --- a/app/api/export/employees/route.ts +++ b/app/api/export/employees/route.ts @@ -142,6 +142,10 @@ function employeeExportColumns( { header: "Kollektivvertrag", get: (e) => e.collective_agreement }, { header: "Betriebsrat", get: (e) => e.is_betriebsrat }, { header: "Dienstwagen", get: (e) => e.has_dienstwagen }, + { header: "Antriebsart", get: (e) => e.dienstwagen_art ?? "" }, + { header: "Notfallkontakt", get: (e) => e.emergency_contact_name ?? "" }, + { header: "Notfallkontakt Telefon", get: (e) => e.emergency_contact_phone ?? "" }, + { header: "Notfallkontakt Verhältnis", get: (e) => e.emergency_contact_relation ?? "" }, { header: "Laterale Führung", get: (e) => e.is_laterale_fuehrung }, { header: "C-Level", get: (e) => e.is_c_level }, { header: "Paygrade", get: (e) => e.paygrade }, diff --git a/components/employees/EmployeeFilters.tsx b/components/employees/EmployeeFilters.tsx index d29fbc5..49b4077 100644 --- a/components/employees/EmployeeFilters.tsx +++ b/components/employees/EmployeeFilters.tsx @@ -104,6 +104,22 @@ export function EmployeeFilters({ units, depthOf, locations }: EmployeeFiltersPr ))} + {/* „Wer hat einen Dienstwagen" ist eine wiederkehrende Frage — als + Filter beantwortet sie sich mit einem Klick, statt über einen + Export mit Nachbearbeitung. E-KFZ getrennt, weil das die Frage + hinter der Frage ist. */} + ); } diff --git a/components/employees/RoleEmploymentFields.tsx b/components/employees/RoleEmploymentFields.tsx index 764ecdc..3c77e17 100644 --- a/components/employees/RoleEmploymentFields.tsx +++ b/components/employees/RoleEmploymentFields.tsx @@ -1,7 +1,7 @@ "use client"; import { SelectField } from "@/components/ui/Field"; -import type { CollectiveAgreement, Weekday, WorkerType } from "@/lib/supabase/types"; +import type { CollectiveAgreement, DienstwagenArt, Weekday, WorkerType } from "@/lib/supabase/types"; const WEEKDAYS: Weekday[] = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]; @@ -11,6 +11,15 @@ export type RoleEmploymentValue = { workDays: Weekday[]; isBetriebsrat: boolean; hasDienstwagen: boolean; + /** + * Nur bedeutsam, solange hasDienstwagen gesetzt ist. + * + * Der Wert bleibt beim Abwählen stehen, statt zurückgesetzt zu werden — + * wer versehentlich klickt und zurückklickt, findet seine Angabe wieder. + * Beim Speichern setzen die Aufrufer ihn auf null, wie es der CHECK + * verlangt. + */ + dienstwagenArt: DienstwagenArt; isLateraleFuehrung: boolean; isCLevel: boolean; }; @@ -78,6 +87,21 @@ export function RoleEmploymentFields({ value, onChange }: { value: RoleEmploymen onChange({ hasDienstwagen: e.target.checked })} /> Dienstwagen + {/* Nur sichtbar, wenn es einen gibt: eine Antriebsart ohne Fahrzeug + ist keine Angabe, sondern eine Frage ohne Gegenstand — und die + Datenbank weist sie ab. */} + {value.hasDienstwagen && ( + onChange({ dienstwagenArt: v as DienstwagenArt })} + options={[ + { value: "Verbrenner", label: "Verbrenner" }, + { value: "Elektro", label: "Elektro (E-KFZ)" }, + ]} + /> + )}