"use client"; import { useEffect, useState } from "react"; import { useParams } from "next/navigation"; import { Button } from "@/components/ui/button"; import { Loader2 } from "lucide-react"; import { screenApi } from "@/lib/api/screen"; import { ScreenDefinition, LayoutData } from "@/types/screen"; import { InteractiveScreenViewer } from "@/components/screen/InteractiveScreenViewerDynamic"; import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRenderer"; import { DynamicWebTypeRenderer } from "@/lib/registry"; import { useRouter } from "next/navigation"; import { toast } from "sonner"; import { initializeComponents } from "@/lib/registry/components"; import { EditModal } from "@/components/screen/EditModal"; import { isFileComponent, getComponentWebType } from "@/lib/utils/componentTypeUtils"; // import { ResponsiveScreenContainer } from "@/components/screen/ResponsiveScreenContainer"; // 컨테이너 제거 export default function ScreenViewPage() { const params = useParams(); const router = useRouter(); const screenId = parseInt(params.screenId as string); const [screen, setScreen] = useState(null); const [layout, setLayout] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [formData, setFormData] = useState>({}); // 테이블 선택된 행 상태 (화면 레벨에서 관리) const [selectedRows, setSelectedRows] = useState([]); const [selectedRowsData, setSelectedRowsData] = useState([]); // 테이블 새로고침을 위한 키 상태 const [refreshKey, setRefreshKey] = useState(0); // 편집 모달 상태 const [editModalOpen, setEditModalOpen] = useState(false); const [editModalConfig, setEditModalConfig] = useState<{ screenId?: number; modalSize?: "sm" | "md" | "lg" | "xl" | "full"; editData?: any; onSave?: () => void; }>({}); useEffect(() => { const initComponents = async () => { try { console.log("🚀 할당된 화면에서 컴포넌트 시스템 초기화 시작..."); await initializeComponents(); console.log("✅ 할당된 화면에서 컴포넌트 시스템 초기화 완료"); } catch (error) { console.error("❌ 할당된 화면에서 컴포넌트 시스템 초기화 실패:", error); } }; initComponents(); }, []); // 편집 모달 이벤트 리스너 등록 useEffect(() => { const handleOpenEditModal = (event: CustomEvent) => { console.log("🎭 편집 모달 열기 이벤트 수신:", event.detail); setEditModalConfig({ screenId: event.detail.screenId, modalSize: event.detail.modalSize, editData: event.detail.editData, onSave: event.detail.onSave, }); setEditModalOpen(true); }; // @ts-ignore window.addEventListener("openEditModal", handleOpenEditModal); return () => { // @ts-ignore window.removeEventListener("openEditModal", handleOpenEditModal); }; }, []); useEffect(() => { const loadScreen = async () => { try { setLoading(true); setError(null); // 화면 정보 로드 const screenData = await screenApi.getScreen(screenId); setScreen(screenData); // 레이아웃 로드 try { const layoutData = await screenApi.getLayout(screenId); setLayout(layoutData); } catch (layoutError) { console.warn("레이아웃 로드 실패, 빈 레이아웃 사용:", layoutError); setLayout({ components: [], gridSettings: { columns: 12, gap: 16, padding: 16 }, }); } } catch (error) { console.error("화면 로드 실패:", error); setError("화면을 불러오는데 실패했습니다."); toast.error("화면을 불러오는데 실패했습니다."); } finally { setLoading(false); } }; if (screenId) { loadScreen(); } }, [screenId]); if (loading) { return (

