180 lines
9.4 KiB
TypeScript
180 lines
9.4 KiB
TypeScript
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, ConsolidateSettings } 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;
|
|
settings: ConsolidateSettings;
|
|
onSettingsChange: (settings: ConsolidateSettings) => void;
|
|
}
|
|
|
|
const ColumnMapper: React.FC<ColumnMapperProps> = ({
|
|
sheetMappings,
|
|
onHeaderRowChange,
|
|
onMappingChange,
|
|
onBack,
|
|
onConsolidate,
|
|
isConsolidating,
|
|
settings,
|
|
onSettingsChange,
|
|
}) => {
|
|
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={{ marginTop: "20px", padding: "10px", backgroundColor: "#f3f2f1", borderRadius: "4px" }}>
|
|
<Text weight="semibold">Hervorhebungen (Farben)</Text>
|
|
<div style={{ display: "flex", gap: "20px", marginTop: "10px" }}>
|
|
<Field label="Neue Kabel">
|
|
<input
|
|
type="color"
|
|
value={settings.colorNew}
|
|
onChange={(e) => onSettingsChange({ ...settings, colorNew: e.target.value })}
|
|
style={{ width: "60px", padding: "0", cursor: "pointer", height: "30px", border: "none" }}
|
|
/>
|
|
</Field>
|
|
<Field label="Geänderte Werte">
|
|
<input
|
|
type="color"
|
|
value={settings.colorChanged}
|
|
onChange={(e) => onSettingsChange({ ...settings, colorChanged: e.target.value })}
|
|
style={{ width: "60px", padding: "0", cursor: "pointer", height: "30px", border: "none" }}
|
|
/>
|
|
</Field>
|
|
<Field label="Entfallene Kabel">
|
|
<input
|
|
type="color"
|
|
value={settings.colorDeleted}
|
|
onChange={(e) => onSettingsChange({ ...settings, colorDeleted: e.target.value })}
|
|
style={{ width: "60px", padding: "0", cursor: "pointer", height: "30px", border: "none" }}
|
|
/>
|
|
</Field>
|
|
<Field label="Duplikate">
|
|
<input
|
|
type="color"
|
|
value={settings.colorDuplicate}
|
|
onChange={(e) => onSettingsChange({ ...settings, colorDuplicate: e.target.value })}
|
|
style={{ width: "60px", padding: "0", cursor: "pointer", height: "30px", border: "none" }}
|
|
/>
|
|
</Field>
|
|
</div>
|
|
</div>
|
|
|
|
<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;
|