"use client"; import React, { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from "@/components/ui/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; // ๐Ÿ†• ํ…Œ์ด๋ธ”๋ช… (๊ทธ๋ฃน ์กฐํšŒ์šฉ) buttonConfig?: any; // ๐Ÿ†• ๋ฒ„ํŠผ ์„ค์ • (์ œ์–ด๋กœ์ง ์‹คํ–‰์šฉ) buttonContext?: any; // ๐Ÿ†• ๋ฒ„ํŠผ ์ปจํ…์ŠคํŠธ (screenId, userId ๋“ฑ) saveButtonConfig?: { enableDataflowControl?: boolean; dataflowConfig?: any; dataflowTiming?: string; }; // ๐Ÿ†• ๋ชจ๋‹ฌ ๋‚ด๋ถ€ ์ €์žฅ ๋ฒ„ํŠผ์˜ ์ œ์–ด๋กœ์ง ์„ค์ • } interface EditModalProps { className?: string; } /** * ๋ชจ๋‹ฌ ๋‚ด๋ถ€์—์„œ ์ €์žฅ ๋ฒ„ํŠผ ์ฐพ๊ธฐ (์žฌ๊ท€์ ์œผ๋กœ ํƒ์ƒ‰) * action.type์ด "save"์ธ button-primary ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ์Œ */ const findSaveButtonInComponents = (components: any[]): any | null => { if (!components || !Array.isArray(components)) return null; for (const comp of components) { // button-primary์ด๊ณ  action.type์ด save์ธ ๊ฒฝ์šฐ if ( comp.componentType === "button-primary" && comp.componentConfig?.action?.type === "save" ) { return comp; } // conditional-container์˜ sections ๋‚ด๋ถ€ ํƒ์ƒ‰ if (comp.componentType === "conditional-container" && comp.componentConfig?.sections) { for (const section of comp.componentConfig.sections) { if (section.screenId) { // ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ์˜ ๋‚ด๋ถ€ ํ™”๋ฉด์€ ๋ณ„๋„๋กœ ๋กœ๋“œํ•ด์•ผ ํ•จ // ์—ฌ๊ธฐ์„œ๋Š” null ๋ฐ˜ํ™˜ํ•˜๊ณ , loadSaveButtonConfig์—์„œ ์ฒ˜๋ฆฌ continue; } } } // ์ž์‹ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์žฌ๊ท€ ํƒ์ƒ‰ if (comp.children && Array.isArray(comp.children)) { const found = findSaveButtonInComponents(comp.children); if (found) return found; } } return null; }; 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, buttonConfig: undefined, buttonContext: undefined, saveButtonConfig: 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 ์ œ๊ฑฐ }; }; // ๐Ÿ†• ๋ชจ๋‹ฌ ๋‚ด๋ถ€ ์ €์žฅ ๋ฒ„ํŠผ์˜ ์ œ์–ด๋กœ์ง ์„ค์ • ์กฐํšŒ const loadSaveButtonConfig = async (targetScreenId: number): Promise<{ enableDataflowControl?: boolean; dataflowConfig?: any; dataflowTiming?: string; } | null> => { try { // 1. ๋Œ€์ƒ ํ™”๋ฉด์˜ ๋ ˆ์ด์•„์›ƒ ์กฐํšŒ const layoutData = await screenApi.getLayout(targetScreenId); if (!layoutData?.components) { console.log("[EditModal] ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ ์—†์Œ:", targetScreenId); return null; } // 2. ์ €์žฅ ๋ฒ„ํŠผ ์ฐพ๊ธฐ let saveButton = findSaveButtonInComponents(layoutData.components); // 3. conditional-container๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋‚ด๋ถ€ ํ™”๋ฉด๋„ ํƒ์ƒ‰ if (!saveButton) { for (const comp of layoutData.components) { if (comp.componentType === "conditional-container" && comp.componentConfig?.sections) { for (const section of comp.componentConfig.sections) { if (section.screenId) { try { const innerLayoutData = await screenApi.getLayout(section.screenId); saveButton = findSaveButtonInComponents(innerLayoutData?.components || []); if (saveButton) { // console.log("[EditModal] ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์—์„œ ์ €์žฅ ๋ฒ„ํŠผ ๋ฐœ๊ฒฌ:", { // sectionScreenId: section.screenId, // sectionLabel: section.label, // }); break; } } catch (innerError) { // console.warn("[EditModal] ๋‚ด๋ถ€ ํ™”๋ฉด ๋ ˆ์ด์•„์›ƒ ์กฐํšŒ ์‹คํŒจ:", section.screenId); } } } if (saveButton) break; } } } if (!saveButton) { // console.log("[EditModal] ์ €์žฅ ๋ฒ„ํŠผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ:", targetScreenId); return null; } // 4. webTypeConfig์—์„œ ์ œ์–ด๋กœ์ง ์„ค์ • ์ถ”์ถœ const webTypeConfig = saveButton.webTypeConfig; if (webTypeConfig?.enableDataflowControl) { const config = { enableDataflowControl: webTypeConfig.enableDataflowControl, dataflowConfig: webTypeConfig.dataflowConfig, dataflowTiming: webTypeConfig.dataflowConfig?.flowConfig?.executionTiming || "after", }; // console.log("[EditModal] ์ €์žฅ ๋ฒ„ํŠผ ์ œ์–ด๋กœ์ง ์„ค์ • ๋ฐœ๊ฒฌ:", config); return config; } // console.log("[EditModal] ์ €์žฅ ๋ฒ„ํŠผ์— ์ œ์–ด๋กœ์ง ์„ค์ • ์—†์Œ"); return null; } catch (error) { // console.warn("[EditModal] ์ €์žฅ ๋ฒ„ํŠผ ์„ค์ • ์กฐํšŒ ์‹คํŒจ:", error); return null; } }; // ์ „์—ญ ๋ชจ๋‹ฌ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ useEffect(() => { const handleOpenEditModal = async (event: CustomEvent) => { const { screenId, title, description, modalSize, editData, onSave, groupByColumns, tableName, isCreateMode, buttonConfig, buttonContext } = event.detail; // ๐Ÿ†• ๋ชจ๋‹ฌ ๋‚ด๋ถ€ ์ €์žฅ ๋ฒ„ํŠผ์˜ ์ œ์–ด๋กœ์ง ์„ค์ • ์กฐํšŒ let saveButtonConfig: EditModalState["saveButtonConfig"] = undefined; if (screenId) { const config = await loadSaveButtonConfig(screenId); if (config) { saveButtonConfig = config; } } setModalState({ isOpen: true, screenId, title, description: description || "", modalSize: modalSize || "lg", editData: editData || {}, onSave, groupByColumns, // ๐Ÿ†• ๊ทธ๋ฃนํ•‘ ์ปฌ๋Ÿผ tableName, // ๐Ÿ†• ํ…Œ์ด๋ธ”๋ช… buttonConfig, // ๐Ÿ†• ๋ฒ„ํŠผ ์„ค์ • buttonContext, // ๐Ÿ†• ๋ฒ„ํŠผ ์ปจํ…์ŠคํŠธ saveButtonConfig, // ๐Ÿ†• ๋ชจ๋‹ฌ ๋‚ด๋ถ€ ์ €์žฅ ๋ฒ„ํŠผ์˜ ์ œ์–ด๋กœ์ง ์„ค์ • }); // ํŽธ์ง‘ ๋ฐ์ดํ„ฐ๋กœ ํผ ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™” setFormData(editData || {}); // ๐Ÿ†• isCreateMode๊ฐ€ true์ด๋ฉด originalData๋ฅผ ๋นˆ ๊ฐ์ฒด๋กœ ์„ค์ • (INSERT ๋ชจ๋“œ) // originalData๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด INSERT, ์žˆ์œผ๋ฉด UPDATE๋กœ ์ฒ˜๋ฆฌ๋จ setOriginalData(isCreateMode ? {} : editData || {}); if (isCreateMode) { console.log("[EditModal] ์ƒ์„ฑ ๋ชจ๋“œ๋กœ ์—ด๋ฆผ, ์ดˆ๊ธฐ๊ฐ’:", 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, modalState.groupByColumns, modalState.tableName]); // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ํ•จ์ˆ˜ 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.length, "๊ฑด"); 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 (saveData?: any) => { // universal-form-modal ๋“ฑ์—์„œ ์ž์ฒด ์ €์žฅ ์™„๋ฃŒ ํ›„ ํ˜ธ์ถœ๋œ ๊ฒฝ์šฐ ์Šคํ‚ต if (saveData?._saveCompleted) { console.log("[EditModal] ์ž์ฒด ์ €์žฅ ์™„๋ฃŒ๋œ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ˜ธ์ถœ๋จ - ์ €์žฅ ์Šคํ‚ต"); // ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ onSave ์ฝœ๋ฐฑ ์‹คํ–‰ (ํ…Œ์ด๋ธ” ์ƒˆ๋กœ๊ณ ์นจ) if (modalState.onSave) { try { modalState.onSave(); } catch (callbackError) { console.error("onSave ์ฝœ๋ฐฑ ์—๋Ÿฌ:", callbackError); } } handleClose(); return; } 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, }); // ๐Ÿ†• ๋‚ ์งœ ํ•„๋“œ ์ •๊ทœํ™” ํ•จ์ˆ˜ (YYYY-MM-DD ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜) const normalizeDateField = (value: any): string | null => { if (!value) return null; // ISO 8601 ํ˜•์‹ (2025-11-26T00:00:00.000Z) ๋˜๋Š” Date ๊ฐ์ฒด if (value instanceof Date || typeof value === "string") { try { const date = new Date(value); if (isNaN(date.getTime())) return null; // YYYY-MM-DD ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; } catch (error) { console.warn("๋‚ ์งœ ๋ณ€ํ™˜ ์‹คํŒจ:", value, error); return null; } } return null; }; // ๋‚ ์งœ ํ•„๋“œ ๋ชฉ๋ก const dateFields = ["item_due_date", "delivery_date", "due_date", "order_date"]; 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๋Š” ์ž๋™ ์ƒ์„ฑ๋˜๋ฏ€๋กœ ์ œ๊ฑฐ // ๐Ÿ†• ๋‚ ์งœ ํ•„๋“œ ์ •๊ทœํ™” (YYYY-MM-DD ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜) dateFields.forEach((fieldName) => { if (insertData[fieldName]) { const normalizedDate = normalizeDateField(insertData[fieldName]); if (normalizedDate) { insertData[fieldName] = normalizedDate; console.log(`๐Ÿ“… [๋‚ ์งœ ์ •๊ทœํ™”] ${fieldName}: ${currentData[fieldName]} โ†’ ${normalizedDate}`); } } }); // ๐Ÿ†• 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) { // ๋‚ ์งœ ํ•„๋“œ์ธ ๊ฒฝ์šฐ ์ •๊ทœํ™” if (dateFields.includes(fieldName)) { const normalizedDate = normalizeDateField(formData[fieldName]); if (normalizedDate) { insertData[fieldName] = normalizedDate; console.log(`๐Ÿ”— [๊ณตํ†ต ํ•„๋“œ - ๋‚ ์งœ] ${fieldName} ๊ฐ’ ์ถ”๊ฐ€:`, normalizedDate); } } else { 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, fieldName?: string): any => { if (val === null || val === undefined || val === "") return null; // ๋‚ ์งœ ํ•„๋“œ์ธ ๊ฒฝ์šฐ YYYY-MM-DD ํ˜•์‹์œผ๋กœ ์ •๊ทœํ™” if (fieldName && dateFields.includes(fieldName)) { const normalizedDate = normalizeDateField(val); return normalizedDate; } 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], key); const originalValue = normalizeValue(originalItemData[key], key); // ๊ฐ’์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ๋งŒ ํฌํ•จ if (currentValue !== originalValue) { console.log(`๐Ÿ” [ํ’ˆ๋ชฉ ์ˆ˜์ • ๊ฐ์ง€] ${key}: ${originalValue} โ†’ ${currentValue}`); // ๋‚ ์งœ ํ•„๋“œ๋Š” ์ •๊ทœํ™”๋œ ๊ฐ’ ์‚ฌ์šฉ, ๋‚˜๋จธ์ง€๋Š” ์›๋ณธ ๊ฐ’ ์‚ฌ์šฉ changedData[key] = dateFields.includes(key) ? currentValue : 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); } } // ๐Ÿ†• ์ €์žฅ ํ›„ ์ œ์–ด๋กœ์ง ์‹คํ–‰ (๋ฒ„ํŠผ์˜ After ํƒ€์ด๋ฐ ์ œ์–ด) // ์šฐ์„ ์ˆœ์œ„: ๋ชจ๋‹ฌ ๋‚ด๋ถ€ ์ €์žฅ ๋ฒ„ํŠผ ์„ค์ •(saveButtonConfig) > ์ˆ˜์ • ๋ฒ„ํŠผ์—์„œ ์ „๋‹ฌ๋ฐ›์€ ์„ค์ •(buttonConfig) try { const controlConfig = modalState.saveButtonConfig || modalState.buttonConfig; console.log("[EditModal] ๊ทธ๋ฃน ์ €์žฅ ์™„๋ฃŒ ํ›„ ์ œ์–ด๋กœ์ง ์‹คํ–‰ ์‹œ๋„", { hasSaveButtonConfig: !!modalState.saveButtonConfig, hasButtonConfig: !!modalState.buttonConfig, controlConfig, }); if (controlConfig?.enableDataflowControl && controlConfig?.dataflowTiming === "after") { console.log("๐ŸŽฏ [EditModal] ์ €์žฅ ํ›„ ์ œ์–ด๋กœ์ง ๋ฐœ๊ฒฌ:", controlConfig.dataflowConfig); // buttonActions์˜ executeAfterSaveControl ๋™์  import const { ButtonActionExecutor } = await import("@/lib/utils/buttonActions"); // ์ œ์–ด๋กœ์ง ์‹คํ–‰ await ButtonActionExecutor.executeAfterSaveControl( controlConfig, { formData: modalState.editData, screenId: modalState.buttonContext?.screenId || modalState.screenId, tableName: modalState.buttonContext?.tableName || screenData?.screenInfo?.tableName, userId: user?.userId, companyCode: user?.companyCode, onRefresh: modalState.onSave, } ); console.log("โœ… [EditModal] ์ œ์–ด๋กœ์ง ์‹คํ–‰ ์™„๋ฃŒ"); } else { console.log("โ„น๏ธ [EditModal] ์ €์žฅ ํ›„ ์‹คํ–‰ํ•  ์ œ์–ด๋กœ์ง ์—†์Œ"); } } catch (controlError) { console.error("โŒ [EditModal] ์ œ์–ด๋กœ์ง ์‹คํ–‰ ์˜ค๋ฅ˜:", controlError); // ์ œ์–ด๋กœ์ง ์˜ค๋ฅ˜๋Š” ์ €์žฅ ์„ฑ๊ณต์„ ๋ฐฉํ•ดํ•˜์ง€ ์•Š์Œ (๊ฒฝ๊ณ ๋งŒ ํ‘œ์‹œ) toast.warning("์ €์žฅ์€ ์™„๋ฃŒ๋˜์—ˆ์œผ๋‚˜ ์—ฐ๊ฒฐ๋œ ์ œ์–ด ์‹คํ–‰ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."); } handleClose(); } else { toast.info("๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค."); handleClose(); } return; } // originalData๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด INSERT, ์žˆ์œผ๋ฉด UPDATE const isCreateMode = Object.keys(originalData).length === 0; if (isCreateMode) { // INSERT ๋ชจ๋“œ console.log("[EditModal] INSERT ๋ชจ๋“œ - ์ƒˆ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ:", formData); const response = await dynamicFormApi.saveFormData({ screenId: modalState.screenId!, tableName: screenData.screenInfo.tableName, data: formData, }); if (response.success) { toast.success("๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); // ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ onSave ์ฝœ๋ฐฑ ์‹คํ–‰ (ํ…Œ์ด๋ธ” ์ƒˆ๋กœ๊ณ ์นจ) if (modalState.onSave) { try { modalState.onSave(); } catch (callbackError) { console.error("onSave ์ฝœ๋ฐฑ ์—๋Ÿฌ:", callbackError); } } // ๐Ÿ†• ์ €์žฅ ํ›„ ์ œ์–ด๋กœ์ง ์‹คํ–‰ (๋ฒ„ํŠผ์˜ After ํƒ€์ด๋ฐ ์ œ์–ด) // ์šฐ์„ ์ˆœ์œ„: ๋ชจ๋‹ฌ ๋‚ด๋ถ€ ์ €์žฅ ๋ฒ„ํŠผ ์„ค์ •(saveButtonConfig) > ์ˆ˜์ • ๋ฒ„ํŠผ์—์„œ ์ „๋‹ฌ๋ฐ›์€ ์„ค์ •(buttonConfig) try { const controlConfig = modalState.saveButtonConfig || modalState.buttonConfig; console.log("[EditModal] INSERT ์™„๋ฃŒ ํ›„ ์ œ์–ด๋กœ์ง ์‹คํ–‰ ์‹œ๋„", { controlConfig }); if (controlConfig?.enableDataflowControl && controlConfig?.dataflowTiming === "after") { console.log("๐ŸŽฏ [EditModal] ์ €์žฅ ํ›„ ์ œ์–ด๋กœ์ง ๋ฐœ๊ฒฌ:", controlConfig.dataflowConfig); const { ButtonActionExecutor } = await import("@/lib/utils/buttonActions"); await ButtonActionExecutor.executeAfterSaveControl( controlConfig, { formData, screenId: modalState.buttonContext?.screenId || modalState.screenId, tableName: modalState.buttonContext?.tableName || screenData?.screenInfo?.tableName, userId: user?.userId, companyCode: user?.companyCode, onRefresh: modalState.onSave, } ); console.log("โœ… [EditModal] ์ œ์–ด๋กœ์ง ์‹คํ–‰ ์™„๋ฃŒ"); } } catch (controlError) { console.error("โŒ [EditModal] ์ œ์–ด๋กœ์ง ์‹คํ–‰ ์˜ค๋ฅ˜:", controlError); toast.warning("์ €์žฅ์€ ์™„๋ฃŒ๋˜์—ˆ์œผ๋‚˜ ์—ฐ๊ฒฐ๋œ ์ œ์–ด ์‹คํ–‰ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."); } handleClose(); } else { throw new Error(response.message || "์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."); } } else { // UPDATE ๋ชจ๋“œ - ๊ธฐ์กด ๋กœ์ง 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); } } // ๐Ÿ†• ์ €์žฅ ํ›„ ์ œ์–ด๋กœ์ง ์‹คํ–‰ (๋ฒ„ํŠผ์˜ After ํƒ€์ด๋ฐ ์ œ์–ด) // ์šฐ์„ ์ˆœ์œ„: ๋ชจ๋‹ฌ ๋‚ด๋ถ€ ์ €์žฅ ๋ฒ„ํŠผ ์„ค์ •(saveButtonConfig) > ์ˆ˜์ • ๋ฒ„ํŠผ์—์„œ ์ „๋‹ฌ๋ฐ›์€ ์„ค์ •(buttonConfig) try { const controlConfig = modalState.saveButtonConfig || modalState.buttonConfig; console.log("[EditModal] UPDATE ์™„๋ฃŒ ํ›„ ์ œ์–ด๋กœ์ง ์‹คํ–‰ ์‹œ๋„", { controlConfig }); if (controlConfig?.enableDataflowControl && controlConfig?.dataflowTiming === "after") { console.log("๐ŸŽฏ [EditModal] ์ €์žฅ ํ›„ ์ œ์–ด๋กœ์ง ๋ฐœ๊ฒฌ:", controlConfig.dataflowConfig); const { ButtonActionExecutor } = await import("@/lib/utils/buttonActions"); await ButtonActionExecutor.executeAfterSaveControl( controlConfig, { formData, screenId: modalState.buttonContext?.screenId || modalState.screenId, tableName: modalState.buttonContext?.tableName || screenData?.screenInfo?.tableName, userId: user?.userId, companyCode: user?.companyCode, onRefresh: modalState.onSave, } ); console.log("โœ… [EditModal] ์ œ์–ด๋กœ์ง ์‹คํ–‰ ์™„๋ฃŒ"); } } catch (controlError) { console.error("โŒ [EditModal] ์ œ์–ด๋กœ์ง ์‹คํ–‰ ์˜ค๋ฅ˜:", controlError); toast.warning("์ €์žฅ์€ ์™„๋ฃŒ๋˜์—ˆ์œผ๋‚˜ ์—ฐ๊ฒฐ๋œ ์ œ์–ด ์‹คํ–‰ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."); } 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 ์‚ฌ์šฉ }; } // ํ™”๋ฉด๊ด€๋ฆฌ์—์„œ ์„ค์ •ํ•œ ํฌ๊ธฐ = ์ปจํ…์ธ  ์˜์—ญ ํฌ๊ธฐ // ์‹ค์ œ ๋ชจ๋‹ฌ ํฌ๊ธฐ = ์ปจํ…์ธ  + ํ—ค๋” + gap + padding + ๋ผ๋ฒจ ๊ณต๊ฐ„ const headerHeight = 52; // DialogHeader (ํƒ€์ดํ‹€ + border-b + py-3) const dialogGap = 16; // DialogContent gap-4 const extraPadding = 24; // ์ถ”๊ฐ€ ์—ฌ๋ฐฑ (์•ˆ์ „ ๋งˆ์ง„) const labelSpace = 30; // ์ž…๋ ฅ ํ•„๋“œ ์œ„ ๋ผ๋ฒจ ๊ณต๊ฐ„ (-top-6 = 24px + ์—ฌ์œ ) const totalHeight = screenDimensions.height + headerHeight + dialogGap + extraPadding + labelSpace; return { className: "overflow-hidden p-0", style: { width: `${Math.min(screenDimensions.width + 48, 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 ? (
{screenData.components.map((component) => { // ์ปดํฌ๋„ŒํŠธ ์œ„์น˜๋ฅผ offset๋งŒํผ ์กฐ์ • const offsetX = screenDimensions?.offsetX || 0; const offsetY = screenDimensions?.offsetY || 0; const labelSpace = 30; // ๋ผ๋ฒจ ๊ณต๊ฐ„ (์ž…๋ ฅ ํ•„๋“œ ์œ„ -top-6 ๋ผ๋ฒจ์šฉ) const adjustedComponent = { ...component, position: { ...component.position, x: parseFloat(component.position?.x?.toString() || "0") - offsetX, y: parseFloat(component.position?.y?.toString() || "0") - offsetY + labelSpace, // ๋ผ๋ฒจ ๊ณต๊ฐ„ ์ถ”๊ฐ€ }, }; const groupedDataProp = groupData.length > 0 ? groupData : undefined; // ๐Ÿ†• UniversalFormModal์ด ์žˆ๋Š”์ง€ ํ™•์ธ (์ž์ฒด ์ €์žฅ ๋กœ์ง ์‚ฌ์šฉ) // ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ ๋˜๋Š” ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€ ํ™”๋ฉด์— universal-form-modal์ด ์žˆ๋Š”์ง€ ํ™•์ธ const hasUniversalFormModal = screenData.components.some( (c) => { // ์ตœ์ƒ์œ„์— universal-form-modal์ด ์žˆ๋Š” ๊ฒฝ์šฐ if (c.componentType === "universal-form-modal") return true; // ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์— universal-form-modal์ด ์žˆ๋Š” ๊ฒฝ์šฐ // (์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์žˆ์œผ๋ฉด ๋‚ด๋ถ€ ํ™”๋ฉด์—์„œ universal-form-modal์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ€์ •) if (c.componentType === "conditional-container") return true; return false; } ); // ๐Ÿ”‘ ์ฒจ๋ถ€ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ–‰(๋ ˆ์ฝ”๋“œ) ๋‹จ์œ„๋กœ ํŒŒ์ผ์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก tableName ์ถ”๊ฐ€ const enrichedFormData = { ...(groupData.length > 0 ? groupData[0] : formData), tableName: screenData.screenInfo?.tableName, // ํ…Œ์ด๋ธ”๋ช… ์ถ”๊ฐ€ screenId: modalState.screenId, // ํ™”๋ฉด ID ์ถ”๊ฐ€ }; return ( { // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ์ฒ˜๋ฆฌ 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, }} // ๐Ÿ†• UniversalFormModal์ด ์žˆ์œผ๋ฉด onSave ์ „๋‹ฌ ์•ˆ ํ•จ (์ž์ฒด ์ €์žฅ ๋กœ์ง ์‚ฌ์šฉ) // ModalRepeaterTable๋งŒ ์žˆ์œผ๋ฉด ๊ธฐ์กด๋Œ€๋กœ onSave ์ „๋‹ฌ (ํ˜ธํ™˜์„ฑ ์œ ์ง€) onSave={hasUniversalFormModal ? undefined : handleSave} isInModal={true} // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๋ฅผ ModalRepeaterTable์— ์ „๋‹ฌ groupedData={groupedDataProp} // ๐Ÿ†• ์ˆ˜์ • ๋ชจ๋‹ฌ์—์„œ ์ฝ๊ธฐ ์ „์šฉ ํ•„๋“œ ์ง€์ • (์ˆ˜์ฃผ๋ฒˆํ˜ธ, ๊ฑฐ๋ž˜์ฒ˜) disabledFields={["order_no", "partner_id"]} /> ); })}
) : (

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

)}
); }; export default EditModal;