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,137 @@
import * as React from "react";
import {
Text,
Button,
SpinButton,
Dropdown,
Option,
Accordion,
AccordionHeader,
AccordionItem,
AccordionPanel,
Field,
Label,
Spinner,
} from "@fluentui/react-components";
import { SheetMappingStatus, TARGET_COLUMNS } from "../models";
interface ColumnMapperProps {
sheetMappings: SheetMappingStatus[];
onHeaderRowChange: (sheetName: string, newRowIndex: number) => void;
onMappingChange: (sheetName: string, targetCol: string, sourceColIndex: number) => void;
onBack: () => void;
onConsolidate: () => void;
isConsolidating: boolean;
}
const ColumnMapper: React.FC<ColumnMapperProps> = ({
sheetMappings,
onHeaderRowChange,
onMappingChange,
onBack,
onConsolidate,
isConsolidating,
}) => {
return (
<div style={{ display: "flex", flexDirection: "column", gap: "15px", padding: "10px" }}>
<Text size={400} weight="semibold">
2. Spalten-Mapping prüfen
</Text>
<Text size={300}>
Bitte überprüfe die gefundenen Kopfzeilen und passe fehlende Spalten manuell an.
</Text>
<Accordion multiple collapsible defaultOpenItems={sheetMappings.map((s) => s.sheetName)}>
{sheetMappings.map((sheet) => {
const missingCount = sheet.mappings.filter((m) => m.sourceColumnIndex === -1).length;
return (
<AccordionItem key={sheet.sheetName} value={sheet.sheetName}>
<AccordionHeader>
<div style={{ display: "flex", justifyContent: "space-between", width: "100%" }}>
<Text weight="semibold">{sheet.sheetName}</Text>
{missingCount > 0 ? (
<Text style={{ color: "red", paddingRight: "10px" }}>{missingCount} Lücken</Text>
) : (
<Text style={{ color: "green", paddingRight: "10px" }}>OK</Text>
)}
</div>
</AccordionHeader>
<AccordionPanel>
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
{missingCount === TARGET_COLUMNS.length && (
<div style={{ backgroundColor: "#fdf6f6", padding: "10px", borderRadius: "4px", border: "1px solid #f5b0b0" }}>
<Text style={{ color: "red", fontWeight: "semibold" }}>Achtung: Keine passenden Kopfzeilen gefunden.</Text><br />
<Text size={200}>Bitte weise die Spalten manuell zu. Wenn du dieses Blatt überspringen willst, lass einfach alles auf "Nicht gefunden".</Text>
</div>
)}
<Field
label="Kopfzeile (Index 0-basiert):"
orientation="horizontal"
>
<SpinButton
value={sheet.headerRowIndex}
min={0}
onChange={(_, data) => {
if (data.value !== undefined) {
onHeaderRowChange(sheet.sheetName, data.value);
}
}}
style={{ width: "80px" }}
/>
</Field>
{TARGET_COLUMNS.map((tc) => {
const colName = tc.id;
const mappedInfo = sheet.mappings.find((m) => m.targetColumn === colName);
const selectedVal = mappedInfo?.sourceColumnIndex !== -1 ? mappedInfo?.sourceColumnIndex.toString() : "-1";
return (
<Field key={colName} label={colName} orientation="horizontal" style={{ justifyContent: "space-between" }}>
<Dropdown
value={
selectedVal === "-1"
? "--- Nicht gefunden ---"
: sheet.availableColumns.find((c) => c.index.toString() === selectedVal)?.name || "Unbekannt"
}
selectedOptions={[selectedVal || "-1"]}
onOptionSelect={(_, data) => {
const newIndex = parseInt(data.optionValue || "-1", 10);
onMappingChange(sheet.sheetName, colName, newIndex);
}}
style={{ minWidth: "150px" }}
>
<Option value="-1" text="--- Nicht gefunden ---">--- Nicht gefunden ---</Option>
{sheet.availableColumns.map((availCol) => (
<Option key={availCol.index} value={availCol.index.toString()} text={`${availCol.name} (Spalte ${availCol.index + 1})`}>
{availCol.name} (Spalte {availCol.index + 1})
</Option>
))}
</Dropdown>
</Field>
);
})}
</div>
</AccordionPanel>
</AccordionItem>
);
})}
</Accordion>
<div style={{ display: "flex", justifyContent: "space-between", marginTop: "20px" }}>
<Button onClick={onBack} disabled={isConsolidating}>Zurück</Button>
<Button
appearance="primary"
onClick={onConsolidate}
disabled={isConsolidating || sheetMappings.length === 0}
icon={isConsolidating ? <Spinner size="tiny" /> : undefined}
>
{isConsolidating ? "Konsolidierung läuft..." : "Konsolidieren"}
</Button>
</div>
</div>
);
};
export default ColumnMapper;