"use client"; import { useEffect, useRef, useState } from "react"; import { personalnummerVergeben } from "@/actions/employees"; import { TextField } from "@/components/ui/Field"; // Die Personalnummer wird eingegeben, nicht vergeben — sie muss mit Loga und // Interflex übereinstimmen. Genau deshalb kommt sie von aussen, und genau // deshalb kann sie schon vergeben sein: an dieselbe Person, die jemand ein // zweites Mal anlegt, oder an eine ganz andere nach einem Zahlendreher. // // Die Datenbank weist das ab (hire_employee prüft es eigens), aber erst beim // Anlegen — nach sechs Schritten Eingabe. Bis dahin ist die falsche Nummer // schon durch alle Formulare gereist. // // ── Wann gefragt wird ─────────────────────────────────────────────── // // Nicht bei jedem Tastendruck: „3", „34", „347" wären drei Fragen an die // Datenbank für eine Eingabe, und die ersten beiden hätten eine Antwort auf // eine Nummer, die niemand meint. Stattdessen eine halbe Sekunde Ruhe // abwarten — lange genug, dass eine vierstellige Nummer am Stück eingetippt // eine einzige Frage ergibt, kurz genug, dass die Antwort da ist, bevor der // Blick zum nächsten Feld wandert. // // Die Antwort kann veralten, während sie unterwegs ist. Deshalb zählt jede // Anfrage mit und nur die jüngste darf schreiben: sonst überschriebe die // langsamere Antwort auf „347" die schnellere auf „3471". // // ── Warum der Befund an der Nummer hängt und nicht an einem Ja/Nein ── // // Gespeichert wird **die geprüfte Nummer** mitsamt ihrem Ergebnis, nicht // bloss „frei" oder „vergeben". Damit ist jede Anzeige eine Ableitung aus // dem, was gerade im Feld steht — es gibt keinen Zustand, der zurückgesetzt // werden müsste, wenn die Eingabe sich ändert, und deshalb auch keine Stelle, // an der das Zurücksetzen vergessen werden kann. const WARTEZEIT_MS = 500; type Befund = { nummer: number; vergeben: boolean; name?: string }; export function PersonalnummerField({ wert, onChange, onBefund, }: { wert: string; onChange: (wert: string) => void; /** Meldet dem Assistenten die geprüfte Nummer und ihr Ergebnis. */ onBefund: (befund: Befund) => void; }) { const [befund, setBefund] = useState(null); const laufendeNr = useRef(0); const nummer = Number(wert); const gueltig = Boolean(wert.trim()) && Number.isInteger(nummer) && nummer > 0; // Nur ein Befund zu *dieser* Nummer zählt. Steht im Feld inzwischen etwas // anderes, ist die alte Auskunft gegenstandslos. const passend = gueltig && befund?.nummer === nummer ? befund : null; const laeuft = gueltig && !passend; useEffect(() => { if (!gueltig) return; const meine = ++laufendeNr.current; const zeit = setTimeout(async () => { let antwort: { vergeben: boolean; name?: string }; try { antwort = await personalnummerVergeben(nummer); } catch { // Keine Auskunft ist kein Hindernis: die Datenbank entscheidet beim // Anlegen ohnehin. Eine Meldung über eine gescheiterte *Vorab*-Prüfung // wäre für die Eingebende nur Lärm. antwort = { vergeben: false }; } if (meine !== laufendeNr.current) return; const neu: Befund = { nummer, ...antwort }; setBefund(neu); onBefund(neu); }, WARTEZEIT_MS); return () => clearTimeout(zeit); }, [gueltig, nummer, onBefund]); return ( onChange(v.replace(/\D/g, ""))} error={ passend?.vergeben ? `Diese Personalnummer ist bereits vergeben${passend.name ? ` — an ${passend.name}` : ""}.` : undefined } hint={laeuft ? "Wird geprüft…" : "Muss mit Loga und Interflex übereinstimmen. Wird nicht automatisch vergeben."} /> ); }