"use client"; import React, { useEffect, useRef } from "react"; import { AutoRegisteringComponentRenderer } from "../../AutoRegisteringComponentRenderer"; import { V2InputDefinition } from "./index"; import { V2Input } from "@/components/v2/V2Input"; import { isColumnRequiredByMeta } from "../../DynamicComponentRenderer"; import { v2EventBus, V2_EVENTS } from "@/lib/v2-core"; /** * dataBinding이 설정된 v2-input을 위한 wrapper * v2-table-list의 TABLE_DATA_CHANGE 이벤트를 구독하여 * 선택된 행의 특정 컬럼 값을 자동으로 formData에 반영 */ function DataBindingWrapper({ dataBinding, columnName, onFormDataChange, isInteractive, children, }: { dataBinding: { sourceComponentId: string; sourceColumn: string }; columnName: string; onFormDataChange?: (field: string, value: any) => void; isInteractive?: boolean; children: React.ReactNode; }) { const lastBoundValueRef = useRef(null); useEffect(() => { if (!dataBinding?.sourceComponentId || !dataBinding?.sourceColumn) return; console.log("[DataBinding] 구독 시작:", { sourceComponentId: dataBinding.sourceComponentId, sourceColumn: dataBinding.sourceColumn, targetColumn: columnName, isInteractive, hasOnFormDataChange: !!onFormDataChange, }); const unsubscribe = v2EventBus.subscribe(V2_EVENTS.TABLE_DATA_CHANGE, (payload: any) => { console.log("[DataBinding] TABLE_DATA_CHANGE 수신:", { payloadSource: payload.source, expectedSource: dataBinding.sourceComponentId, dataLength: payload.data?.length, match: payload.source === dataBinding.sourceComponentId, }); if (payload.source !== dataBinding.sourceComponentId) return; const selectedData = payload.data; if (selectedData && selectedData.length > 0) { const value = selectedData[0][dataBinding.sourceColumn]; console.log("[DataBinding] 바인딩 값:", { column: dataBinding.sourceColumn, value, columnName }); if (value !== lastBoundValueRef.current) { lastBoundValueRef.current = value; if (onFormDataChange && columnName) { onFormDataChange(columnName, value ?? ""); } } } else { if (lastBoundValueRef.current !== null) { lastBoundValueRef.current = null; if (onFormDataChange && columnName) { onFormDataChange(columnName, ""); } } } }); return () => unsubscribe(); }, [dataBinding?.sourceComponentId, dataBinding?.sourceColumn, columnName, onFormDataChange, isInteractive]); return <>{children}; } /** * V2Input 렌더러 * 자동 등록 시스템을 사용하여 컴포넌트를 레지스트리에 등록 */ export class V2InputRenderer extends AutoRegisteringComponentRenderer { static componentDefinition = V2InputDefinition; render(): React.ReactElement { const { component, formData, onFormDataChange, isDesignMode, isSelected, isInteractive, ...restProps } = this.props; const config = component.componentConfig || component.config || {}; const columnName = component.columnName; const tableName = component.tableName || this.props.tableName; const currentValue = formData?.[columnName] ?? component.value ?? ""; const handleChange = (value: any) => { if (isInteractive && onFormDataChange && columnName) { onFormDataChange(columnName, value); } }; const style = component.style || {}; const labelDisplay = style.labelDisplay ?? (component as any).labelDisplay; const effectiveLabel = labelDisplay === true ? style.labelText || component.label : undefined; const dataBinding = config.dataBinding || (component as any).dataBinding || config.componentConfig?.dataBinding; if (dataBinding || (config as any).dataBinding || (component as any).dataBinding) { console.log("[V2InputRenderer] dataBinding 탐색:", { componentId: component.id, columnName, configKeys: Object.keys(config), configDataBinding: config.dataBinding, componentDataBinding: (component as any).dataBinding, nestedDataBinding: config.componentConfig?.dataBinding, finalDataBinding: dataBinding, }); } const inputElement = ( ); // dataBinding이 있으면 wrapper로 감싸서 이벤트 구독 if (dataBinding?.sourceComponentId && dataBinding?.sourceColumn) { return ( {inputElement} ); } return inputElement; } } // 자동 등록 실행 V2InputRenderer.registerSelf(); // Hot Reload 지원 (개발 모드) if (process.env.NODE_ENV === "development") { V2InputRenderer.enableHotReload(); }