Initial Project

This commit is contained in:
Toni Martin
2026-02-25 13:16:14 +01:00
commit ca0022e250
73 changed files with 20166 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
import * as React from "react";
import { useState, useEffect } from "react";
import { makeStyles } from "@fluentui/react-components";
import { SheetInfo, SheetMappingStatus } from "../models";
import SheetSelector from "./SheetSelector";
import ColumnMapper from "./ColumnMapper";
import StatusNotifier from "./StatusNotifier";
import { getAvailableSheets, detectHeadersAndColumns, detectHeadersForSingleSheetRow, consolidateData } from "../excelLogic";
interface AppProps {
title: string;
}
const useStyles = makeStyles({
root: {
minHeight: "100vh",
display: "flex",
flexDirection: "column",
},
});
const App: React.FC<AppProps> = () => {
const styles = useStyles();
type WizardStep = "select_sheets" | "map_columns" | "done";
const [step, setStep] = useState<WizardStep>("select_sheets");
const [sheets, setSheets] = useState<SheetInfo[]>([]);
const [selectedSheetIds, setSelectedSheetIds] = useState<string[]>([]);
const [sheetMappings, setSheetMappings] = useState<SheetMappingStatus[]>([]);
const [status, setStatus] = useState<"idle" | "success" | "warning" | "error">("idle");
const [statusMessage, setStatusMessage] = useState("");
const [isConsolidating, setIsConsolidating] = useState(false);
useEffect(() => {
// Load internal sheets on mount
getAvailableSheets().then(setSheets).catch(err => {
setStatus("error");
setStatusMessage("Fehler beim Laden der Arbeitsblätter: " + String(err));
});
}, []);
const handleExternalSheetsLoaded = (newExternalSheets: SheetInfo[]) => {
setSheets(prev => [...prev, ...newExternalSheets]);
};
const handleNextToMapping = async () => {
const selectedSheets = sheets.filter(s => selectedSheetIds.includes(s.id));
if (selectedSheets.length === 0) return;
try {
const mappings = await detectHeadersAndColumns(selectedSheets);
setSheetMappings(mappings);
setStep("map_columns");
setStatus("idle");
setStatusMessage("");
} catch (err) {
setStatus("error");
setStatusMessage("Fehler beim Analysieren der Blätter: " + String(err));
}
};
const handleHeaderRowChange = async (sheetName: string, newRowIndex: number) => {
try {
// Wir müssen das richtige SheetInfo Objekt finden (für isExternal check)
const sheetInfo = sheets.find(s => s.name === sheetName);
if (!sheetInfo) return;
// Re-detect columns for exactly this row
const newMapping = await detectHeadersForSingleSheetRow(sheetInfo, newRowIndex);
setSheetMappings(prev => prev.map(m => m.sheetName === sheetName ? newMapping : m));
} catch (err) {
setStatus("error");
setStatusMessage("Fehler beim Neuladen der Zeile " + newRowIndex + " für Blatt " + sheetName);
}
};
const handleMappingChange = (sheetName: string, targetCol: string, sourceColIndex: number) => {
setSheetMappings(prev => prev.map(sheet => {
if (sheet.sheetName !== sheetName) return sheet;
const newMappings = sheet.mappings.map(m =>
m.targetColumn === targetCol ? { ...m, sourceColumnIndex: sourceColIndex } : m
);
return { ...sheet, mappings: newMappings };
}));
};
const handleConsolidate = async () => {
setIsConsolidating(true);
setStatus("idle");
try {
const rowsCount = await consolidateData(sheetMappings);
setStatus("success");
setStatusMessage(`Erfolgreich! Es wurden ${rowsCount} Zeilen aus ${sheetMappings.length} Blättern zusammengefasst.`);
setStep("done");
} catch (err: any) {
setStatus("error");
setStatusMessage(err.message || "Fehler bei der Konsolidierung: " + String(err));
} finally {
setIsConsolidating(false);
}
};
return (
<div className={styles.root}>
<StatusNotifier status={status} message={statusMessage} />
{step === "select_sheets" && (
<SheetSelector
sheets={sheets}
selectedSheetIds={selectedSheetIds}
onSelectionChange={setSelectedSheetIds}
onNext={handleNextToMapping}
onExternalSheetsLoaded={handleExternalSheetsLoaded}
/>
)}
{step === "map_columns" && (
<ColumnMapper
sheetMappings={sheetMappings}
onHeaderRowChange={handleHeaderRowChange}
onMappingChange={handleMappingChange}
onBack={() => setStep("select_sheets")}
onConsolidate={handleConsolidate}
isConsolidating={isConsolidating}
/>
)}
{step === "done" && (
<div style={{ padding: "10px", textAlign: "center", marginTop: "40px" }}>
<h2>Fertig!</h2>
<p>Die Daten wurden in die 'Gesamtliste' geschrieben.</p>
<button
style={{ padding: "8px 16px", marginTop: "10px", cursor: "pointer" }}
onClick={() => {
setStep("select_sheets");
setSelectedSheetIds([]);
setStatus("idle");
}}
>
Neuen Durchlauf starten
</button>
</div>
)}
</div>
);
};
export default App;