"use client"; import React, { useState, useEffect } from "react"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Switch } from "@/components/ui/switch"; import { Button } from "@/components/ui/button"; import { Plus, X, Check, ChevronsUpDown } from "lucide-react"; import { AutocompleteSearchInputConfig, FieldMapping, ValueFieldStorage } from "./types"; import { tableManagementApi } from "@/lib/api/tableManagement"; import { cn } from "@/lib/utils"; interface AutocompleteSearchInputConfigPanelProps { config: AutocompleteSearchInputConfig; onConfigChange: (config: AutocompleteSearchInputConfig) => void; } export function AutocompleteSearchInputConfigPanel({ config, onConfigChange, }: AutocompleteSearchInputConfigPanelProps) { const [localConfig, setLocalConfig] = useState(config); const [allTables, setAllTables] = useState([]); const [tableColumns, setTableColumns] = useState([]); const [isLoadingTables, setIsLoadingTables] = useState(false); const [isLoadingColumns, setIsLoadingColumns] = useState(false); const [openTableCombo, setOpenTableCombo] = useState(false); const [openDisplayFieldCombo, setOpenDisplayFieldCombo] = useState(false); const [openValueFieldCombo, setOpenValueFieldCombo] = useState(false); const [openStorageTableCombo, setOpenStorageTableCombo] = useState(false); const [openStorageColumnCombo, setOpenStorageColumnCombo] = useState(false); const [storageTableColumns, setStorageTableColumns] = useState([]); const [isLoadingStorageColumns, setIsLoadingStorageColumns] = useState(false); // 전체 테이블 목록 로드 useEffect(() => { const loadTables = async () => { setIsLoadingTables(true); try { const response = await tableManagementApi.getTableList(); if (response.success && response.data) { setAllTables(response.data); } } catch (error) { console.error("테이블 목록 로드 실패:", error); } finally { setIsLoadingTables(false); } }; loadTables(); }, []); // 선택된 테이블의 컬럼 목록 로드 useEffect(() => { const loadColumns = async () => { if (!localConfig.tableName) { setTableColumns([]); return; } setIsLoadingColumns(true); try { const response = await tableManagementApi.getColumnList(localConfig.tableName); if (response.success && response.data) { setTableColumns(response.data.columns); } } catch (error) { console.error("컬럼 목록 로드 실패:", error); setTableColumns([]); } finally { setIsLoadingColumns(false); } }; loadColumns(); }, [localConfig.tableName]); // 저장 대상 테이블의 컬럼 목록 로드 useEffect(() => { const loadStorageColumns = async () => { const storageTable = localConfig.valueFieldStorage?.targetTable; if (!storageTable) { setStorageTableColumns([]); return; } setIsLoadingStorageColumns(true); try { const response = await tableManagementApi.getColumnList(storageTable); if (response.success && response.data) { setStorageTableColumns(response.data.columns); } } catch (error) { console.error("저장 테이블 컬럼 로드 실패:", error); setStorageTableColumns([]); } finally { setIsLoadingStorageColumns(false); } }; loadStorageColumns(); }, [localConfig.valueFieldStorage?.targetTable]); useEffect(() => { setLocalConfig(config); }, [config]); const updateConfig = (updates: Partial) => { const newConfig = { ...localConfig, ...updates }; setLocalConfig(newConfig); onConfigChange(newConfig); }; const addSearchField = () => { const fields = localConfig.searchFields || []; updateConfig({ searchFields: [...fields, ""] }); }; const updateSearchField = (index: number, value: string) => { const fields = [...(localConfig.searchFields || [])]; fields[index] = value; updateConfig({ searchFields: fields }); }; const removeSearchField = (index: number) => { const fields = [...(localConfig.searchFields || [])]; fields.splice(index, 1); updateConfig({ searchFields: fields }); }; const addAdditionalField = () => { const fields = localConfig.additionalFields || []; updateConfig({ additionalFields: [...fields, ""] }); }; const updateAdditionalField = (index: number, value: string) => { const fields = [...(localConfig.additionalFields || [])]; fields[index] = value; updateConfig({ additionalFields: fields }); }; const removeAdditionalField = (index: number) => { const fields = [...(localConfig.additionalFields || [])]; fields.splice(index, 1); updateConfig({ additionalFields: fields }); }; // 필드 매핑 관리 함수 const addFieldMapping = () => { const mappings = localConfig.fieldMappings || []; updateConfig({ fieldMappings: [ ...mappings, { sourceField: "", targetField: "", label: "" }, ], }); }; const updateFieldMapping = (index: number, updates: Partial) => { const mappings = [...(localConfig.fieldMappings || [])]; mappings[index] = { ...mappings[index], ...updates }; updateConfig({ fieldMappings: mappings }); }; const removeFieldMapping = (index: number) => { const mappings = [...(localConfig.fieldMappings || [])]; mappings.splice(index, 1); updateConfig({ fieldMappings: mappings }); }; return (
테이블을 찾을 수 없습니다. {allTables.map((table) => ( { updateConfig({ tableName: table.tableName }); setOpenTableCombo(false); }} className="text-xs sm:text-sm" >
{table.displayName || table.tableName} {table.displayName && {table.tableName}}
))}