화면을 불러오는 중...

); } if (error || !screen) { return (
⚠️

화면을 찾을 수 없습니다

{error || "요청하신 화면이 존재하지 않습니다."}

); } // 화면 해상도 정보가 있으면 해당 크기로, 없으면 기본 크기 사용 const screenWidth = layout?.screenResolution?.width || 1200; const screenHeight = layout?.screenResolution?.height || 800; return (
{layout && layout.components.length > 0 ? ( // 캔버스 컴포넌트들을 정확한 해상도로 표시
{layout.components .filter((comp) => !comp.parentId) // 최상위 컴포넌트만 렌더링 (그룹 포함) .map((component) => { // 그룹 컴포넌트인 경우 특별 처리 if (component.type === "group") { const groupChildren = layout.components.filter((child) => child.parentId === component.id); return (
{/* 그룹 제목 */} {(component as any).title && (
{(component as any).title}
)} {/* 그룹 내 자식 컴포넌트들 렌더링 */} {groupChildren.map((child) => (
{ console.log("📝 폼 데이터 변경:", { fieldName, value }); setFormData((prev) => { const newFormData = { ...prev, [fieldName]: value, }; console.log("📊 전체 폼 데이터:", newFormData); return newFormData; }); }} screenInfo={{ id: screenId, tableName: screen?.tableName, }} />
))}
); } // 라벨 표시 여부 계산 const templateTypes = ["datatable"]; const shouldShowLabel = component.style?.labelDisplay !== false && (component.label || component.style?.labelText) && !templateTypes.includes(component.type); const labelText = component.style?.labelText || component.label || ""; const labelStyle = { fontSize: component.style?.labelFontSize || "14px", color: component.style?.labelColor || "#212121", fontWeight: component.style?.labelFontWeight || "500", backgroundColor: component.style?.labelBackgroundColor || "transparent", padding: component.style?.labelPadding || "0", borderRadius: component.style?.labelBorderRadius || "0", marginBottom: component.style?.labelMarginBottom || "4px", }; // 일반 컴포넌트 렌더링 return (
{/* 라벨을 외부에 별도로 렌더링 */} {shouldShowLabel && (
{labelText} {component.required && *}
)} {/* 실제 컴포넌트 */}
{ // console.log("🎯 할당된 화면 컴포넌트:", { // id: component.id, // type: component.type, // position: component.position, // size: component.size, // styleWidth: component.style?.width, // styleHeight: component.style?.height, // finalWidth: `${component.size.width}px`, // finalHeight: `${component.size.height}px`, // }); }} > {/* 위젯 컴포넌트가 아닌 경우 DynamicComponentRenderer 사용 */} {component.type !== "widget" ? ( { setFormData((prev) => ({ ...prev, [fieldName]: value, })); }} screenId={screenId} tableName={screen?.tableName} onRefresh={() => { console.log("화면 새로고침 요청"); // 테이블 컴포넌트 강제 새로고침을 위한 키 업데이트 setRefreshKey((prev) => prev + 1); // 선택된 행 상태도 초기화 setSelectedRows([]); setSelectedRowsData([]); }} onClose={() => { console.log("화면 닫기 요청"); }} // 테이블 선택된 행 정보 전달 selectedRows={selectedRows} selectedRowsData={selectedRowsData} onSelectedRowsChange={(newSelectedRows, newSelectedRowsData) => { setSelectedRows(newSelectedRows); setSelectedRowsData(newSelectedRowsData); }} // 테이블 새로고침 키 전달 refreshKey={refreshKey} /> ) : ( { // 유틸리티 함수로 파일 컴포넌트 감지 if (isFileComponent(component)) { console.log(`🎯 page.tsx - 파일 컴포넌트 감지 → webType: "file"`, { componentId: component.id, componentType: component.type, originalWebType: component.webType }); return "file"; } // 다른 컴포넌트는 유틸리티 함수로 webType 결정 return getComponentWebType(component) || "text"; })()} config={component.webTypeConfig} props={{ component: component, value: formData[component.columnName || component.id] || "", onChange: (value: any) => { const fieldName = component.columnName || component.id; setFormData((prev) => ({ ...prev, [fieldName]: value, })); }, onFormDataChange: (fieldName, value) => { console.log(`🎯 page.tsx onFormDataChange 호출: ${fieldName} = "${value}"`); console.log("📋 현재 formData:", formData); setFormData((prev) => { const newFormData = { ...prev, [fieldName]: value, }; console.log("📝 업데이트된 formData:", newFormData); return newFormData; }); }, isInteractive: true, formData: formData, readonly: component.readonly, required: component.required, placeholder: component.placeholder, className: "w-full h-full", }} /> )}
); })}
) : ( // 빈 화면일 때도 깔끔하게 표시
📄

화면이 비어있습니다

이 화면에는 아직 설계된 컴포넌트가 없습니다.

)} {/* 편집 모달 */} { setEditModalOpen(false); setEditModalConfig({}); }} screenId={editModalConfig.screenId} modalSize={editModalConfig.modalSize} editData={editModalConfig.editData} onSave={editModalConfig.onSave} onDataChange={(changedFormData) => { console.log("📝 EditModal에서 데이터 변경 수신:", changedFormData); // 변경된 데이터를 메인 폼에 반영 setFormData((prev) => { const updatedFormData = { ...prev, ...changedFormData, // 변경된 필드들만 업데이트 }; console.log("📊 메인 폼 데이터 업데이트:", updatedFormData); return updatedFormData; }); }} />
); }