테스트테이블 생성 및 오류 수정
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { commonCodeApi } from "../../../api/commonCode";
|
||||
import { tableTypeApi } from "../../../api/screen";
|
||||
import { filterDOMProps } from "@/lib/utils/domPropsFilter";
|
||||
|
||||
interface Option {
|
||||
value: string;
|
||||
@@ -14,11 +15,14 @@ export interface SelectBasicComponentProps {
|
||||
onUpdate?: (field: string, value: any) => void;
|
||||
isSelected?: boolean;
|
||||
isDesignMode?: boolean;
|
||||
isInteractive?: boolean;
|
||||
onFormDataChange?: (fieldName: string, value: any) => void;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
onClick?: () => void;
|
||||
onDragStart?: () => void;
|
||||
onDragEnd?: () => void;
|
||||
value?: any; // 외부에서 전달받는 값
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@@ -164,6 +168,7 @@ const loadGlobalCodeOptions = async (codeCategory: string): Promise<Option[]> =>
|
||||
const actualValue = code.code || code.CODE || code.value || code.code_value || `code_${index}`;
|
||||
const actualLabel =
|
||||
code.codeName ||
|
||||
code.code_name || // 스네이크 케이스 추가!
|
||||
code.name ||
|
||||
code.CODE_NAME ||
|
||||
code.NAME ||
|
||||
@@ -233,16 +238,34 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
|
||||
onUpdate,
|
||||
isSelected = false,
|
||||
isDesignMode = false,
|
||||
isInteractive = false,
|
||||
onFormDataChange,
|
||||
className,
|
||||
style,
|
||||
onClick,
|
||||
onDragStart,
|
||||
onDragEnd,
|
||||
value: externalValue, // 명시적으로 value prop 받기
|
||||
...props
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [selectedValue, setSelectedValue] = useState(componentConfig?.value || "");
|
||||
|
||||
// webTypeConfig 또는 componentConfig 사용 (DynamicWebTypeRenderer 호환성)
|
||||
const config = (props as any).webTypeConfig || componentConfig || {};
|
||||
|
||||
// 외부에서 전달받은 value가 있으면 우선 사용, 없으면 config.value 사용
|
||||
const [selectedValue, setSelectedValue] = useState(externalValue || config?.value || "");
|
||||
const [selectedLabel, setSelectedLabel] = useState("");
|
||||
|
||||
console.log("🔍 SelectBasicComponent 초기화:", {
|
||||
componentId: component.id,
|
||||
externalValue,
|
||||
componentConfigValue: componentConfig?.value,
|
||||
webTypeConfigValue: (props as any).webTypeConfig?.value,
|
||||
configValue: config?.value,
|
||||
finalSelectedValue: externalValue || config?.value || "",
|
||||
props: Object.keys(props),
|
||||
});
|
||||
const [codeOptions, setCodeOptions] = useState<Option[]>([]);
|
||||
const [isLoadingCodes, setIsLoadingCodes] = useState(false);
|
||||
const [dynamicCodeCategory, setDynamicCodeCategory] = useState<string | null>(null);
|
||||
@@ -250,7 +273,25 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
|
||||
const selectRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 코드 카테고리 결정: 동적 카테고리 > 설정 카테고리
|
||||
const codeCategory = dynamicCodeCategory || componentConfig?.codeCategory;
|
||||
const codeCategory = dynamicCodeCategory || config?.codeCategory;
|
||||
|
||||
// 외부 value prop 변경 시 selectedValue 업데이트
|
||||
useEffect(() => {
|
||||
const newValue = externalValue || config?.value || "";
|
||||
// 값이 실제로 다른 경우에만 업데이트 (빈 문자열도 유효한 값으로 처리)
|
||||
if (newValue !== selectedValue) {
|
||||
console.log(`🔄 SelectBasicComponent value 업데이트: "${selectedValue}" → "${newValue}"`);
|
||||
console.log(`🔍 업데이트 조건 분석:`, {
|
||||
externalValue,
|
||||
componentConfigValue: componentConfig?.value,
|
||||
configValue: config?.value,
|
||||
newValue,
|
||||
selectedValue,
|
||||
shouldUpdate: newValue !== selectedValue,
|
||||
});
|
||||
setSelectedValue(newValue);
|
||||
}
|
||||
}, [externalValue, config?.value]);
|
||||
|
||||
// 🚀 전역 상태 구독 및 동기화
|
||||
useEffect(() => {
|
||||
@@ -359,7 +400,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
|
||||
// 선택된 값에 따른 라벨 업데이트
|
||||
useEffect(() => {
|
||||
const getAllOptions = () => {
|
||||
const configOptions = componentConfig.options || [];
|
||||
const configOptions = config.options || [];
|
||||
return [...codeOptions, ...configOptions];
|
||||
};
|
||||
|
||||
@@ -370,7 +411,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
|
||||
if (newLabel !== selectedLabel) {
|
||||
setSelectedLabel(newLabel);
|
||||
}
|
||||
}, [selectedValue, codeOptions, componentConfig.options]);
|
||||
}, [selectedValue, codeOptions, config.options]);
|
||||
|
||||
// 클릭 이벤트 핸들러 (전역 상태 새로고침)
|
||||
const handleToggle = () => {
|
||||
@@ -416,10 +457,23 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
|
||||
setSelectedLabel(label);
|
||||
setIsOpen(false);
|
||||
|
||||
// 디자인 모드에서의 컴포넌트 속성 업데이트
|
||||
if (onUpdate) {
|
||||
onUpdate("value", value);
|
||||
}
|
||||
|
||||
// 인터랙티브 모드에서 폼 데이터 업데이트 (TextInputComponent와 동일한 로직)
|
||||
if (isInteractive && onFormDataChange && component.columnName) {
|
||||
console.log(`📤 SelectBasicComponent -> onFormDataChange 호출: ${component.columnName} = "${value}"`);
|
||||
onFormDataChange(component.columnName, value);
|
||||
} else {
|
||||
console.log("❌ SelectBasicComponent onFormDataChange 조건 미충족:", {
|
||||
isInteractive,
|
||||
hasOnFormDataChange: !!onFormDataChange,
|
||||
hasColumnName: !!component.columnName,
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`✅ [${component.id}] 옵션 선택:`, { value, label });
|
||||
};
|
||||
|
||||
@@ -473,7 +527,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
|
||||
|
||||
// 모든 옵션 가져오기
|
||||
const getAllOptions = () => {
|
||||
const configOptions = componentConfig.options || [];
|
||||
const configOptions = config.options || [];
|
||||
console.log(`🔧 [${component.id}] 옵션 병합:`, {
|
||||
codeOptionsLength: codeOptions.length,
|
||||
codeOptions: codeOptions.map((o) => ({ value: o.value, label: o.label })),
|
||||
@@ -486,6 +540,24 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
|
||||
const allOptions = getAllOptions();
|
||||
const placeholder = componentConfig.placeholder || "선택하세요";
|
||||
|
||||
// DOM props에서 React 전용 props 필터링
|
||||
const {
|
||||
component: _component,
|
||||
componentConfig: _componentConfig,
|
||||
screenId: _screenId,
|
||||
onUpdate: _onUpdate,
|
||||
isSelected: _isSelected,
|
||||
isDesignMode: _isDesignMode,
|
||||
className: _className,
|
||||
style: _style,
|
||||
onClick: _onClick,
|
||||
onDragStart: _onDragStart,
|
||||
onDragEnd: _onDragEnd,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const safeDomProps = filterDOMProps(otherProps);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={selectRef}
|
||||
@@ -494,8 +566,27 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
|
||||
onClick={onClick}
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={onDragEnd}
|
||||
{...props}
|
||||
{...safeDomProps}
|
||||
>
|
||||
{/* 라벨 렌더링 */}
|
||||
{component.label && component.style?.labelDisplay !== false && (
|
||||
<label
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "-25px",
|
||||
left: "0px",
|
||||
fontSize: component.style?.labelFontSize || "14px",
|
||||
color: component.style?.labelColor || "#374151",
|
||||
fontWeight: "500",
|
||||
// isInteractive 모드에서는 사용자 스타일 우선 적용
|
||||
...(isInteractive && component.style ? component.style : {}),
|
||||
}}
|
||||
>
|
||||
{component.label}
|
||||
{component.required && <span style={{ color: "#ef4444" }}>*</span>}
|
||||
</label>
|
||||
)}
|
||||
|
||||
{/* 커스텀 셀렉트 박스 */}
|
||||
<div
|
||||
className={`flex w-full cursor-pointer items-center justify-between rounded-md border border-gray-300 bg-white px-3 py-2 ${isDesignMode ? "pointer-events-none" : "hover:border-gray-400"} ${isSelected ? "ring-2 ring-blue-500" : ""} ${isOpen ? "border-blue-500" : ""} `}
|
||||
@@ -520,11 +611,11 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
|
||||
{/* 드롭다운 옵션 */}
|
||||
{isOpen && !isDesignMode && (
|
||||
<div
|
||||
className="absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg"
|
||||
className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg"
|
||||
style={{
|
||||
backgroundColor: "white",
|
||||
color: "black",
|
||||
zIndex: 9999,
|
||||
zIndex: 99999, // 더 높은 z-index로 설정
|
||||
}}
|
||||
>
|
||||
{(() => {
|
||||
|
||||
Reference in New Issue
Block a user