검색할 데이터가 저장된 테이블을 선택하세요

필드를 찾을 수 없습니다. {tableColumns.map((column) => ( { updateConfig({ displayField: column.columnName }); setOpenDisplayFieldCombo(false); }} className="text-xs sm:text-sm" >
{column.displayName || column.columnName} {column.displayName && {column.columnName}}
))}

사용자에게 보여줄 필드 (예: 거래처명)

필드를 찾을 수 없습니다. {tableColumns.map((column) => ( { updateConfig({ valueField: column.columnName }); setOpenValueFieldCombo(false); }} className="text-xs sm:text-sm" >
{column.displayName || column.columnName} {column.displayName && {column.columnName}}
))}

검색 테이블에서 가져올 값의 컬럼 (예: customer_code)

updateConfig({ placeholder: e.target.value })} placeholder="검색..." className="h-8 text-xs sm:h-10 sm:text-sm" />
{/* 값 필드 저장 위치 설정 */}

값 필드 저장 위치 (고급)

위에서 선택한 "값 필드"의 데이터를 어느 테이블/컬럼에 저장할지 지정합니다.
미설정 시 화면의 연결 테이블에 컴포넌트의 바인딩 필드로 자동 저장됩니다.

{/* 저장 테이블 선택 */}
테이블을 찾을 수 없습니다. {/* 기본값 옵션 */} { updateConfig({ valueFieldStorage: { ...localConfig.valueFieldStorage, targetTable: undefined, targetColumn: undefined, }, }); setOpenStorageTableCombo(false); }} className="text-xs sm:text-sm" >
기본값 화면의 연결 테이블 사용
{allTables.map((table) => ( { updateConfig({ valueFieldStorage: { ...localConfig.valueFieldStorage, targetTable: table.tableName, targetColumn: undefined, // 테이블 변경 시 컬럼 초기화 }, }); setOpenStorageTableCombo(false); }} className="text-xs sm:text-sm" >
{table.displayName || table.tableName} {table.displayName && {table.tableName}}
))}

값을 저장할 테이블 (기본값: 화면 연결 테이블)

{/* 저장 컬럼 선택 */} {localConfig.valueFieldStorage?.targetTable && (
컬럼을 찾을 수 없습니다. {storageTableColumns.map((column) => ( { updateConfig({ valueFieldStorage: { ...localConfig.valueFieldStorage, targetColumn: column.columnName, }, }); setOpenStorageColumnCombo(false); }} className="text-xs sm:text-sm" >
{column.displayName || column.columnName} {column.displayName && {column.columnName}}
))}

값을 저장할 컬럼명

)} {/* 설명 박스 */}

저장 위치 동작

{localConfig.valueFieldStorage?.targetTable ? ( <>

선택한 값({localConfig.valueField})을

{localConfig.valueFieldStorage.targetTable} {" "} 테이블의{" "} {localConfig.valueFieldStorage.targetColumn || "(컬럼 미지정)"} {" "} 컬럼에 저장합니다.

) : (

기본값: 화면의 연결 테이블에 컴포넌트의 바인딩 필드로 저장됩니다.

)}
{(localConfig.searchFields || []).map((field, index) => (
))}
updateConfig({ showAdditionalInfo: checked }) } />
{localConfig.showAdditionalInfo && (
{(localConfig.additionalFields || []).map((field, index) => (
))}
)} {/* 필드 자동 매핑 설정 */}

필드 자동 매핑

선택한 항목의 필드를 화면의 다른 입력 필드에 자동으로 채워넣습니다

updateConfig({ enableFieldMapping: checked }) } />

활성화하면 항목 선택 시 설정된 필드들이 자동으로 채워집니다

{localConfig.enableFieldMapping && (
{(localConfig.fieldMappings || []).map((mapping, index) => (
매핑 #{index + 1}
{/* 표시명 */}
updateFieldMapping(index, { label: e.target.value }) } placeholder="예: 거래처명" className="h-8 text-xs sm:h-10 sm:text-sm" />

이 매핑의 설명 (선택사항)

{/* 소스 필드 (테이블의 컬럼) */}

가져올 데이터의 컬럼명

{/* 타겟 필드 (화면의 input ID) */}
updateFieldMapping(index, { targetField: e.target.value }) } placeholder="예: customer_name_input" className="h-8 text-xs sm:h-10 sm:text-sm" />

값을 채울 화면 컴포넌트의 ID (예: input의 id 속성)

{/* 예시 설명 */}

{mapping.sourceField && mapping.targetField ? ( <> {mapping.label || "이 필드"}: 테이블의{" "} {mapping.sourceField} {" "} 값을 화면의{" "} {mapping.targetField} {" "} 컴포넌트에 자동으로 채웁니다 ) : ( "소스 필드와 타겟 필드를 모두 선택하세요" )}

))}
{/* 사용 안내 */} {localConfig.fieldMappings && localConfig.fieldMappings.length > 0 && (

사용 방법

  • 화면에서 이 검색 컴포넌트로 항목을 선택하면
  • 설정된 매핑에 따라 다른 입력 필드들이 자동으로 채워집니다
  • 타겟 필드 ID는 화면 디자이너에서 설정한 컴포넌트 ID와 일치해야 합니다
)}
)}
); }