"use client"; import React, { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { X, Save, RotateCcw } from "lucide-react"; import { toast } from "sonner"; import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRenderer"; import { InteractiveScreenViewer } from "./InteractiveScreenViewer"; import { screenApi } from "@/lib/api/screen"; import { ComponentData } from "@/lib/types/screen"; interface EditModalProps { isOpen: boolean; onClose: () => void; screenId?: number; modalSize?: "sm" | "md" | "lg" | "xl" | "full"; editData?: any; onSave?: () => void; onDataChange?: (formData: Record) => void; // 폼 데이터 변경 콜백 추가 } /** * 편집 모달 컴포넌트 * 선택된 데이터를 폼 화면에 로드하여 편집할 수 있게 해주는 모달 */ export const EditModal: React.FC = ({ isOpen, onClose, screenId, modalSize = "lg", editData, onSave, onDataChange, }) => { const [loading, setLoading] = useState(false); const [formData, setFormData] = useState({}); const [originalData, setOriginalData] = useState({}); // 부분 업데이트용 원본 데이터 const [screenData, setScreenData] = useState(null); const [components, setComponents] = useState([]); // 컴포넌트 기반 동적 크기 계산 const calculateModalSize = () => { if (components.length === 0) { return { width: 600, height: 400 }; // 기본 크기 } const maxWidth = Math.max(...components.map((c) => (c.position?.x || 0) + (c.size?.width || 200)), 500) + 100; // 더 넉넉한 여백 const maxHeight = Math.max(...components.map((c) => (c.position?.y || 0) + (c.size?.height || 40)), 400) + 20; // 최소한의 여백만 추가 console.log(`🎯 계산된 모달 크기: ${maxWidth}px x ${maxHeight}px`); console.log( "📍 컴포넌트 위치들:", components.map((c) => ({ x: c.position?.x, y: c.position?.y, w: c.size?.width, h: c.size?.height })), ); return { width: maxWidth, height: maxHeight }; }; const dynamicSize = calculateModalSize(); // DialogContent 크기 강제 적용 useEffect(() => { if (isOpen && dynamicSize) { // 모달이 렌더링된 후 DOM 직접 조작으로 크기 강제 적용 setTimeout(() => { const dialogContent = document.querySelector('[role="dialog"] > div'); const modalContent = document.querySelector('[role="dialog"] [class*="overflow-auto"]'); if (dialogContent) { const targetWidth = dynamicSize.width; const targetHeight = dynamicSize.height; console.log(`🔧 DialogContent 크기 강제 적용: ${targetWidth}px x ${targetHeight}px`); dialogContent.style.width = `${targetWidth}px`; dialogContent.style.height = `${targetHeight}px`; dialogContent.style.minWidth = `${targetWidth}px`; dialogContent.style.minHeight = `${targetHeight}px`; dialogContent.style.maxWidth = "95vw"; dialogContent.style.maxHeight = "95vh"; dialogContent.style.padding = "0"; } // 스크롤 완전 제거 if (modalContent) { modalContent.style.overflow = "hidden"; console.log("🚫 스크롤 완전 비활성화"); } }, 100); // 100ms 지연으로 렌더링 완료 후 실행 } }, [isOpen, dynamicSize]); // 편집 데이터가 변경되면 폼 데이터 및 원본 데이터 초기화 useEffect(() => { if (editData) { console.log("📋 편집 데이터 로드:", editData); console.log("📋 편집 데이터 키들:", Object.keys(editData)); // 원본 데이터와 현재 폼 데이터 모두 설정 const dataClone = { ...editData }; setOriginalData(dataClone); // 원본 데이터 저장 (부분 업데이트용) setFormData(dataClone); // 편집용 폼 데이터 설정 console.log("📋 originalData 설정 완료:", dataClone); console.log("📋 formData 설정 완료:", dataClone); } else { console.log("⚠️ editData가 없습니다."); setOriginalData({}); setFormData({}); } }, [editData]); // formData 변경 시 로그 useEffect(() => { console.log("🔄 EditModal formData 상태 변경:", formData); console.log("🔄 formData 키들:", Object.keys(formData || {})); }, [formData]); // 화면 데이터 로드 useEffect(() => { const fetchScreenData = async () => { if (!screenId || !isOpen) return; try { setLoading(true); console.log("🔄 화면 데이터 로드 시작:", screenId); // 화면 정보와 레이아웃 데이터를 동시에 로드 const [screenInfo, layoutData] = await Promise.all([ screenApi.getScreen(screenId), screenApi.getLayout(screenId), ]); console.log("📋 화면 정보:", screenInfo); console.log("🎨 레이아웃 데이터:", layoutData); setScreenData(screenInfo); if (layoutData && layoutData.components) { setComponents(layoutData.components); console.log("✅ 화면 컴포넌트 로드 완료:", layoutData.components); // 컴포넌트와 formData 매칭 정보 출력 console.log("🔍 컴포넌트-formData 매칭 분석:"); layoutData.components.forEach((comp) => { if (comp.columnName) { const formValue = formData[comp.columnName]; console.log( ` - ${comp.columnName}: "${formValue}" (타입: ${comp.type}, 웹타입: ${(comp as any).widgetType})`, ); // 코드 타입인 경우 특별히 로깅 if ((comp as any).widgetType === "code") { console.log(" 🔍 코드 타입 세부정보:", { columnName: comp.columnName, componentId: comp.id, formValue, webTypeConfig: (comp as any).webTypeConfig, }); } } }); } else { console.log("⚠️ 레이아웃 데이터가 없습니다:", layoutData); } } catch (error) { console.error("❌ 화면 데이터 로드 실패:", error); toast.error("화면을 불러오는데 실패했습니다."); } finally { setLoading(false); } }; fetchScreenData(); }, [screenId, isOpen]); // 저장 처리 const handleSave = async () => { try { setLoading(true); console.log("💾 편집 데이터 저장:", formData); // TODO: 실제 저장 API 호출 // const result = await DynamicFormApi.updateFormData({ // screenId, // data: formData, // }); // 임시: 저장 성공 시뮬레이션 await new Promise((resolve) => setTimeout(resolve, 1000)); toast.success("수정이 완료되었습니다."); onSave?.(); onClose(); } catch (error) { console.error("❌ 저장 실패:", error); toast.error("저장 중 오류가 발생했습니다."); } finally { setLoading(false); } }; // 초기화 처리 const handleReset = () => { if (editData) { setFormData({ ...editData }); toast.info("초기값으로 되돌렸습니다."); } }; // 모달 크기 클래스 매핑 const getModalSizeClass = () => { switch (modalSize) { case "sm": return "max-w-md"; case "md": return "max-w-lg"; case "lg": return "max-w-4xl"; case "xl": return "max-w-6xl"; case "full": return "max-w-[95vw] max-h-[95vh]"; default: return "max-w-4xl"; } }; if (!screenId) { return null; } return ( 수정
{loading ? (

화면 로딩 중...

) : screenData && components.length > 0 ? ( // 원본 화면과 동일한 레이아웃으로 렌더링
{/* 화면 컴포넌트들 원본 레이아웃 유지하여 렌더링 */}
{components.map((component, index) => (
{/* 위젯 컴포넌트는 InteractiveScreenViewer 사용 (라벨 표시) */} {component.type === "widget" ? ( { console.log("📝 폼 데이터 변경:", fieldName, value); const newFormData = { ...formData, [fieldName]: value }; setFormData(newFormData); // 변경된 데이터를 즉시 부모로 전달 if (onDataChange) { console.log("📤 EditModal -> 부모로 데이터 전달:", newFormData); onDataChange(newFormData); } }} screenInfo={{ id: screenId || 0, tableName: screenData.tableName, }} /> ) : ( { console.log("📝 폼 데이터 변경:", fieldName, value); const newFormData = { ...formData, [fieldName]: value }; setFormData(newFormData); // 변경된 데이터를 즉시 부모로 전달 if (onDataChange) { console.log("📤 EditModal -> 부모로 데이터 전달:", newFormData); onDataChange(newFormData); } }} // 편집 모드로 설정 mode="edit" // 모달 내에서 렌더링되고 있음을 표시 isInModal={true} // 인터랙티브 모드 활성화 (formData 사용을 위해 필수) isInteractive={true} /> )}
))}
) : (

화면을 불러올 수 없습니다.

화면 ID: {screenId}

)}
); };