ERP-node/frontend/lib/registry/components/conditional-container/ConditionalContainerCompone...

217 lines
6.6 KiB
TypeScript
Raw Normal View History

"use client";
2025-11-17 10:09:02 +09:00
import React, { useState, useEffect, useRef } from "react";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { ConditionalContainerProps, ConditionalSection } from "./types";
import { ConditionalSectionViewer } from "./ConditionalSectionViewer";
import { cn } from "@/lib/utils";
console.log("🚀 ConditionalContainerComponent 모듈 로드됨!");
/**
*
* UI를
*/
export function ConditionalContainerComponent({
config,
controlField: propControlField,
controlLabel: propControlLabel,
sections: propSections,
defaultValue: propDefaultValue,
showBorder: propShowBorder,
spacing: propSpacing,
value,
onChange,
formData,
onFormDataChange,
isDesignMode = false,
onUpdateComponent,
onDeleteComponent,
onSelectComponent,
selectedComponentId,
2025-11-17 10:09:02 +09:00
onHeightChange,
componentId,
style,
className,
}: ConditionalContainerProps) {
console.log("🎯 ConditionalContainerComponent 렌더링!", {
isDesignMode,
hasOnHeightChange: !!onHeightChange,
componentId,
});
// config prop 우선, 없으면 개별 prop 사용
const controlField = config?.controlField || propControlField || "condition";
const controlLabel = config?.controlLabel || propControlLabel || "조건 선택";
const sections = config?.sections || propSections || [];
const defaultValue = config?.defaultValue || propDefaultValue || sections[0]?.condition;
const showBorder = config?.showBorder ?? propShowBorder ?? true;
const spacing = config?.spacing || propSpacing || "normal";
// 현재 선택된 값
const [selectedValue, setSelectedValue] = useState<string>(
value || formData?.[controlField] || defaultValue || ""
);
// formData 변경 시 동기화
useEffect(() => {
if (formData?.[controlField]) {
setSelectedValue(formData[controlField]);
}
}, [formData, controlField]);
// 값 변경 핸들러
const handleValueChange = (newValue: string) => {
setSelectedValue(newValue);
if (onChange) {
onChange(newValue);
}
if (onFormDataChange) {
onFormDataChange(controlField, newValue);
}
};
2025-11-17 10:09:02 +09:00
// 컨테이너 높이 측정용 ref
const containerRef = useRef<HTMLDivElement>(null);
const previousHeightRef = useRef<number>(0);
// 🔍 디버그: props 확인
useEffect(() => {
console.log("🔍 ConditionalContainer props:", {
isDesignMode,
hasOnHeightChange: !!onHeightChange,
componentId,
selectedValue,
});
}, [isDesignMode, onHeightChange, componentId, selectedValue]);
2025-11-17 10:09:02 +09:00
// 높이 변화 감지 및 콜백 호출
useEffect(() => {
console.log("🔍 ResizeObserver 등록 조건:", {
hasContainer: !!containerRef.current,
isDesignMode,
hasOnHeightChange: !!onHeightChange,
});
2025-11-17 10:09:02 +09:00
if (!containerRef.current || isDesignMode || !onHeightChange) return;
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
const newHeight = entry.contentRect.height;
// 높이가 실제로 변경되었을 때만 콜백 호출
if (Math.abs(newHeight - previousHeightRef.current) > 5) {
console.log(`📏 조건부 컨테이너 높이 변화: ${previousHeightRef.current}px → ${newHeight}px`);
previousHeightRef.current = newHeight;
onHeightChange(newHeight);
}
}
});
resizeObserver.observe(containerRef.current);
return () => {
resizeObserver.disconnect();
};
}, [isDesignMode, onHeightChange, selectedValue]); // selectedValue 변경 시에도 감지
// 간격 스타일
const spacingClass = {
tight: "space-y-2",
normal: "space-y-4",
loose: "space-y-8",
}[spacing];
return (
<div
2025-11-17 10:09:02 +09:00
ref={containerRef}
className={cn("w-full flex flex-col", spacingClass, className)}
style={style}
>
{/* 제어 셀렉트박스 */}
<div className="space-y-2 flex-shrink-0">
<Label htmlFor={controlField} className="text-xs sm:text-sm">
{controlLabel}
</Label>
<Select value={selectedValue} onValueChange={handleValueChange}>
<SelectTrigger
id={controlField}
className="h-8 text-xs sm:h-10 sm:text-sm"
>
<SelectValue placeholder="선택하세요" />
</SelectTrigger>
<SelectContent>
{sections.map((section) => (
<SelectItem key={section.id} value={section.condition}>
{section.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* 조건별 섹션들 */}
2025-11-17 10:09:02 +09:00
<div className="flex-1 min-h-0">
{isDesignMode ? (
// 디자인 모드: 모든 섹션 표시
<div className={spacingClass}>
{sections.map((section) => (
<ConditionalSectionViewer
key={section.id}
sectionId={section.id}
condition={section.condition}
label={section.label}
screenId={section.screenId}
screenName={section.screenName}
isActive={selectedValue === section.condition}
isDesignMode={isDesignMode}
showBorder={showBorder}
formData={formData}
onFormDataChange={onFormDataChange}
/>
))}
</div>
) : (
// 실행 모드: 활성 섹션만 표시
sections.map((section) =>
selectedValue === section.condition ? (
<ConditionalSectionViewer
key={section.id}
sectionId={section.id}
condition={section.condition}
label={section.label}
screenId={section.screenId}
screenName={section.screenName}
isActive={true}
isDesignMode={false}
showBorder={showBorder}
formData={formData}
onFormDataChange={onFormDataChange}
/>
) : null
)
)}
{/* 섹션이 없는 경우 안내 */}
{sections.length === 0 && isDesignMode && (
<div className="flex items-center justify-center min-h-[200px] border-2 border-dashed border-muted-foreground/30 rounded-lg bg-muted/20">
<p className="text-sm text-muted-foreground">
</p>
</div>
)}
</div>
</div>
);
}