"use client"; import React, { useState, useMemo } from "react"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Card, CardContent } from "@/components/ui/card"; import { Plus, X } from "lucide-react"; import { SelectedItemsDetailInputConfig, AdditionalFieldDefinition } from "./types"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Check, ChevronsUpDown } from "lucide-react"; import { cn } from "@/lib/utils"; export interface SelectedItemsDetailInputConfigPanelProps { config: SelectedItemsDetailInputConfig; onChange: (config: Partial) => void; tableColumns?: Array<{ columnName: string; columnLabel?: string; dataType?: string }>; allTables?: Array<{ tableName: string; displayName?: string }>; onTableChange?: (tableName: string) => void; } /** * SelectedItemsDetailInput 설정 패널 * 컴포넌트의 설정값들을 편집할 수 있는 UI 제공 */ export const SelectedItemsDetailInputConfigPanel: React.FC = ({ config, onChange, tableColumns = [], allTables = [], onTableChange, }) => { const [localFields, setLocalFields] = useState(config.additionalFields || []); const [displayColumns, setDisplayColumns] = useState(config.displayColumns || []); const [fieldPopoverOpen, setFieldPopoverOpen] = useState>({}); const handleChange = (key: keyof SelectedItemsDetailInputConfig, value: any) => { onChange({ [key]: value }); }; const handleFieldsChange = (fields: AdditionalFieldDefinition[]) => { setLocalFields(fields); handleChange("additionalFields", fields); }; const handleDisplayColumnsChange = (columns: string[]) => { setDisplayColumns(columns); handleChange("displayColumns", columns); }; // 필드 추가 const addField = () => { const newField: AdditionalFieldDefinition = { name: `field_${localFields.length + 1}`, label: `필드 ${localFields.length + 1}`, type: "text", }; handleFieldsChange([...localFields, newField]); }; // 필드 제거 const removeField = (index: number) => { handleFieldsChange(localFields.filter((_, i) => i !== index)); }; // 필드 수정 const updateField = (index: number, updates: Partial) => { const newFields = [...localFields]; newFields[index] = { ...newFields[index], ...updates }; handleFieldsChange(newFields); }; // 표시 컬럼 추가 const addDisplayColumn = (columnName: string) => { if (!displayColumns.includes(columnName)) { handleDisplayColumnsChange([...displayColumns, columnName]); } }; // 표시 컬럼 제거 const removeDisplayColumn = (columnName: string) => { handleDisplayColumnsChange(displayColumns.filter((col) => col !== columnName)); }; // 사용되지 않은 컬럼 목록 const availableColumns = useMemo(() => { const usedColumns = new Set([...displayColumns, ...localFields.map((f) => f.name)]); return tableColumns.filter((col) => !usedColumns.has(col.columnName)); }, [tableColumns, displayColumns, localFields]); // 테이블 선택 Combobox 상태 const [tableSelectOpen, setTableSelectOpen] = useState(false); const [tableSearchValue, setTableSearchValue] = useState(""); // 필터링된 테이블 목록 const filteredTables = useMemo(() => { if (!tableSearchValue) return allTables; const searchLower = tableSearchValue.toLowerCase(); return allTables.filter( (table) => table.tableName.toLowerCase().includes(searchLower) || table.displayName?.toLowerCase().includes(searchLower), ); }, [allTables, tableSearchValue]); // 선택된 테이블 표시명 const selectedTableLabel = useMemo(() => { if (!config.targetTable) return "테이블을 선택하세요"; const table = allTables.find((t) => t.tableName === config.targetTable); return table ? table.displayName || table.tableName : config.targetTable; }, [config.targetTable, allTables]); return (
{/* 데이터 소스 ID */}
handleChange("dataSourceId", e.target.value)} placeholder="table-list-123" className="h-7 text-xs sm:h-8 sm:text-sm" />

💡 이전 모달에서 데이터를 전달하는 컴포넌트 ID (보통 TableList의 ID)

{/* 저장 대상 테이블 */}
테이블을 찾을 수 없습니다. {filteredTables.map((table) => ( { handleChange("targetTable", currentValue); setTableSelectOpen(false); setTableSearchValue(""); if (onTableChange) { onTableChange(currentValue); } }} className="text-xs sm:text-sm" > {table.displayName || table.tableName} ))}

최종 데이터를 저장할 테이블

{/* 표시할 원본 데이터 컬럼 */}
{displayColumns.map((colName, index) => (
))} 사용 가능한 컬럼이 없습니다. {availableColumns.map((column) => ( addDisplayColumn(column.columnName)} className="text-xs sm:text-sm" >
{column.columnLabel || column.columnName}
{column.dataType &&
{column.dataType}
}
))}

전달받은 원본 데이터 중 화면에 표시할 컬럼 (예: 품목코드, 품목명)

{/* 추가 입력 필드 정의 */}
{localFields.map((field, index) => (
필드 {index + 1}
setFieldPopoverOpen({ ...fieldPopoverOpen, [index]: open })} > 사용 가능한 컬럼이 없습니다. {availableColumns.map((column) => ( { updateField(index, { name: column.columnName, label: column.columnLabel || column.columnName, }); setFieldPopoverOpen({ ...fieldPopoverOpen, [index]: false }); }} className="text-[10px] sm:text-xs" >
{column.columnLabel}
{column.columnName}
))}
updateField(index, { label: e.target.value })} placeholder="필드 라벨" className="h-6 w-full text-[10px] sm:h-7 sm:text-xs" />
updateField(index, { placeholder: e.target.value })} placeholder="입력 안내" className="h-6 w-full text-[10px] sm:h-7 sm:text-xs" />
updateField(index, { required: checked as boolean })} />
))}
{/* 레이아웃 설정 */}

{config.layout === "grid" ? "행 단위로 데이터를 표시합니다" : "각 항목을 카드로 표시합니다"}

{/* 옵션 */}
handleChange("showIndex", checked as boolean)} />
handleChange("allowRemove", checked as boolean)} />
handleChange("disabled", checked as boolean)} />
{/* 사용 예시 */}

💡 사용 예시

  • • 품목 선택 모달 → 다음 버튼 → 거래처별 가격 입력
  • • 사용자 선택 모달 → 다음 버튼 → 권한 및 부서 할당
  • • 제품 선택 모달 → 다음 버튼 → 수량 및 납기일 입력
); }; SelectedItemsDetailInputConfigPanel.displayName = "SelectedItemsDetailInputConfigPanel";