"use client"; import React, { useState, useEffect, useRef } from "react"; import { Input } from "@/components/ui/input"; import { X, Loader2, ChevronDown } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useEntitySearch } from "../entity-search-input/useEntitySearch"; import { EntitySearchResult } from "../entity-search-input/types"; import { cn } from "@/lib/utils"; import { AutocompleteSearchInputConfig } from "./types"; import { ComponentRendererProps } from "../../DynamicComponentRenderer"; export interface AutocompleteSearchInputProps extends ComponentRendererProps { config?: AutocompleteSearchInputConfig; tableName?: string; displayField?: string; valueField?: string; searchFields?: string[]; filterCondition?: Record; placeholder?: string; showAdditionalInfo?: boolean; additionalFields?: string[]; } export function AutocompleteSearchInputComponent({ component, config, tableName: propTableName, displayField: propDisplayField, valueField: propValueField, searchFields: propSearchFields, filterCondition = {}, placeholder: propPlaceholder, disabled = false, value, onChange, className, isInteractive = false, onFormDataChange, formData, }: AutocompleteSearchInputProps) { // config prop 우선, 없으면 개별 prop 사용 const tableName = config?.tableName || propTableName || ""; const displayField = config?.displayField || propDisplayField || ""; const valueField = config?.valueField || propValueField || ""; const searchFields = config?.searchFields || propSearchFields || [displayField]; const placeholder = config?.placeholder || propPlaceholder || "검색..."; const [inputValue, setInputValue] = useState(""); const [isOpen, setIsOpen] = useState(false); const [selectedData, setSelectedData] = useState(null); const containerRef = useRef(null); const { searchText, setSearchText, results, loading, clearSearch } = useEntitySearch({ tableName, searchFields, filterCondition, }); // formData에서 현재 값 가져오기 (isInteractive 모드) const currentValue = isInteractive && formData && component?.columnName ? formData[component.columnName] : value; // value가 변경되면 표시값 업데이트 useEffect(() => { if (currentValue && selectedData) { setInputValue(selectedData[displayField] || ""); } else if (!currentValue) { setInputValue(""); setSelectedData(null); } }, [currentValue, displayField, selectedData]); // 외부 클릭 감지 useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(event.target as Node)) { setIsOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); const handleInputChange = (e: React.ChangeEvent) => { const newValue = e.target.value; setInputValue(newValue); setSearchText(newValue); setIsOpen(true); }; const handleSelect = (item: EntitySearchResult) => { setSelectedData(item); setInputValue(item[displayField] || ""); console.log("🔍 AutocompleteSearchInput handleSelect:", { item, valueField, value: item[valueField], config, isInteractive, hasOnFormDataChange: !!onFormDataChange, columnName: component?.columnName, }); // isInteractive 모드에서만 저장 if (isInteractive && onFormDataChange) { // 필드 매핑 처리 if (config?.fieldMappings && Array.isArray(config.fieldMappings)) { console.log("📋 필드 매핑 처리 시작:", config.fieldMappings); config.fieldMappings.forEach((mapping: any, index: number) => { const targetField = mapping.targetField || mapping.targetColumn; console.log(` 매핑 ${index + 1}:`, { sourceField: mapping.sourceField, targetField, label: mapping.label, }); if (mapping.sourceField && targetField) { const sourceValue = item[mapping.sourceField]; console.log(` 값: ${mapping.sourceField} = ${sourceValue}`); if (sourceValue !== undefined) { console.log(` ✅ 저장: ${targetField} = ${sourceValue}`); onFormDataChange(targetField, sourceValue); } else { console.warn(` ⚠️ sourceField "${mapping.sourceField}"의 값이 undefined입니다`); } } else { console.warn(` ⚠️ 매핑 불완전: sourceField=${mapping.sourceField}, targetField=${targetField}`); } }); } // 기본 필드 저장 (columnName이 설정된 경우) if (component?.columnName) { console.log(`💾 기본 필드 저장: ${component.columnName} = ${item[valueField]}`); onFormDataChange(component.columnName, item[valueField]); } } // onChange 콜백 호출 (호환성) onChange?.(item[valueField], item); setIsOpen(false); }; const handleClear = () => { setInputValue(""); setSelectedData(null); onChange?.(null, null); setIsOpen(false); }; const handleInputFocus = () => { // 포커스 시 항상 검색 실행 (빈 값이면 전체 목록) if (!selectedData) { setSearchText(inputValue || ""); setIsOpen(true); } }; return (
{/* 입력 필드 */}
{loading && ( )} {inputValue && !disabled && ( )}
{/* 드롭다운 결과 */} {isOpen && (results.length > 0 || loading) && (
{loading && results.length === 0 ? (
검색 중...
) : results.length === 0 ? (
검색 결과가 없습니다
) : (
{results.map((item, index) => ( ))}
)}
)}
); }