Merge pull request 'feature/screen-management' (#120) from feature/screen-management into main
Reviewed-on: http://39.117.244.52:3000/kjs/ERP-node/pulls/120
This commit is contained in:
commit
874cf485a8
|
|
@ -200,12 +200,21 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
|
||||||
|
|
||||||
// onChange 핸들러 - 컴포넌트 타입에 따라 다르게 처리
|
// onChange 핸들러 - 컴포넌트 타입에 따라 다르게 처리
|
||||||
const handleChange = (value: any) => {
|
const handleChange = (value: any) => {
|
||||||
|
// React 이벤트 객체인 경우 값 추출
|
||||||
|
let actualValue = value;
|
||||||
|
if (value && typeof value === "object" && value.nativeEvent && value.target) {
|
||||||
|
// SyntheticEvent인 경우 target.value 추출
|
||||||
|
actualValue = value.target.value;
|
||||||
|
console.log("⚠️ DynamicComponentRenderer: 이벤트 객체 감지, value 추출:", actualValue);
|
||||||
|
}
|
||||||
|
|
||||||
console.log("🔄 DynamicComponentRenderer handleChange 호출:", {
|
console.log("🔄 DynamicComponentRenderer handleChange 호출:", {
|
||||||
componentType,
|
componentType,
|
||||||
fieldName,
|
fieldName,
|
||||||
value,
|
originalValue: value,
|
||||||
valueType: typeof value,
|
actualValue,
|
||||||
isArray: Array.isArray(value),
|
valueType: typeof actualValue,
|
||||||
|
isArray: Array.isArray(actualValue),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (onFormDataChange) {
|
if (onFormDataChange) {
|
||||||
|
|
@ -213,11 +222,11 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
|
||||||
// 단순 input 컴포넌트는 (fieldName, value) 형태로 전달받음
|
// 단순 input 컴포넌트는 (fieldName, value) 형태로 전달받음
|
||||||
if (componentType === "repeater-field-group" || componentType === "repeater") {
|
if (componentType === "repeater-field-group" || componentType === "repeater") {
|
||||||
// fieldName과 함께 전달
|
// fieldName과 함께 전달
|
||||||
console.log("💾 RepeaterInput 데이터 저장:", fieldName, value);
|
console.log("💾 RepeaterInput 데이터 저장:", fieldName, actualValue);
|
||||||
onFormDataChange(fieldName, value);
|
onFormDataChange(fieldName, actualValue);
|
||||||
} else {
|
} else {
|
||||||
// 이미 fieldName이 포함된 경우는 그대로 전달
|
// 이미 fieldName이 포함된 경우는 그대로 전달
|
||||||
onFormDataChange(fieldName, value);
|
onFormDataChange(fieldName, actualValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -325,11 +325,8 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
setEmailUsername(newUsername);
|
setEmailUsername(newUsername);
|
||||||
const fullEmail = `${newUsername}@${emailDomain}`;
|
const fullEmail = `${newUsername}@${emailDomain}`;
|
||||||
|
|
||||||
if (isInteractive && formData && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
onFormDataChange({
|
onFormDataChange(component.columnName, fullEmail);
|
||||||
...formData,
|
|
||||||
[component.columnName]: fullEmail,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`h-full flex-1 rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
className={`h-full flex-1 rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
||||||
|
|
@ -367,11 +364,8 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
setEmailDomain(value);
|
setEmailDomain(value);
|
||||||
const fullEmail = `${emailUsername}@${value}`;
|
const fullEmail = `${emailUsername}@${value}`;
|
||||||
|
|
||||||
if (isInteractive && formData && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
onFormDataChange({
|
onFormDataChange(component.columnName, fullEmail);
|
||||||
...formData,
|
|
||||||
[component.columnName]: fullEmail,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -388,11 +382,8 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
setEmailDomain(currentValue);
|
setEmailDomain(currentValue);
|
||||||
const fullEmail = `${emailUsername}@${currentValue}`;
|
const fullEmail = `${emailUsername}@${currentValue}`;
|
||||||
|
|
||||||
if (isInteractive && formData && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
onFormDataChange({
|
onFormDataChange(component.columnName, fullEmail);
|
||||||
...formData,
|
|
||||||
[component.columnName]: fullEmail,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
setEmailDomainOpen(false);
|
setEmailDomainOpen(false);
|
||||||
}}
|
}}
|
||||||
|
|
@ -437,11 +428,8 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
setTelPart1(value);
|
setTelPart1(value);
|
||||||
const fullTel = `${value}-${telPart2}-${telPart3}`;
|
const fullTel = `${value}-${telPart2}-${telPart3}`;
|
||||||
|
|
||||||
if (isInteractive && formData && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
onFormDataChange({
|
onFormDataChange(component.columnName, fullTel);
|
||||||
...formData,
|
|
||||||
[component.columnName]: fullTel,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`h-full flex-1 rounded-md border px-3 py-2 text-center text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
className={`h-full flex-1 rounded-md border px-3 py-2 text-center text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
||||||
|
|
@ -462,11 +450,8 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
setTelPart2(value);
|
setTelPart2(value);
|
||||||
const fullTel = `${telPart1}-${value}-${telPart3}`;
|
const fullTel = `${telPart1}-${value}-${telPart3}`;
|
||||||
|
|
||||||
if (isInteractive && formData && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
onFormDataChange({
|
onFormDataChange(component.columnName, fullTel);
|
||||||
...formData,
|
|
||||||
[component.columnName]: fullTel,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`h-full flex-1 rounded-md border px-3 py-2 text-center text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
className={`h-full flex-1 rounded-md border px-3 py-2 text-center text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
||||||
|
|
@ -487,11 +472,8 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
setTelPart3(value);
|
setTelPart3(value);
|
||||||
const fullTel = `${telPart1}-${telPart2}-${value}`;
|
const fullTel = `${telPart1}-${telPart2}-${value}`;
|
||||||
|
|
||||||
if (isInteractive && formData && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
onFormDataChange({
|
onFormDataChange(component.columnName, fullTel);
|
||||||
...formData,
|
|
||||||
[component.columnName]: fullTel,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`h-full flex-1 rounded-md border px-3 py-2 text-center text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
className={`h-full flex-1 rounded-md border px-3 py-2 text-center text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
||||||
|
|
@ -523,11 +505,8 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
setUrlProtocol(newProtocol);
|
setUrlProtocol(newProtocol);
|
||||||
const fullUrl = `${newProtocol}${urlDomain}`;
|
const fullUrl = `${newProtocol}${urlDomain}`;
|
||||||
|
|
||||||
if (isInteractive && formData && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
onFormDataChange({
|
onFormDataChange(component.columnName, fullUrl);
|
||||||
...formData,
|
|
||||||
[component.columnName]: fullUrl,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`h-full w-[100px] cursor-pointer rounded-md border px-2 py-2 text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
className={`h-full w-[100px] cursor-pointer rounded-md border px-2 py-2 text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
||||||
|
|
@ -548,11 +527,8 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
setUrlDomain(newDomain);
|
setUrlDomain(newDomain);
|
||||||
const fullUrl = `${urlProtocol}${newDomain}`;
|
const fullUrl = `${urlProtocol}${newDomain}`;
|
||||||
|
|
||||||
if (isInteractive && formData && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
onFormDataChange({
|
onFormDataChange(component.columnName, fullUrl);
|
||||||
...formData,
|
|
||||||
[component.columnName]: fullUrl,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`h-full flex-1 rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
className={`h-full flex-1 rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
||||||
|
|
@ -595,11 +571,8 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
required={componentConfig.required || false}
|
required={componentConfig.required || false}
|
||||||
readOnly={componentConfig.readonly || false}
|
readOnly={componentConfig.readonly || false}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (isInteractive && formData && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
onFormDataChange({
|
onFormDataChange(component.columnName, e.target.value);
|
||||||
...formData,
|
|
||||||
[component.columnName]: e.target.value,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`box-border h-full w-full max-w-full resize-none rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} placeholder:text-gray-400 focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
className={`box-border h-full w-full max-w-full resize-none rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-gray-300"} ${componentConfig.disabled ? "bg-gray-100 text-gray-400" : "bg-white text-gray-900"} placeholder:text-gray-400 focus:border-orange-500 focus:ring-2 focus:ring-orange-100 disabled:cursor-not-allowed`}
|
||||||
|
|
@ -625,10 +598,13 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
|
|
||||||
if (isInteractive && formData && component.columnName) {
|
if (isInteractive && formData && component.columnName) {
|
||||||
// 인터랙티브 모드: formData 우선, 없으면 자동생성 값
|
// 인터랙티브 모드: formData 우선, 없으면 자동생성 값
|
||||||
displayValue = formData[component.columnName] || autoGeneratedValue || "";
|
const rawValue = formData[component.columnName] || autoGeneratedValue || "";
|
||||||
|
// 객체인 경우 빈 문자열로 변환 (에러 방지)
|
||||||
|
displayValue = typeof rawValue === "object" ? "" : String(rawValue);
|
||||||
} else {
|
} else {
|
||||||
// 디자인 모드: component.value 우선, 없으면 자동생성 값
|
// 디자인 모드: component.value 우선, 없으면 자동생성 값
|
||||||
displayValue = component.value || autoGeneratedValue || "";
|
const rawValue = component.value || autoGeneratedValue || "";
|
||||||
|
displayValue = typeof rawValue === "object" ? "" : String(rawValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("📄 Input 값 계산:", {
|
console.log("📄 Input 값 계산:", {
|
||||||
|
|
@ -636,9 +612,11 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
hasFormData: !!formData,
|
hasFormData: !!formData,
|
||||||
columnName: component.columnName,
|
columnName: component.columnName,
|
||||||
formDataValue: formData?.[component.columnName],
|
formDataValue: formData?.[component.columnName],
|
||||||
|
formDataValueType: typeof formData?.[component.columnName],
|
||||||
componentValue: component.value,
|
componentValue: component.value,
|
||||||
autoGeneratedValue,
|
autoGeneratedValue,
|
||||||
finalDisplayValue: displayValue,
|
finalDisplayValue: displayValue,
|
||||||
|
isObject: typeof displayValue === "object",
|
||||||
});
|
});
|
||||||
|
|
||||||
return displayValue;
|
return displayValue;
|
||||||
|
|
@ -670,23 +648,28 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
|
|
||||||
// isInteractive 모드에서는 formData 업데이트
|
// isInteractive 모드에서는 formData 업데이트
|
||||||
if (isInteractive && onFormDataChange && component.columnName) {
|
if (isInteractive && onFormDataChange && component.columnName) {
|
||||||
// console.log(`📤 TextInputComponent -> onFormDataChange 호출: ${component.columnName} = "${newValue}"`);
|
console.log(`✅ TextInputComponent onChange 조건 충족:`, {
|
||||||
console.log("🔍 onFormDataChange 함수 정보:", {
|
columnName: component.columnName,
|
||||||
functionName: onFormDataChange.name,
|
newValue,
|
||||||
functionString: onFormDataChange.toString().substring(0, 200),
|
valueType: typeof newValue,
|
||||||
|
isInteractive,
|
||||||
|
hasOnFormDataChange: !!onFormDataChange,
|
||||||
|
onFormDataChangeType: typeof onFormDataChange,
|
||||||
});
|
});
|
||||||
onFormDataChange(component.columnName, newValue);
|
onFormDataChange(component.columnName, newValue);
|
||||||
|
console.log(`✅ onFormDataChange 호출 완료`);
|
||||||
} else {
|
} else {
|
||||||
console.log("❌ TextInputComponent onFormDataChange 조건 미충족:", {
|
console.log("❌ TextInputComponent onFormDataChange 조건 미충족:", {
|
||||||
isInteractive,
|
isInteractive,
|
||||||
hasOnFormDataChange: !!onFormDataChange,
|
hasOnFormDataChange: !!onFormDataChange,
|
||||||
hasColumnName: !!component.columnName,
|
hasColumnName: !!component.columnName,
|
||||||
|
columnName: component.columnName,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 기존 onChange 핸들러도 호출
|
// props.onChange는 DynamicComponentRenderer의 handleChange
|
||||||
|
// 이벤트 객체 감지 및 값 추출 로직이 있으므로 안전하게 호출 가능
|
||||||
if (props.onChange) {
|
if (props.onChange) {
|
||||||
// console.log(`📤 TextInputComponent -> props.onChange 호출: "${newValue}"`);
|
|
||||||
props.onChange(newValue);
|
props.onChange(newValue);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue