"use client"; import React from "react"; import { AutoRegisteringComponentRenderer } from "../../AutoRegisteringComponentRenderer"; import { V2SelectDefinition } from "./index"; import { V2Select } from "@/components/v2/V2Select"; /** * V2Select 렌더러 * 자동 등록 시스템을 사용하여 컴포넌트를 레지스트리에 등록 */ export class V2SelectRenderer extends AutoRegisteringComponentRenderer { static componentDefinition = V2SelectDefinition; 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; // 🔧 카테고리 타입 감지 (inputType 또는 webType이 category인 경우) const inputType = component.componentConfig?.inputType || component.inputType; const webType = component.componentConfig?.webType || component.webType; const isCategoryType = inputType === "category" || webType === "category"; // formData에서 현재 값 가져오기 (기본값 지원) const defaultValue = config.defaultValue || ""; // 🔧 tagbox, check, tag, swap 모드는 본질적으로 다중 선택 const multiSelectModes = ["tagbox", "check", "checkbox", "tag", "swap"]; const isMultiple = config.multiple || multiSelectModes.includes(config.mode); let currentValue = formData?.[columnName] ?? component.value ?? ""; // 🔧 다중 선택 시 값 정규화 (잘못된 형식 필터링) if (isMultiple) { // 헬퍼: 유효한 값인지 체크 (중괄호, 따옴표, 백슬래시 없어야 함) // 숫자도 유효한 값으로 처리 const isValidValue = (v: any): boolean => { // 숫자면 유효 if (typeof v === "number" && !isNaN(v)) return true; if (typeof v !== "string") return false; if (!v || v.trim() === "") return false; if (v.includes("{") || v.includes("}") || v.includes('"') || v.includes("\\")) return false; return true; }; if (typeof currentValue === "string" && currentValue) { // 🔧 PostgreSQL 배열 형식 또는 중첩된 잘못된 형식 감지 if (currentValue.startsWith("{") || currentValue.includes('{"') || currentValue.includes('\\"')) { currentValue = []; } else if (currentValue.includes(",")) { // 쉼표 구분 문자열 파싱 후 유효한 값만 필터링 currentValue = currentValue.split(",").map(v => v.trim()).filter(isValidValue); } else if (isValidValue(currentValue)) { currentValue = [currentValue]; } else { currentValue = []; } } else if (Array.isArray(currentValue)) { // 🔧 배열일 때도 잘못된 값 필터링 + 숫자→문자열 변환! const filtered = currentValue .map(v => typeof v === "number" ? String(v) : v) .filter(isValidValue); currentValue = filtered; } else { currentValue = []; } } // 🆕 formData에 값이 없고 기본값이 설정된 경우, 기본값 적용 if ((currentValue === "" || currentValue === undefined || currentValue === null) && defaultValue && isInteractive && onFormDataChange && columnName) { // 초기 렌더링 시 기본값을 formData에 설정 setTimeout(() => { if (!formData?.[columnName]) { onFormDataChange(columnName, defaultValue); } }, 0); currentValue = defaultValue; } // 값 변경 핸들러 (배열 → 쉼표 구분 문자열로 변환하여 저장) const handleChange = (value: any) => { if (isInteractive && onFormDataChange && columnName) { // 🔧 배열이면 무조건 쉼표 구분 문자열로 변환 (PostgreSQL 배열 형식 방지) if (Array.isArray(value)) { const stringValue = value.map(v => typeof v === "number" ? String(v) : v).join(","); onFormDataChange(columnName, stringValue); } else { onFormDataChange(columnName, value); } } }; // 🔧 DynamicComponentRenderer에서 전달한 style/size를 우선 사용 (height 포함) // restProps.style에 mergedStyle(height 변환됨)이 있고, restProps.size에도 size가 있음 const effectiveStyle = restProps.style || component.style; const effectiveSize = restProps.size || component.size; // 디버깅 필요시 주석 해제 // console.log("🔍 [V2SelectRenderer]", { componentId: component.id, effectiveStyle, effectiveSize }); // 🔧 restProps에서 style, size 제외 (effectiveStyle/effectiveSize가 우선되어야 함) const { style: _style, size: _size, ...restPropsClean } = restProps as any; return ( ); } } // 자동 등록 실행 V2SelectRenderer.registerSelf(); // Hot Reload 지원 (개발 모드) if (process.env.NODE_ENV === "development") { V2SelectRenderer.enableHotReload(); }