"use client"; import React, { useState, useEffect, useMemo, useCallback } from "react"; import { ComponentRendererProps } from "@/types/component"; import { SelectedItemsDetailInputConfig, AdditionalFieldDefinition } from "./types"; import { useModalDataStore, ModalDataItem } from "@/stores/modalDataStore"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Checkbox } from "@/components/ui/checkbox"; import { Button } from "@/components/ui/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { X } from "lucide-react"; import { cn } from "@/lib/utils"; export interface SelectedItemsDetailInputComponentProps extends ComponentRendererProps { config?: SelectedItemsDetailInputConfig; } /** * SelectedItemsDetailInput 컴포넌트 * 선택된 항목들의 상세 정보를 입력하는 컴포넌트 */ export const SelectedItemsDetailInputComponent: React.FC = ({ component, isDesignMode = false, isSelected = false, isInteractive = false, onClick, onDragStart, onDragEnd, config, className, style, formData, onFormDataChange, screenId, ...props }) => { // 컴포넌트 설정 const componentConfig = useMemo(() => ({ dataSourceId: component.id || "default", displayColumns: [], additionalFields: [], layout: "grid", showIndex: true, allowRemove: false, emptyMessage: "전달받은 데이터가 없습니다.", targetTable: "", ...config, ...component.config, } as SelectedItemsDetailInputConfig), [config, component.config, component.id]); // 모달 데이터 스토어에서 데이터 가져오기 // dataSourceId를 안정적으로 유지 const dataSourceId = useMemo( () => componentConfig.dataSourceId || component.id || "default", [componentConfig.dataSourceId, component.id] ); // 전체 레지스트리를 가져와서 컴포넌트 내부에서 필터링 (캐싱 문제 회피) const dataRegistry = useModalDataStore((state) => state.dataRegistry); const modalData = useMemo( () => dataRegistry[dataSourceId] || [], [dataRegistry, dataSourceId] ); const updateItemData = useModalDataStore((state) => state.updateItemData); // 로컬 상태로 데이터 관리 const [items, setItems] = useState([]); // 모달 데이터가 변경되면 로컬 상태 업데이트 useEffect(() => { if (modalData && modalData.length > 0) { console.log("📦 [SelectedItemsDetailInput] 데이터 수신:", modalData); setItems(modalData); // formData에도 반영 (초기 로드 시에만) if (onFormDataChange && items.length === 0) { onFormDataChange({ [component.id || "selected_items"]: modalData }); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [modalData, component.id]); // onFormDataChange는 의존성에서 제외 // 스타일 계산 const componentStyle: React.CSSProperties = { width: "100%", height: "100%", ...component.style, ...style, }; // 디자인 모드 스타일 if (isDesignMode) { componentStyle.border = "1px dashed #cbd5e1"; componentStyle.borderColor = isSelected ? "#3b82f6" : "#cbd5e1"; componentStyle.padding = "16px"; componentStyle.borderRadius = "8px"; } // 이벤트 핸들러 const handleClick = (e: React.MouseEvent) => { e.stopPropagation(); onClick?.(); }; // 필드 값 변경 핸들러 const handleFieldChange = useCallback((itemId: string | number, fieldName: string, value: any) => { // 상태 업데이트 setItems((prevItems) => { const updatedItems = prevItems.map((item) => item.id === itemId ? { ...item, additionalData: { ...item.additionalData, [fieldName]: value, }, } : item ); // formData에도 반영 (디바운스 없이 즉시 반영) if (onFormDataChange) { onFormDataChange({ [component.id || "selected_items"]: updatedItems }); } return updatedItems; }); // 스토어에도 업데이트 updateItemData(dataSourceId, itemId, { [fieldName]: value }); }, [dataSourceId, updateItemData, onFormDataChange, component.id]); // 항목 제거 핸들러 const handleRemoveItem = (itemId: string | number) => { setItems((prevItems) => prevItems.filter((item) => item.id !== itemId)); }; // 개별 필드 렌더링 const renderField = (field: AdditionalFieldDefinition, item: ModalDataItem) => { const value = item.additionalData?.[field.name] || field.defaultValue || ""; const commonProps = { value: value || "", disabled: componentConfig.disabled || componentConfig.readonly, placeholder: field.placeholder, required: field.required, }; switch (field.type) { case "select": return ( ); case "textarea": return (