"use client"; import React, { 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 { useRouter } from "next/navigation"; import { toast } from "sonner"; import { initializeComponents } from "@/lib/registry/components"; import { EditModal } from "@/components/screen/EditModal"; import { RealtimePreview } from "@/components/screen/RealtimePreviewDynamic"; 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 [selectedRowsData, setSelectedRowsData] = useState([]); // 플로우에서 선택된 데이터 (버튼 액션에 전달) const [flowSelectedData, setFlowSelectedData] = useState([]); const [flowSelectedStepId, setFlowSelectedStepId] = useState(null); // 테이블 새로고침을 위한 키 (값이 변경되면 테이블이 리렌더링됨) const [tableRefreshKey, setTableRefreshKey] = useState(0); // 플로우 새로고침을 위한 키 (값이 변경되면 플로우 데이터가 리렌더링됨) const [flowRefreshKey, setFlowRefreshKey] = useState(0); // 편집 모달 상태 const [editModalOpen, setEditModalOpen] = useState(false); const [editModalConfig, setEditModalConfig] = useState<{ screenId?: number; modalSize?: "sm" | "md" | "lg" | "xl" | "full"; editData?: Record; onSave?: () => void; modalTitle?: string; modalDescription?: string; }>({}); // 자동 스케일 조정 (사용자 화면 크기에 맞춤) const [scale, setScale] = useState(1); const containerRef = React.useRef(null); 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, modalTitle: event.detail.modalTitle, modalDescription: event.detail.modalDescription, }); setEditModalOpen(true); }; // @ts-expect-error - CustomEvent type window.addEventListener("openEditModal", handleOpenEditModal); return () => { // @ts-expect-error - CustomEvent type 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({ screenId, components: [], gridSettings: { columns: 12, gap: 16, padding: 16, enabled: true, size: 8, color: "#e0e0e0", opacity: 0.5, snapToGrid: true, }, }); } } catch (error) { console.error("화면 로드 실패:", error); setError("화면을 불러오는데 실패했습니다."); toast.error("화면을 불러오는데 실패했습니다."); } finally { setLoading(false); } }; if (screenId) { loadScreen(); } }, [screenId]); // 자동 스케일 조정 useEffect (항상 화면에 꽉 차게) useEffect(() => { const updateScale = () => { if (containerRef.current && layout) { const screenWidth = layout?.screenResolution?.width || 1200; const containerWidth = containerRef.current.offsetWidth; const availableWidth = containerWidth - 32; // 좌우 패딩 16px * 2 // 항상 화면에 맞춰서 스케일 조정 (늘리거나 줄임) const newScale = availableWidth / screenWidth; console.log("📏 스케일 계산 (화면 꽉 차게):", { screenWidth, containerWidth, availableWidth, scale: newScale, }); setScale(newScale); } }; // 초기 측정 (DOM이 완전히 렌더링된 후) const timer = setTimeout(() => { updateScale(); }, 100); window.addEventListener("resize", updateScale); return () => { clearTimeout(timer); window.removeEventListener("resize", updateScale); }; }, [layout]); 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((component) => !component.parentId) .map((component) => ( {}} screenId={screenId} tableName={screen?.tableName} selectedRowsData={selectedRowsData} onSelectedRowsChange={(_, selectedData) => { console.log("🔍 화면에서 선택된 행 데이터:", selectedData); setSelectedRowsData(selectedData); }} flowSelectedData={flowSelectedData} flowSelectedStepId={flowSelectedStepId} onFlowSelectedDataChange={(selectedData: any[], stepId: number | null) => { console.log("🔍 [page.tsx] 플로우 선택된 데이터 받음:", { dataCount: selectedData.length, selectedData, stepId, }); setFlowSelectedData(selectedData); setFlowSelectedStepId(stepId); console.log("🔍 [page.tsx] 상태 업데이트 완료"); }} refreshKey={tableRefreshKey} onRefresh={() => { console.log("🔄 테이블 새로고침 요청됨"); setTableRefreshKey((prev) => prev + 1); setSelectedRowsData([]); // 선택 해제 }} flowRefreshKey={flowRefreshKey} onFlowRefresh={() => { console.log("🔄 플로우 새로고침 요청됨"); setFlowRefreshKey((prev) => prev + 1); setFlowSelectedData([]); // 선택 해제 setFlowSelectedStepId(null); }} formData={formData} onFormDataChange={(fieldName, value) => { console.log("📝 폼 데이터 변경:", fieldName, "=", value); setFormData((prev) => ({ ...prev, [fieldName]: value })); }} > {/* 자식 컴포넌트들 */} {(component.type === "group" || component.type === "container" || component.type === "area") && layout.components .filter((child) => child.parentId === component.id) .map((child) => { // 자식 컴포넌트의 위치를 부모 기준 상대 좌표로 조정 const relativeChildComponent = { ...child, position: { x: child.position.x - component.position.x, y: child.position.y - component.position.y, z: child.position.z || 1, }, }; return ( {}} screenId={screenId} tableName={screen?.tableName} selectedRowsData={selectedRowsData} onSelectedRowsChange={(_, selectedData) => { console.log("🔍 화면에서 선택된 행 데이터 (자식):", selectedData); setSelectedRowsData(selectedData); }} refreshKey={tableRefreshKey} onRefresh={() => { console.log("🔄 테이블 새로고침 요청됨 (자식)"); setTableRefreshKey((prev) => prev + 1); setSelectedRowsData([]); // 선택 해제 }} formData={formData} onFormDataChange={(fieldName, value) => { console.log("📝 폼 데이터 변경 (자식):", fieldName, "=", value); setFormData((prev) => ({ ...prev, [fieldName]: value })); }} /> ); })} ))}
) : ( // 빈 화면일 때
📄

화면이 비어있습니다

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

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