"use client"; import React, { useState, useEffect } from "react"; import { ResizableDialog, ResizableDialogContent, ResizableDialogHeader, ResizableDialogTitle, ResizableDialogDescription, ResizableDialogFooter, } from "@/components/ui/resizable-dialog"; import { InteractiveScreenViewerDynamic } from "@/components/screen/InteractiveScreenViewerDynamic"; import { screenApi } from "@/lib/api/screen"; import { ComponentData } from "@/types/screen"; import { toast } from "sonner"; import { dynamicFormApi } from "@/lib/api/dynamicForm"; import { useAuth } from "@/hooks/useAuth"; interface EditModalState { isOpen: boolean; screenId: number | null; title: string; description?: string; modalSize: "sm" | "md" | "lg" | "xl"; editData: Record; onSave?: () => void; groupByColumns?: string[]; // ๐Ÿ†• ๊ทธ๋ฃนํ•‘ ์ปฌ๋Ÿผ (์˜ˆ: ["order_no"]) tableName?: string; // ๐Ÿ†• ํ…Œ์ด๋ธ”๋ช… (๊ทธ๋ฃน ์กฐํšŒ์šฉ) } interface EditModalProps { className?: string; } export const EditModal: React.FC = ({ className }) => { const { user } = useAuth(); const [modalState, setModalState] = useState({ isOpen: false, screenId: null, title: "", description: "", modalSize: "md", editData: {}, onSave: undefined, groupByColumns: undefined, tableName: undefined, }); const [screenData, setScreenData] = useState<{ components: ComponentData[]; screenInfo: any; } | null>(null); const [loading, setLoading] = useState(false); const [screenDimensions, setScreenDimensions] = useState<{ width: number; height: number; offsetX?: number; offsetY?: number; } | null>(null); // ํผ ๋ฐ์ดํ„ฐ ์ƒํƒœ (ํŽธ์ง‘ ๋ฐ์ดํ„ฐ๋กœ ์ดˆ๊ธฐํ™”๋จ) const [formData, setFormData] = useState>({}); const [originalData, setOriginalData] = useState>({}); // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์ƒํƒœ (๊ฐ™์€ order_no์˜ ๋ชจ๋“  ํ’ˆ๋ชฉ) const [groupData, setGroupData] = useState[]>([]); const [originalGroupData, setOriginalGroupData] = useState[]>([]); // ํ™”๋ฉด์˜ ์‹ค์ œ ํฌ๊ธฐ ๊ณ„์‚ฐ ํ•จ์ˆ˜ (ScreenModal๊ณผ ๋™์ผ) const calculateScreenDimensions = (components: ComponentData[]) => { if (components.length === 0) { return { width: 400, height: 300, offsetX: 0, offsetY: 0, }; } // ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ๊ณ„ ์ฐพ๊ธฐ let minX = Infinity; let minY = Infinity; let maxX = -Infinity; let maxY = -Infinity; components.forEach((component) => { const x = parseFloat(component.position?.x?.toString() || "0"); const y = parseFloat(component.position?.y?.toString() || "0"); const width = parseFloat(component.size?.width?.toString() || "100"); const height = parseFloat(component.size?.height?.toString() || "40"); minX = Math.min(minX, x); minY = Math.min(minY, y); maxX = Math.max(maxX, x + width); maxY = Math.max(maxY, y + height); }); // ์‹ค์ œ ์ปจํ…์ธ  ํฌ๊ธฐ ๊ณ„์‚ฐ const contentWidth = maxX - minX; const contentHeight = maxY - minY; // ์ ์ ˆํ•œ ์—ฌ๋ฐฑ ์ถ”๊ฐ€ (์ฃผ์„์ฒ˜๋ฆฌ - ์‚ฌ์šฉ์ž ์„ค์ • ํฌ๊ธฐ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ) // const paddingX = 40; // const paddingY = 40; const finalWidth = Math.max(contentWidth, 400); // padding ์ œ๊ฑฐ const finalHeight = Math.max(contentHeight, 300); // padding ์ œ๊ฑฐ return { width: Math.min(finalWidth, window.innerWidth * 0.95), height: Math.min(finalHeight, window.innerHeight * 0.9), offsetX: Math.max(0, minX), // paddingX ์ œ๊ฑฐ offsetY: Math.max(0, minY), // paddingY ์ œ๊ฑฐ }; }; // ์ „์—ญ ๋ชจ๋‹ฌ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ useEffect(() => { const handleOpenEditModal = (event: CustomEvent) => { const { screenId, title, description, modalSize, editData, onSave, groupByColumns, tableName } = event.detail; setModalState({ isOpen: true, screenId, title, description: description || "", modalSize: modalSize || "lg", editData: editData || {}, onSave, groupByColumns, // ๐Ÿ†• ๊ทธ๋ฃนํ•‘ ์ปฌ๋Ÿผ tableName, // ๐Ÿ†• ํ…Œ์ด๋ธ”๋ช… }); // ํŽธ์ง‘ ๋ฐ์ดํ„ฐ๋กœ ํผ ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™” setFormData(editData || {}); setOriginalData(editData || {}); }; const handleCloseEditModal = () => { // ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ onSave ์ฝœ๋ฐฑ ์‹คํ–‰ (ํ…Œ์ด๋ธ” ์ƒˆ๋กœ๊ณ ์นจ) if (modalState.onSave) { try { modalState.onSave(); } catch (callbackError) { console.error("โš ๏ธ onSave ์ฝœ๋ฐฑ ์—๋Ÿฌ:", callbackError); } } // ๋ชจ๋‹ฌ ๋‹ซ๊ธฐ handleClose(); }; window.addEventListener("openEditModal", handleOpenEditModal as EventListener); window.addEventListener("closeEditModal", handleCloseEditModal); return () => { window.removeEventListener("openEditModal", handleOpenEditModal as EventListener); window.removeEventListener("closeEditModal", handleCloseEditModal); }; }, [modalState.onSave]); // modalState.onSave๋ฅผ ์˜์กด์„ฑ์— ์ถ”๊ฐ€ํ•˜์—ฌ ์ตœ์‹  ์ฝœ๋ฐฑ ์ฐธ์กฐ // ํ™”๋ฉด ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ useEffect(() => { if (modalState.isOpen && modalState.screenId) { loadScreenData(modalState.screenId); // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ (groupByColumns๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ) if (modalState.groupByColumns && modalState.groupByColumns.length > 0 && modalState.tableName) { loadGroupData(); } } }, [modalState.isOpen, modalState.screenId]); // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ํ•จ์ˆ˜ const loadGroupData = async () => { if (!modalState.tableName || !modalState.groupByColumns || modalState.groupByColumns.length === 0) { console.warn("ํ…Œ์ด๋ธ”๋ช… ๋˜๋Š” ๊ทธ๋ฃนํ•‘ ์ปฌ๋Ÿผ์ด ์—†์Šต๋‹ˆ๋‹ค."); return; } try { console.log("๐Ÿ” ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ์‹œ์ž‘:", { tableName: modalState.tableName, groupByColumns: modalState.groupByColumns, editData: modalState.editData, }); // ๊ทธ๋ฃนํ•‘ ์ปฌ๋Ÿผ ๊ฐ’ ์ถ”์ถœ (์˜ˆ: order_no = "ORD-20251124-001") const groupValues: Record = {}; modalState.groupByColumns.forEach((column) => { if (modalState.editData[column]) { groupValues[column] = modalState.editData[column]; } }); if (Object.keys(groupValues).length === 0) { console.warn("๊ทธ๋ฃนํ•‘ ์ปฌ๋Ÿผ ๊ฐ’์ด ์—†์Šต๋‹ˆ๋‹ค:", modalState.groupByColumns); return; } console.log("๐Ÿ” ๊ทธ๋ฃน ์กฐํšŒ ์š”์ฒญ:", { tableName: modalState.tableName, groupValues, }); // ๊ฐ™์€ ๊ทธ๋ฃน์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ ์กฐํšŒ (entityJoinApi ์‚ฌ์šฉ) const { entityJoinApi } = await import("@/lib/api/entityJoin"); const response = await entityJoinApi.getTableDataWithJoins(modalState.tableName, { page: 1, size: 1000, search: groupValues, // search ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ (๋ฐฑ์—”๋“œ์—์„œ WHERE ์กฐ๊ฑด์œผ๋กœ ์ฒ˜๋ฆฌ) enableEntityJoin: true, }); console.log("๐Ÿ” ๊ทธ๋ฃน ์กฐํšŒ ์‘๋‹ต:", response); // entityJoinApi๋Š” ๋ฐฐ์—ด ๋˜๋Š” { data: [] } ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜ const dataArray = Array.isArray(response) ? response : response?.data || []; if (dataArray.length > 0) { console.log("โœ… ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ์„ฑ๊ณต:", dataArray); setGroupData(dataArray); setOriginalGroupData(JSON.parse(JSON.stringify(dataArray))); // Deep copy toast.info(`${dataArray.length}๊ฐœ์˜ ๊ด€๋ จ ํ’ˆ๋ชฉ์„ ๋ถˆ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.`); } else { console.warn("๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค:", response); setGroupData([modalState.editData]); // ๊ธฐ๋ณธ๊ฐ’: ์„ ํƒ๋œ ํ–‰๋งŒ setOriginalGroupData([JSON.parse(JSON.stringify(modalState.editData))]); } } catch (error: any) { console.error("โŒ ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ์˜ค๋ฅ˜:", error); toast.error("๊ด€๋ จ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."); setGroupData([modalState.editData]); // ๊ธฐ๋ณธ๊ฐ’: ์„ ํƒ๋œ ํ–‰๋งŒ setOriginalGroupData([JSON.parse(JSON.stringify(modalState.editData))]); } }; const loadScreenData = async (screenId: number) => { try { setLoading(true); console.log("ํ™”๋ฉด ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์‹œ์ž‘:", screenId); // ํ™”๋ฉด ์ •๋ณด์™€ ๋ ˆ์ด์•„์›ƒ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ const [screenInfo, layoutData] = await Promise.all([ screenApi.getScreen(screenId), screenApi.getLayout(screenId), ]); console.log("API ์‘๋‹ต:", { screenInfo, layoutData }); if (screenInfo && layoutData) { const components = layoutData.components || []; // ํ™”๋ฉด์˜ ์‹ค์ œ ํฌ๊ธฐ ๊ณ„์‚ฐ const dimensions = calculateScreenDimensions(components); setScreenDimensions(dimensions); setScreenData({ components, screenInfo: screenInfo, }); console.log("ํ™”๋ฉด ๋ฐ์ดํ„ฐ ์„ค์ • ์™„๋ฃŒ:", { componentsCount: components.length, dimensions, screenInfo, }); } else { throw new Error("ํ™”๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค"); } } catch (error) { console.error("ํ™”๋ฉด ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์˜ค๋ฅ˜:", error); toast.error("ํ™”๋ฉด์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."); handleClose(); } finally { setLoading(false); } }; const handleClose = () => { setModalState({ isOpen: false, screenId: null, title: "", description: "", modalSize: "md", editData: {}, onSave: undefined, groupByColumns: undefined, tableName: undefined, }); setScreenData(null); setFormData({}); setOriginalData({}); setGroupData([]); // ๐Ÿ†• setOriginalGroupData([]); // ๐Ÿ†• }; // ์ €์žฅ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ - UPDATE ์•ก์…˜ ์‹คํ–‰ const handleSave = async () => { if (!screenData?.screenInfo?.tableName) { toast.error("ํ…Œ์ด๋ธ” ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค."); return; } try { // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ: ๋ชจ๋“  ํ’ˆ๋ชฉ ์ผ๊ด„ ์ฒ˜๋ฆฌ (์ถ”๊ฐ€/์ˆ˜์ •/์‚ญ์ œ) if (groupData.length > 0 || originalGroupData.length > 0) { console.log("๐Ÿ”„ ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์ผ๊ด„ ์ฒ˜๋ฆฌ ์‹œ์ž‘:", { groupDataLength: groupData.length, originalGroupDataLength: originalGroupData.length, groupData, originalGroupData, tableName: screenData.screenInfo.tableName, screenId: modalState.screenId, }); let insertedCount = 0; let updatedCount = 0; let deletedCount = 0; // 1๏ธโƒฃ ์‹ ๊ทœ ํ’ˆ๋ชฉ ์ถ”๊ฐ€ (id๊ฐ€ ์—†๋Š” ํ•ญ๋ชฉ) for (const currentData of groupData) { if (!currentData.id) { console.log("โž• ์‹ ๊ทœ ํ’ˆ๋ชฉ ์ถ”๊ฐ€:", currentData); console.log("๐Ÿ“‹ [์‹ ๊ทœ ํ’ˆ๋ชฉ] currentData ํ‚ค ๋ชฉ๋ก:", Object.keys(currentData)); // ๐Ÿ†• ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จ (id ์ œ์™ธ) const insertData: Record = { ...currentData }; console.log("๐Ÿ“ฆ [์‹ ๊ทœ ํ’ˆ๋ชฉ] ๋ณต์‚ฌ ์งํ›„ insertData:", insertData); console.log("๐Ÿ“‹ [์‹ ๊ทœ ํ’ˆ๋ชฉ] insertData ํ‚ค ๋ชฉ๋ก:", Object.keys(insertData)); delete insertData.id; // id๋Š” ์ž๋™ ์ƒ์„ฑ๋˜๋ฏ€๋กœ ์ œ๊ฑฐ // ๐Ÿ†• groupByColumns์˜ ๊ฐ’์„ ๊ฐ•์ œ๋กœ ํฌํ•จ (order_no ๋“ฑ) if (modalState.groupByColumns && modalState.groupByColumns.length > 0) { modalState.groupByColumns.forEach((colName) => { // ๊ธฐ์กด ํ’ˆ๋ชฉ(originalGroupData[0])์—์„œ groupByColumns ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ const referenceData = originalGroupData[0] || groupData.find((item) => item.id); if (referenceData && referenceData[colName]) { insertData[colName] = referenceData[colName]; console.log(`๐Ÿ”‘ [์‹ ๊ทœ ํ’ˆ๋ชฉ] ${colName} ๊ฐ’ ์ถ”๊ฐ€:`, referenceData[colName]); } }); } // ๐Ÿ†• ๊ณตํ†ต ํ•„๋“œ ์ถ”๊ฐ€ (๊ฑฐ๋ž˜์ฒ˜, ๋‹ด๋‹น์ž, ๋‚ฉํ’ˆ์ฒ˜, ๋ฉ”๋ชจ ๋“ฑ) // formData์—์„œ ํ’ˆ๋ชฉ๋ณ„ ํ•„๋“œ๊ฐ€ ์•„๋‹Œ ๊ณตํ†ต ํ•„๋“œ๋ฅผ ๋ณต์‚ฌ const commonFields = [ 'partner_id', // ๊ฑฐ๋ž˜์ฒ˜ 'manager_id', // ๋‹ด๋‹น์ž 'delivery_partner_id', // ๋‚ฉํ’ˆ์ฒ˜ 'delivery_address', // ๋‚ฉํ’ˆ์žฅ์†Œ 'memo', // ๋ฉ”๋ชจ 'order_date', // ์ฃผ๋ฌธ์ผ 'due_date', // ๋‚ฉ๊ธฐ์ผ 'shipping_method', // ๋ฐฐ์†ก๋ฐฉ๋ฒ• 'status', // ์ƒํƒœ 'sales_type', // ์˜์—…์œ ํ˜• ]; commonFields.forEach((fieldName) => { // formData์— ๊ฐ’์ด ์žˆ์œผ๋ฉด ์ถ”๊ฐ€ if (formData[fieldName] !== undefined && formData[fieldName] !== null) { insertData[fieldName] = formData[fieldName]; console.log(`๐Ÿ”— [๊ณตํ†ต ํ•„๋“œ] ${fieldName} ๊ฐ’ ์ถ”๊ฐ€:`, formData[fieldName]); } }); console.log("๐Ÿ“ฆ [์‹ ๊ทœ ํ’ˆ๋ชฉ] ์ตœ์ข… insertData:", insertData); console.log("๐Ÿ“‹ [์‹ ๊ทœ ํ’ˆ๋ชฉ] ์ตœ์ข… insertData ํ‚ค ๋ชฉ๋ก:", Object.keys(insertData)); try { const response = await dynamicFormApi.saveFormData({ screenId: modalState.screenId || 0, tableName: screenData.screenInfo.tableName, data: insertData, }); if (response.success) { insertedCount++; console.log("โœ… ์‹ ๊ทœ ํ’ˆ๋ชฉ ์ถ”๊ฐ€ ์„ฑ๊ณต:", response.data); } else { console.error("โŒ ์‹ ๊ทœ ํ’ˆ๋ชฉ ์ถ”๊ฐ€ ์‹คํŒจ:", response.message); } } catch (error: any) { console.error("โŒ ์‹ ๊ทœ ํ’ˆ๋ชฉ ์ถ”๊ฐ€ ์˜ค๋ฅ˜:", error); } } } // 2๏ธโƒฃ ๊ธฐ์กด ํ’ˆ๋ชฉ ์ˆ˜์ • (id๊ฐ€ ์žˆ๋Š” ํ•ญ๋ชฉ) for (const currentData of groupData) { if (currentData.id) { // id ๊ธฐ๋ฐ˜ ๋งค์นญ (์ธ๋ฑ์Šค ๊ธฐ๋ฐ˜ X) const originalItemData = originalGroupData.find( (orig) => orig.id === currentData.id ); if (!originalItemData) { console.warn(`์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค (id: ${currentData.id})`); continue; } // ๐Ÿ†• ๊ฐ’ ์ •๊ทœํ™” ํ•จ์ˆ˜ (ํƒ€์ž… ํ†ต์ผ) const normalizeValue = (val: any): any => { if (val === null || val === undefined || val === "") return null; if (typeof val === "string" && !isNaN(Number(val))) { // ์ˆซ์ž๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž์—ด์€ ์ˆซ์ž๋กœ return Number(val); } return val; }; // ๋ณ€๊ฒฝ๋œ ํ•„๋“œ๋งŒ ์ถ”์ถœ (id ์ œ์™ธ) const changedData: Record = {}; Object.keys(currentData).forEach((key) => { // id๋Š” ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€ if (key === "id") { return; } // ๐Ÿ†• ํƒ€์ž… ์ •๊ทœํ™” ํ›„ ๋น„๊ต const currentValue = normalizeValue(currentData[key]); const originalValue = normalizeValue(originalItemData[key]); // ๊ฐ’์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ๋งŒ ํฌํ•จ if (currentValue !== originalValue) { console.log(`๐Ÿ” [ํ’ˆ๋ชฉ ์ˆ˜์ • ๊ฐ์ง€] ${key}: ${originalValue} โ†’ ${currentValue}`); changedData[key] = currentData[key]; // ์›๋ณธ ๊ฐ’ ์‚ฌ์šฉ (๋ฌธ์ž์—ด ๊ทธ๋Œ€๋กœ) } }); // ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์—†์œผ๋ฉด ์Šคํ‚ต if (Object.keys(changedData).length === 0) { console.log(`๋ณ€๊ฒฝ์‚ฌํ•ญ ์—†์Œ (id: ${currentData.id})`); continue; } // UPDATE ์‹คํ–‰ try { const response = await dynamicFormApi.updateFormDataPartial( currentData.id, originalItemData, changedData, screenData.screenInfo.tableName, ); if (response.success) { updatedCount++; console.log(`โœ… ํ’ˆ๋ชฉ ์ˆ˜์ • ์„ฑ๊ณต (id: ${currentData.id})`); } else { console.error(`โŒ ํ’ˆ๋ชฉ ์ˆ˜์ • ์‹คํŒจ (id: ${currentData.id}):`, response.message); } } catch (error: any) { console.error(`โŒ ํ’ˆ๋ชฉ ์ˆ˜์ • ์˜ค๋ฅ˜ (id: ${currentData.id}):`, error); } } } // 3๏ธโƒฃ ์‚ญ์ œ๋œ ํ’ˆ๋ชฉ ์ œ๊ฑฐ (์›๋ณธ์—๋Š” ์žˆ์ง€๋งŒ ํ˜„์žฌ ๋ฐ์ดํ„ฐ์—๋Š” ์—†๋Š” ํ•ญ๋ชฉ) const currentIds = new Set(groupData.map((item) => item.id).filter(Boolean)); const deletedItems = originalGroupData.filter( (orig) => orig.id && !currentIds.has(orig.id) ); for (const deletedItem of deletedItems) { console.log("๐Ÿ—‘๏ธ ํ’ˆ๋ชฉ ์‚ญ์ œ:", deletedItem); try { const response = await dynamicFormApi.deleteFormDataFromTable( deletedItem.id, screenData.screenInfo.tableName ); if (response.success) { deletedCount++; console.log(`โœ… ํ’ˆ๋ชฉ ์‚ญ์ œ ์„ฑ๊ณต (id: ${deletedItem.id})`); } else { console.error(`โŒ ํ’ˆ๋ชฉ ์‚ญ์ œ ์‹คํŒจ (id: ${deletedItem.id}):`, response.message); } } catch (error: any) { console.error(`โŒ ํ’ˆ๋ชฉ ์‚ญ์ œ ์˜ค๋ฅ˜ (id: ${deletedItem.id}):`, error); } } // ๊ฒฐ๊ณผ ๋ฉ”์‹œ์ง€ const messages: string[] = []; if (insertedCount > 0) messages.push(`${insertedCount}๊ฐœ ์ถ”๊ฐ€`); if (updatedCount > 0) messages.push(`${updatedCount}๊ฐœ ์ˆ˜์ •`); if (deletedCount > 0) messages.push(`${deletedCount}๊ฐœ ์‚ญ์ œ`); if (messages.length > 0) { toast.success(`ํ’ˆ๋ชฉ์ด ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค (${messages.join(", ")})`); // ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ onSave ์ฝœ๋ฐฑ ์‹คํ–‰ (ํ…Œ์ด๋ธ” ์ƒˆ๋กœ๊ณ ์นจ) if (modalState.onSave) { try { modalState.onSave(); } catch (callbackError) { console.error("โš ๏ธ onSave ์ฝœ๋ฐฑ ์—๋Ÿฌ:", callbackError); } } handleClose(); } else { toast.info("๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค."); handleClose(); } return; } // ๊ธฐ์กด ๋กœ์ง: ๋‹จ์ผ ๋ ˆ์ฝ”๋“œ ์ˆ˜์ • const changedData: Record = {}; Object.keys(formData).forEach((key) => { if (formData[key] !== originalData[key]) { changedData[key] = formData[key]; } }); if (Object.keys(changedData).length === 0) { toast.info("๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค."); handleClose(); return; } // ๊ธฐ๋ณธํ‚ค ํ™•์ธ (id ๋˜๋Š” ์ฒซ ๋ฒˆ์งธ ํ‚ค) const recordId = originalData.id || Object.values(originalData)[0]; // UPDATE ์•ก์…˜ ์‹คํ–‰ const response = await dynamicFormApi.updateFormDataPartial( recordId, originalData, changedData, screenData.screenInfo.tableName, ); if (response.success) { toast.success("๋ฐ์ดํ„ฐ๊ฐ€ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); // ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ onSave ์ฝœ๋ฐฑ ์‹คํ–‰ (ํ…Œ์ด๋ธ” ์ƒˆ๋กœ๊ณ ์นจ) if (modalState.onSave) { try { modalState.onSave(); } catch (callbackError) { console.error("โš ๏ธ onSave ์ฝœ๋ฐฑ ์—๋Ÿฌ:", callbackError); } } handleClose(); } else { throw new Error(response.message || "์ˆ˜์ •์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."); } } catch (error: any) { console.error("โŒ ์ˆ˜์ • ์‹คํŒจ:", error); toast.error(error.message || "๋ฐ์ดํ„ฐ ์ˆ˜์ • ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."); } }; // ๋ชจ๋‹ฌ ํฌ๊ธฐ ์„ค์ • - ํ™”๋ฉด๊ด€๋ฆฌ ์„ค์ • ํฌ๊ธฐ + ํ—ค๋” const getModalStyle = () => { if (!screenDimensions) { return { className: "w-fit min-w-[400px] max-w-4xl max-h-[90vh] overflow-hidden p-0", style: undefined, // undefined๋กœ ๋ณ€๊ฒฝ - defaultWidth/defaultHeight ์‚ฌ์šฉ }; } // ํ™”๋ฉด๊ด€๋ฆฌ์—์„œ ์„ค์ •ํ•œ ํฌ๊ธฐ = ์ปจํ…์ธ  ์˜์—ญ ํฌ๊ธฐ // ์‹ค์ œ ๋ชจ๋‹ฌ ํฌ๊ธฐ = ์ปจํ…์ธ  + ํ—ค๋” const headerHeight = 60; // DialogHeader const totalHeight = screenDimensions.height + headerHeight; return { className: "overflow-hidden p-0", style: { width: `${Math.min(screenDimensions.width, window.innerWidth * 0.98)}px`, height: `${Math.min(totalHeight, window.innerHeight * 0.95)}px`, maxWidth: "98vw", maxHeight: "95vh", }, }; }; const modalStyle = getModalStyle(); return (
{modalState.title || "๋ฐ์ดํ„ฐ ์ˆ˜์ •"} {modalState.description && !loading && ( {modalState.description} )} {loading && ( {loading ? "ํ™”๋ฉด์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค..." : ""} )}
{loading ? (

ํ™”๋ฉด์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...

) : screenData ? (
{/* ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ */} {groupData.length > 1 && (
{groupData.length}๊ฐœ์˜ ๊ด€๋ จ ํ’ˆ๋ชฉ์„ ํ•จ๊ป˜ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค
)} {screenData.components.map((component) => { // ์ปดํฌ๋„ŒํŠธ ์œ„์น˜๋ฅผ offset๋งŒํผ ์กฐ์ • const offsetX = screenDimensions?.offsetX || 0; const offsetY = screenDimensions?.offsetY || 0; const adjustedComponent = { ...component, position: { ...component.position, x: parseFloat(component.position?.x?.toString() || "0") - offsetX, y: parseFloat(component.position?.y?.toString() || "0") - offsetY, }, }; // ๐Ÿ” ๋””๋ฒ„๊น…: ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ์‹œ์ ์˜ groupData ํ™•์ธ if (component.id === screenData.components[0]?.id) { console.log("๐Ÿ” [EditModal] InteractiveScreenViewerDynamic props:", { componentId: component.id, groupDataLength: groupData.length, groupData: groupData, formData: groupData.length > 0 ? groupData[0] : formData, }); } return ( 0 ? groupData[0] : formData} onFormDataChange={(fieldName, value) => { // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ์ฒ˜๋ฆฌ if (groupData.length > 0) { // ModalRepeaterTable์˜ ๊ฒฝ์šฐ ๋ฐฐ์—ด ์ „์ฒด๋ฅผ ๋ฐ›์Œ if (Array.isArray(value)) { setGroupData(value); } else { // ์ผ๋ฐ˜ ํ•„๋“œ๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์— ๋™์ผํ•˜๊ฒŒ ์ ์šฉ setGroupData((prev) => prev.map((item) => ({ ...item, [fieldName]: value, })) ); } } else { setFormData((prev) => ({ ...prev, [fieldName]: value, })); } }} screenInfo={{ id: modalState.screenId!, tableName: screenData.screenInfo?.tableName, }} onSave={handleSave} isInModal={true} // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๋ฅผ ModalRepeaterTable์— ์ „๋‹ฌ groupedData={groupData.length > 0 ? groupData : undefined} // ๐Ÿ†• ์ˆ˜์ • ๋ชจ๋‹ฌ์—์„œ ์ฝ๊ธฐ ์ „์šฉ ํ•„๋“œ ์ง€์ • (์ˆ˜์ฃผ๋ฒˆํ˜ธ, ๊ฑฐ๋ž˜์ฒ˜) disabledFields={["order_no", "partner_id"]} /> ); })}
) : (

ํ™”๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

)}
); }; export default EditModal;