ERP-node/frontend/components/v2/config-panels/V2RackStructureConfigPanel.tsx

241 lines
9.0 KiB
TypeScript
Raw Normal View History

"use client";
/**
* V2
* UX: 필드 -> -> UI ()
*/
import React, { useState, useEffect } from "react";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { Settings, ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";
import type { RackStructureComponentConfig, FieldMapping } from "@/lib/registry/components/v2-rack-structure/types";
interface V2RackStructureConfigPanelProps {
config: RackStructureComponentConfig;
onChange: (config: RackStructureComponentConfig) => void;
tables?: Array<{
tableName: string;
tableLabel?: string;
columns: Array<{
columnName: string;
columnLabel?: string;
dataType?: string;
}>;
}>;
}
export const V2RackStructureConfigPanel: React.FC<V2RackStructureConfigPanelProps> = ({
config,
onChange,
tables = [],
}) => {
const [availableColumns, setAvailableColumns] = useState<
Array<{ value: string; label: string }>
>([]);
const [advancedOpen, setAdvancedOpen] = useState(false);
useEffect(() => {
const columns: Array<{ value: string; label: string }> = [];
tables.forEach((table) => {
table.columns.forEach((col) => {
columns.push({
value: col.columnName,
label: col.columnLabel || col.columnName,
});
});
});
setAvailableColumns(columns);
}, [tables]);
const handleChange = (key: keyof RackStructureComponentConfig, value: any) => {
onChange({ ...config, [key]: value });
};
const handleFieldMappingChange = (field: keyof FieldMapping, value: string) => {
const currentMapping = config.fieldMapping || {};
onChange({
...config,
fieldMapping: {
...currentMapping,
[field]: value === "__none__" ? undefined : value,
},
});
};
const fieldMapping = config.fieldMapping || {};
const fieldMappingItems: Array<{
key: keyof FieldMapping;
label: string;
description: string;
}> = [
{ key: "warehouseCodeField", label: "창고 코드", description: "창고를 식별하는 코드 필드예요" },
{ key: "warehouseNameField", label: "창고명", description: "창고 이름을 표시하는 필드예요" },
{ key: "floorField", label: "층", description: "몇 층인지 나타내는 필드예요" },
{ key: "zoneField", label: "구역", description: "구역 정보를 가져올 필드예요" },
{ key: "locationTypeField", label: "위치 유형", description: "위치의 유형(선반, 바닥 등)을 나타내요" },
{ key: "statusField", label: "사용 여부", description: "사용/미사용 상태를 나타내는 필드예요" },
];
return (
<div className="space-y-4">
{/* ─── 1단계: 필드 매핑 ─── */}
<div className="space-y-2">
<p className="text-sm font-medium"> </p>
<p className="text-[11px] text-muted-foreground">
</p>
</div>
<div className="rounded-lg border bg-muted/30 p-4 space-y-3">
{fieldMappingItems.map((item) => (
<div key={item.key} className="flex items-center justify-between py-1">
<div>
<span className="text-xs text-muted-foreground">{item.label}</span>
<p className="text-[10px] text-muted-foreground mt-0.5">{item.description}</p>
</div>
<Select
value={fieldMapping[item.key] || "__none__"}
onValueChange={(v) => handleFieldMappingChange(item.key, v)}
>
<SelectTrigger className="h-7 w-[140px] text-xs">
<SelectValue placeholder="선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="__none__"> </SelectItem>
{availableColumns.map((col) => (
<SelectItem key={col.value} value={col.value}>
{col.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
))}
</div>
{/* ─── 2단계: 제한 설정 ─── */}
<div className="space-y-2">
<p className="text-sm font-medium"> </p>
<p className="text-[11px] text-muted-foreground">
</p>
</div>
<div className="rounded-lg border bg-muted/30 p-4 space-y-3">
<div className="flex items-center justify-between py-1">
<span className="text-xs text-muted-foreground"> </span>
<Input
type="number"
min={1}
max={20}
value={config.maxConditions || 10}
onChange={(e) => handleChange("maxConditions", parseInt(e.target.value) || 10)}
className="h-7 w-[100px] text-xs"
/>
</div>
<div className="flex items-center justify-between py-1">
<span className="text-xs text-muted-foreground"> </span>
<Input
type="number"
min={1}
max={999}
value={config.maxRows || 99}
onChange={(e) => handleChange("maxRows", parseInt(e.target.value) || 99)}
className="h-7 w-[100px] text-xs"
/>
</div>
<div className="flex items-center justify-between py-1">
<span className="text-xs text-muted-foreground"> </span>
<Input
type="number"
min={1}
max={99}
value={config.maxLevels || 20}
onChange={(e) => handleChange("maxLevels", parseInt(e.target.value) || 20)}
className="h-7 w-[100px] text-xs"
/>
</div>
</div>
{/* ─── 3단계: 고급 설정 (Collapsible) ─── */}
<Collapsible open={advancedOpen} onOpenChange={setAdvancedOpen}>
<CollapsibleTrigger asChild>
<button
type="button"
className="flex w-full items-center justify-between rounded-lg border bg-muted/30 px-4 py-2.5 text-left transition-colors hover:bg-muted/50"
>
<div className="flex items-center gap-2">
<Settings className="h-4 w-4 text-muted-foreground" />
<span className="text-sm font-medium">UI </span>
</div>
<ChevronDown
className={cn(
"h-4 w-4 text-muted-foreground transition-transform duration-200",
advancedOpen && "rotate-180"
)}
/>
</button>
</CollapsibleTrigger>
<CollapsibleContent>
<div className="rounded-b-lg border border-t-0 p-4 space-y-3">
<div className="flex items-center justify-between py-1">
<div>
<p className="text-sm">릿 </p>
<p className="text-[11px] text-muted-foreground"> 릿 / </p>
</div>
<Switch
checked={config.showTemplates ?? true}
onCheckedChange={(checked) => handleChange("showTemplates", checked)}
/>
</div>
<div className="flex items-center justify-between py-1">
<div>
<p className="text-sm"></p>
<p className="text-[11px] text-muted-foreground"> </p>
</div>
<Switch
checked={config.showPreview ?? true}
onCheckedChange={(checked) => handleChange("showPreview", checked)}
/>
</div>
<div className="flex items-center justify-between py-1">
<div>
<p className="text-sm"> </p>
<p className="text-[11px] text-muted-foreground"> </p>
</div>
<Switch
checked={config.showStatistics ?? true}
onCheckedChange={(checked) => handleChange("showStatistics", checked)}
/>
</div>
<div className="flex items-center justify-between py-1">
<div>
<p className="text-sm"> </p>
<p className="text-[11px] text-muted-foreground"> </p>
</div>
<Switch
checked={config.readonly ?? false}
onCheckedChange={(checked) => handleChange("readonly", checked)}
/>
</div>
</div>
</CollapsibleContent>
</Collapsible>
</div>
);
};
V2RackStructureConfigPanel.displayName = "V2RackStructureConfigPanel";
export default V2RackStructureConfigPanel;