ERP-node/frontend/lib/registry/components/conditional-container/ConditionalSectionViewer.tsx

180 lines
6.3 KiB
TypeScript

"use client";
import React, { useState, useEffect } from "react";
import { ConditionalSectionViewerProps } from "./types";
import { RealtimePreview } from "@/components/screen/RealtimePreviewDynamic";
import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRenderer";
import { cn } from "@/lib/utils";
import { Loader2 } from "lucide-react";
import { screenApi } from "@/lib/api/screen";
import { ComponentData } from "@/types/screen";
import { useAuth } from "@/hooks/useAuth";
/**
* 조건부 섹션 뷰어 컴포넌트
* 각 조건에 해당하는 화면을 표시
*/
export function ConditionalSectionViewer({
sectionId,
condition,
label,
screenId,
screenName,
isActive,
isDesignMode,
showBorder = true,
formData,
onFormDataChange,
groupedData, // 🆕 그룹 데이터
onSave, // 🆕 EditModal의 handleSave 콜백
}: ConditionalSectionViewerProps) {
const { userId, userName, user } = useAuth();
const [isLoading, setIsLoading] = useState(false);
const [components, setComponents] = useState<ComponentData[]>([]);
const [screenInfo, setScreenInfo] = useState<{ id: number; tableName?: string } | null>(null);
const [screenResolution, setScreenResolution] = useState<{ width: number; height: number } | null>(null);
// 화면 로드
useEffect(() => {
if (!screenId) {
setComponents([]);
setScreenInfo(null);
setScreenResolution(null);
return;
}
const loadScreen = async () => {
setIsLoading(true);
try {
const [layout, screen] = await Promise.all([screenApi.getLayout(screenId), screenApi.getScreen(screenId)]);
setComponents(layout.components || []);
setScreenInfo({
id: screenId,
tableName: screen.tableName,
});
setScreenResolution(layout.screenResolution || null);
} catch (error) {
console.error("화면 로드 실패:", error);
setComponents([]);
setScreenInfo(null);
setScreenResolution(null);
} finally {
setIsLoading(false);
}
};
loadScreen();
}, [screenId]);
// 디자인 모드가 아니고 비활성 섹션이면 렌더링하지 않음
if (!isDesignMode && !isActive) {
return null;
}
return (
<div
className={cn(
"relative w-full transition-all",
isDesignMode && showBorder && "border-muted-foreground/30 bg-muted/20 rounded-lg border-2 border-dashed",
!isDesignMode && !isActive && "hidden",
)}
style={{
minHeight: isDesignMode ? "200px" : undefined,
}}
data-section-id={sectionId}
>
{/* 섹션 라벨 (디자인 모드에서만 표시) */}
{isDesignMode && (
<div className="bg-background text-muted-foreground absolute -top-3 left-4 z-10 px-2 text-xs font-medium">
{label} {isActive && "(활성)"}
{screenId && ` - 화면 ID: ${screenId}`}
</div>
)}
{/* 화면 미선택 안내 (디자인 모드 + 화면 없을 때) */}
{isDesignMode && !screenId && (
<div className="absolute inset-0 flex items-center justify-center">
<div className="text-muted-foreground text-center">
<p className="text-sm"> </p>
<p className="mt-1 text-xs">: {condition}</p>
</div>
</div>
)}
{/* 로딩 중 */}
{isLoading && (
<div className="bg-background/50 absolute inset-0 z-20 flex items-center justify-center">
<div className="flex flex-col items-center gap-2">
<Loader2 className="text-primary h-6 w-6 animate-spin" />
<p className="text-muted-foreground text-xs"> ...</p>
</div>
</div>
)}
{/* 화면 렌더링 */}
{screenId && components.length > 0 && (
<>
{isDesignMode ? (
/* 디자인 모드: 화면 정보만 표시 */
<div className="absolute inset-0 flex items-center justify-center">
<div className="text-center">
<p className="text-foreground mb-2 text-sm font-medium">{screenName || `화면 ID: ${screenId}`}</p>
<p className="text-muted-foreground text-xs">
{screenResolution?.width} x {screenResolution?.height}
</p>
<p className="text-muted-foreground mt-1 text-xs"> {components.length}</p>
</div>
</div>
) : (
/* 실행 모드: 실제 화면 렌더링 */
<div className="w-full">
{/* 화면 크기만큼의 절대 위치 캔버스 */}
<div
className="relative mx-auto"
style={{
width: screenResolution?.width ? `${screenResolution.width}px` : "100%",
height: screenResolution?.height ? `${screenResolution.height}px` : "auto",
minHeight: "200px",
}}
>
{components.map((component) => {
const { position = { x: 0, y: 0, z: 1 }, size = { width: 200, height: 40 } } = component;
return (
<div
key={component.id}
className="absolute"
style={{
left: position.x || 0,
top: position.y || 0,
width: size.width || 200,
height: size.height || 40,
zIndex: position.z || 1,
}}
>
<DynamicComponentRenderer
component={component}
isInteractive={true}
screenId={screenInfo?.id}
tableName={screenInfo?.tableName}
userId={userId}
userName={userName}
companyCode={user?.companyCode}
formData={formData}
onFormDataChange={onFormDataChange}
groupedData={groupedData}
onSave={onSave}
/>
</div>
);
})}
</div>
</div>
)}
</>
)}
</div>
);
}