"use client"; import { useRef, useState } from "react"; import { Button } from "@/components/ui/Button"; import { CARD_CLASS } from "@/components/ui/Card"; // Der Ablauf hat bewusst zwei Schritte: prüfen, dann übernehmen. // // Ein Import ist nicht rückgängig zu machen. Wer 800 Zeilen schickt, soll // vorher sehen, was entstehen würde — und bei einem Fehler die Zeilennummer // lesen, nicht „Import fehlgeschlagen". type Befund = { blatt: string; zeile: number | null; spalte: string | null; wert?: string; meldung: string }; type Antwort = { ok: boolean; geprueft: boolean; blaetter: string[]; fehler: Befund[]; hinweise: Befund[]; anzahl: Record; bericht?: Record; meldung?: string; }; /** Mehr als das zeigt niemand durch; der Rest steht in der Anzahl. */ const MAX_ANZEIGE = 200; export function ImportWorkbench() { const [dateien, setDateien] = useState([]); const [antwort, setAntwort] = useState(null); const [laeuft, setLaeuft] = useState<"pruefen" | "uebernehmen" | null>(null); const [fehlschlag, setFehlschlag] = useState(null); const eingabe = useRef(null); async function senden(nurPruefen: boolean) { if (dateien.length === 0) return; setLaeuft(nurPruefen ? "pruefen" : "uebernehmen"); setFehlschlag(null); try { const daten = new FormData(); for (const d of dateien) daten.append("datei", d); if (nurPruefen) daten.append("pruefen", "1"); const antwort = await fetch("/api/import", { method: "POST", body: daten }); const inhalt = (await antwort.json()) as Antwort; setAntwort(inhalt); } catch { setFehlschlag("Die Datei konnte nicht übertragen werden. Bitte erneut versuchen."); } finally { setLaeuft(null); } } function neueAuswahl(liste: FileList | null) { setDateien(liste ? Array.from(liste) : []); // Ein alter Bericht zu einer neuen Datei ist schlimmer als keiner. setAntwort(null); setFehlschlag(null); } const uebernommen = antwort?.bericht !== undefined; const bereit = antwort?.ok === true && antwort.geprueft && !uebernommen; return (

Datei wählen

Eine Excel-Mappe mit den Blättern Standorte, Organisation,{" "} Jobkatalog, Planstellen, Personen,{" "} Historie und Angehörige — oder je Blatt eine CSV-Datei, deren Name dem Blatt entspricht. Nicht jedes Blatt muss dabei sein.

Vorlage herunterladen
neueAuswahl(e.target.files)} className="block w-full max-w-md text-sm text-ink-muted file:mr-3 file:rounded-md file:border file:border-border file:bg-surface file:px-3 file:py-2 file:text-sm file:font-semibold file:text-ink hover:file:bg-brand-50" />
{dateien.length > 0 && (

{dateien.length === 1 ? dateien[0].name : `${dateien.length} Dateien`} ausgewählt

)}
{fehlschlag && (

{fehlschlag}

)} {antwort?.meldung && (

{antwort.meldung}

)} {antwort && !antwort.meldung && (

{uebernommen ? "Übernommen" : "Ergebnis der Prüfung"}

{Object.entries(uebernommen ? antwort.bericht! : antwort.anzahl) .filter(([, n]) => n > 0) .map(([blatt, n]) => ( ))}
{blatt} {n}
{uebernommen ? (

Die Daten stehen jetzt in der Anwendung. Der Vorgang ist im Audit-Log vermerkt.

) : antwort.ok ? ( <>

Keine Beanstandung. Beim Übernehmen entsteht genau das oben Gezeigte — alles in einem Zug oder gar nichts.

) : (

{antwort.fehler.length} Beanstandung{antwort.fehler.length === 1 ? "" : "en"} — es wurde nichts geschrieben.

)}
)} {antwort && antwort.fehler.length > 0 && ( )} {antwort && antwort.hinweise.length > 0 && ( )}
); } function BefundListe({ titel, befunde, art }: { titel: string; befunde: Befund[]; art: "fehler" | "hinweis" }) { const sichtbar = befunde.slice(0, MAX_ANZEIGE); return (

{titel} ({befunde.length})

{sichtbar.map((b, i) => ( ))}
Blatt Zeile Spalte Wert Was zu tun ist
{b.blatt} {b.zeile ?? "–"} {b.spalte ?? "–"} {b.wert ?? ""} {b.meldung}
{befunde.length > sichtbar.length && (

Weitere {befunde.length - sichtbar.length} nicht angezeigt. Oft hängen viele Meldungen an einer Ursache — nach der Korrektur erneut prüfen.

)}
); }