"use client"; import React, { useState, useRef, useEffect, useMemo } from "react"; import { ComponentRendererProps } from "@/types/component"; import { ButtonPrimaryConfig } from "./types"; import { ButtonActionExecutor, ButtonActionContext, ButtonActionType, DEFAULT_BUTTON_ACTIONS, } from "@/lib/utils/buttonActions"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { toast } from "sonner"; import { filterDOMProps } from "@/lib/utils/domPropsFilter"; import { useCurrentFlowStep } from "@/stores/flowStepStore"; import { useScreenPreview } from "@/contexts/ScreenPreviewContext"; import { useScreenContextOptional } from "@/contexts/ScreenContext"; import { useSplitPanelContext, SplitPanelPosition } from "@/contexts/SplitPanelContext"; import { applyMappingRules } from "@/lib/utils/dataMapping"; export interface ButtonPrimaryComponentProps extends ComponentRendererProps { config?: ButtonPrimaryConfig; // ์ถ”๊ฐ€ props screenId?: number; tableName?: string; userId?: string; // ๐Ÿ†• ํ˜„์žฌ ์‚ฌ์šฉ์ž ID userName?: string; // ๐Ÿ†• ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ด๋ฆ„ companyCode?: string; // ๐Ÿ†• ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ํšŒ์‚ฌ ์ฝ”๋“œ onRefresh?: () => void; onClose?: () => void; onFlowRefresh?: () => void; onSave?: () => Promise; // ๐Ÿ†• EditModal์˜ handleSave ์ฝœ๋ฐฑ // ํผ ๋ฐ์ดํ„ฐ ๊ด€๋ จ originalData?: Record; // ๋ถ€๋ถ„ ์—…๋ฐ์ดํŠธ์šฉ ์›๋ณธ ๋ฐ์ดํ„ฐ // ํ…Œ์ด๋ธ” ์„ ํƒ๋œ ํ–‰ ์ •๋ณด (๋‹ค์ค‘ ์„ ํƒ ์•ก์…˜์šฉ) selectedRows?: any[]; selectedRowsData?: any[]; // ํ…Œ์ด๋ธ” ์ •๋ ฌ ์ •๋ณด (์—‘์…€ ๋‹ค์šด๋กœ๋“œ์šฉ) sortBy?: string; sortOrder?: "asc" | "desc"; columnOrder?: string[]; tableDisplayData?: any[]; // ํ™”๋ฉด์— ํ‘œ์‹œ๋œ ๋ฐ์ดํ„ฐ (์ปฌ๋Ÿผ ์ˆœ์„œ ํฌํ•จ) // ํ”Œ๋กœ์šฐ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ ์ •๋ณด (ํ”Œ๋กœ์šฐ ์œ„์ ฏ ์„ ํƒ ์•ก์…˜์šฉ) flowSelectedData?: any[]; flowSelectedStepId?: number | null; // ๐Ÿ†• ๊ฐ™์€ ํ™”๋ฉด์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ (TableList ์ž๋™ ๊ฐ์ง€์šฉ) allComponents?: any[]; } /** * ButtonPrimary ์ปดํฌ๋„ŒํŠธ * button-primary ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค */ export const ButtonPrimaryComponent: React.FC = ({ component, isDesignMode = false, isSelected = false, isInteractive = false, onClick, onDragStart, onDragEnd, config, className, style, formData, originalData, onFormDataChange, screenId, tableName, userId, // ๐Ÿ†• ์‚ฌ์šฉ์ž ID userName, // ๐Ÿ†• ์‚ฌ์šฉ์ž ์ด๋ฆ„ companyCode, // ๐Ÿ†• ํšŒ์‚ฌ ์ฝ”๋“œ onRefresh, onClose, onFlowRefresh, onSave, // ๐Ÿ†• EditModal์˜ handleSave ์ฝœ๋ฐฑ sortBy, // ๐Ÿ†• ์ •๋ ฌ ์ปฌ๋Ÿผ sortOrder, // ๐Ÿ†• ์ •๋ ฌ ๋ฐฉํ–ฅ columnOrder, // ๐Ÿ†• ์ปฌ๋Ÿผ ์ˆœ์„œ tableDisplayData, // ๐Ÿ†• ํ™”๋ฉด์— ํ‘œ์‹œ๋œ ๋ฐ์ดํ„ฐ selectedRows, selectedRowsData, flowSelectedData, flowSelectedStepId, allComponents, // ๐Ÿ†• ๊ฐ™์€ ํ™”๋ฉด์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ...props }) => { const { isPreviewMode } = useScreenPreview(); // ํ”„๋ฆฌ๋ทฐ ๋ชจ๋“œ ํ™•์ธ const screenContext = useScreenContextOptional(); // ํ™”๋ฉด ์ปจํ…์ŠคํŠธ const splitPanelContext = useSplitPanelContext(); // ๋ถ„ํ•  ํŒจ๋„ ์ปจํ…์ŠคํŠธ // ๐Ÿ†• ScreenContext์—์„œ splitPanelPosition ๊ฐ€์ ธ์˜ค๊ธฐ (์ค‘์ฒฉ ํ™”๋ฉด์—์„œ๋„ ์ž‘๋™) const splitPanelPosition = screenContext?.splitPanelPosition; // ๐Ÿ†• tableName์ด props๋กœ ์ „๋‹ฌ๋˜์ง€ ์•Š์œผ๋ฉด ScreenContext์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ const effectiveTableName = tableName || screenContext?.tableName; const effectiveScreenId = screenId || screenContext?.screenId; // ๐Ÿ†• props์—์„œ onSave ์ถ”์ถœ (๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ...props์—์„œ ์ถ”์ถœ) const propsOnSave = (props as any).onSave as (() => Promise) | undefined; const finalOnSave = onSave || propsOnSave; // ๐Ÿ†• ํ”Œ๋กœ์šฐ ๋‹จ๊ณ„๋ณ„ ํ‘œ์‹œ ์ œ์–ด const flowConfig = (component as any).webTypeConfig?.flowVisibilityConfig; const currentStep = useCurrentFlowStep(flowConfig?.targetFlowComponentId); // ๐Ÿ†• ๋ฒ„ํŠผ ํ‘œ์‹œ ์—ฌ๋ถ€ ๊ณ„์‚ฐ const shouldShowButton = useMemo(() => { // ํ”Œ๋กœ์šฐ ์ œ์–ด ๋น„ํ™œ์„ฑํ™” ์‹œ ํ•ญ์ƒ ํ‘œ์‹œ if (!flowConfig?.enabled) { return true; } // ํ”Œ๋กœ์šฐ ๋‹จ๊ณ„๊ฐ€ ์„ ํƒ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ if (currentStep === null) { // ๐Ÿ”ง ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋ชจ๋“œ์ผ ๋•Œ๋Š” ๋‹จ๊ณ„ ๋ฏธ์„ ํƒ ์‹œ ์ˆจ๊น€ if (flowConfig.mode === "whitelist") { return false; } // ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๋‚˜ all ๋ชจ๋“œ๋Š” ํ‘œ์‹œ return true; } const { mode, visibleSteps = [], hiddenSteps = [] } = flowConfig; let result = true; if (mode === "whitelist") { result = visibleSteps.includes(currentStep); } else if (mode === "blacklist") { result = !hiddenSteps.includes(currentStep); } else if (mode === "all") { result = true; } return result; }, [flowConfig, currentStep, component.id, component.label]); // ํ™•์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ ์ƒํƒœ const [showConfirmDialog, setShowConfirmDialog] = useState(false); const [pendingAction, setPendingAction] = useState<{ type: ButtonActionType; config: any; context: ButtonActionContext; } | null>(null); // ํ† ์ŠคํŠธ ์ •๋ฆฌ๋ฅผ ์œ„ํ•œ ref const currentLoadingToastRef = useRef(undefined); // ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ ํ† ์ŠคํŠธ ์ •๋ฆฌ useEffect(() => { return () => { if (currentLoadingToastRef.current !== undefined) { toast.dismiss(currentLoadingToastRef.current); currentLoadingToastRef.current = undefined; } }; }, []); // ์‚ญ์ œ ์•ก์…˜ ๊ฐ์ง€ ๋กœ์ง (์‹ค์ œ ํ•„๋“œ๋ช… ์‚ฌ์šฉ) const isDeleteAction = () => { const deleteKeywords = ["์‚ญ์ œ", "delete", "remove", "์ œ๊ฑฐ", "del"]; return ( component.componentConfig?.action?.type === "delete" || component.config?.action?.type === "delete" || component.webTypeConfig?.actionType === "delete" || component.text?.toLowerCase().includes("์‚ญ์ œ") || component.text?.toLowerCase().includes("delete") || component.label?.toLowerCase().includes("์‚ญ์ œ") || component.label?.toLowerCase().includes("delete") || deleteKeywords.some( (keyword) => component.config?.buttonText?.toLowerCase().includes(keyword) || component.config?.text?.toLowerCase().includes(keyword), ) ); }; // ์‚ญ์ œ ์•ก์…˜์ผ ๋•Œ ๋ผ๋ฒจ ์ƒ‰์ƒ ์ž๋™ ์„ค์ • useEffect(() => { if (isDeleteAction() && !component.style?.labelColor) { // ์‚ญ์ œ ์•ก์…˜์ด๊ณ  ๋ผ๋ฒจ ์ƒ‰์ƒ์ด ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋นจ๊ฐ„์ƒ‰์œผ๋กœ ์ž๋™ ์„ค์ • if (component.style) { component.style.labelColor = "#ef4444"; } else { component.style = { labelColor: "#ef4444" }; } } }, [component.componentConfig?.action?.type, component.config?.action?.type, component.webTypeConfig?.actionType]); // ์ปดํฌ๋„ŒํŠธ ์„ค์ • // ๐Ÿ”ฅ component.componentConfig๋„ ๋ณ‘ํ•ฉํ•ด์•ผ ํ•จ (ํ™”๋ฉด ๋””์ž์ด๋„ˆ์—์„œ ์ €์žฅ๋œ ์„ค์ •) const componentConfig = { ...config, ...component.config, ...component.componentConfig, // ๐Ÿ”ฅ ํ™”๋ฉด ๋””์ž์ด๋„ˆ์—์„œ ์ €์žฅ๋œ action ๋“ฑ ํฌํ•จ } as ButtonPrimaryConfig; // ๐ŸŽจ ๋™์  ์ƒ‰์ƒ ์„ค์ • (์†์„ฑํŽธ์ง‘ ๋ชจ๋‹ฌ์˜ "์ƒ‰์ƒ" ํ•„๋“œ์™€ ์—ฐ๋™) const getLabelColor = () => { if (isDeleteAction()) { return component.style?.labelColor || "#ef4444"; // ๋นจ๊ฐ„์ƒ‰ ๊ธฐ๋ณธ๊ฐ’ (Tailwind red-500) } return component.style?.labelColor || "#212121"; // ๊ฒ€์€์ƒ‰ ๊ธฐ๋ณธ๊ฐ’ (shadcn/ui primary) }; const buttonColor = getLabelColor(); // ์•ก์…˜ ์„ค์ • ์ฒ˜๋ฆฌ - DB์—์„œ ๋ฌธ์ž์—ด๋กœ ์ €์žฅ๋œ ์•ก์…˜์„ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ const processedConfig = { ...componentConfig }; if (componentConfig.action && typeof componentConfig.action === "string") { const actionType = componentConfig.action as ButtonActionType; processedConfig.action = { ...DEFAULT_BUTTON_ACTIONS[actionType], type: actionType, // ๐Ÿ”ฅ ์ œ์–ด๊ด€๋ฆฌ ์„ค์ • ์ถ”๊ฐ€ (webTypeConfig์—์„œ ๊ฐ€์ ธ์˜ด) enableDataflowControl: component.webTypeConfig?.enableDataflowControl, dataflowConfig: component.webTypeConfig?.dataflowConfig, }; } else if (componentConfig.action && typeof componentConfig.action === "object") { // ๐Ÿ”ฅ ์ด๋ฏธ ๊ฐ์ฒด์ธ ๊ฒฝ์šฐ์—๋„ ์ œ์–ด๊ด€๋ฆฌ ์„ค์ • ์ถ”๊ฐ€ processedConfig.action = { ...componentConfig.action, enableDataflowControl: component.webTypeConfig?.enableDataflowControl, dataflowConfig: component.webTypeConfig?.dataflowConfig, }; } // ์Šคํƒ€์ผ ๊ณ„์‚ฐ // height: 100%๋กœ ๋ถ€๋ชจ(RealtimePreviewDynamic์˜ ๋‚ด๋ถ€ div)์˜ ๋†’์ด๋ฅผ ๋”ฐ๋ผ๊ฐ // width๋Š” ํ•ญ์ƒ 100%๋กœ ๊ณ ์ • (๋ถ€๋ชจ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ gridColumns๋กœ ํฌ๊ธฐ ์ œ์–ด) const componentStyle: React.CSSProperties = { ...component.style, ...style, width: "100%", height: "100%", }; // ๋””์ž์ธ ๋ชจ๋“œ ์Šคํƒ€์ผ (border ์†์„ฑ ๋ถ„๋ฆฌํ•˜์—ฌ ์ถฉ๋Œ ๋ฐฉ์ง€) if (isDesignMode) { componentStyle.borderWidth = "1px"; componentStyle.borderStyle = "dashed"; componentStyle.borderColor = isSelected ? "#3b82f6" : "#cbd5e1"; } // ํ™•์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ๊ฐ€ ํ•„์š”ํ•œ ์•ก์…˜ ํƒ€์ž…๋“ค const confirmationRequiredActions: ButtonActionType[] = ["save", "delete"]; // ์‹ค์ œ ์•ก์…˜ ์‹คํ–‰ ํ•จ์ˆ˜ const executeAction = async (actionConfig: any, context: ButtonActionContext) => { try { // ๊ธฐ์กด ํ† ์ŠคํŠธ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋จผ์ € ์ œ๊ฑฐ if (currentLoadingToastRef.current !== undefined) { toast.dismiss(currentLoadingToastRef.current); currentLoadingToastRef.current = undefined; } // ์ถ”๊ฐ€ ์•ˆ์ „์žฅ์น˜: ๋ชจ๋“  ๋กœ๋”ฉ ํ† ์ŠคํŠธ ์ œ๊ฑฐ toast.dismiss(); // UI ์ „ํ™˜ ์•ก์…˜ ๋ฐ ๋ชจ๋‹ฌ ์•ก์…˜์€ ๋กœ๋”ฉ ํ† ์ŠคํŠธ ํ‘œ์‹œํ•˜์ง€ ์•Š์Œ const silentActions = ["edit", "modal", "navigate", "excel_upload", "barcode_scan"]; if (!silentActions.includes(actionConfig.type)) { currentLoadingToastRef.current = toast.loading( actionConfig.type === "save" ? "์ €์žฅ ์ค‘..." : actionConfig.type === "delete" ? "์‚ญ์ œ ์ค‘..." : actionConfig.type === "submit" ? "์ œ์ถœ ์ค‘..." : "์ฒ˜๋ฆฌ ์ค‘...", { duration: Infinity, // ๋ช…์‹œ์ ์œผ๋กœ ๋ฌดํ•œ๋Œ€๋กœ ์„ค์ • }, ); } const success = await ButtonActionExecutor.executeAction(actionConfig, context); // ๋กœ๋”ฉ ํ† ์ŠคํŠธ ์ œ๊ฑฐ (์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ) if (currentLoadingToastRef.current !== undefined) { toast.dismiss(currentLoadingToastRef.current); currentLoadingToastRef.current = undefined; } // ์‹คํŒจํ•œ ๊ฒฝ์šฐ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ if (!success) { // UI ์ „ํ™˜ ์•ก์…˜ ๋ฐ ๋ชจ๋‹ฌ ์•ก์…˜์€ ์—๋Ÿฌ๋„ ์กฐ์šฉํžˆ ์ฒ˜๋ฆฌ (๋ชจ๋‹ฌ ๋‚ด๋ถ€์—์„œ ์ž์ฒด ์—๋Ÿฌ ํ‘œ์‹œ) const silentErrorActions = ["edit", "modal", "navigate", "excel_upload", "barcode_scan"]; if (silentErrorActions.includes(actionConfig.type)) { return; } // ๊ธฐ๋ณธ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๊ฒฐ์ • const defaultErrorMessage = actionConfig.type === "save" ? "์ €์žฅ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค." : actionConfig.type === "delete" ? "์‚ญ์ œ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค." : actionConfig.type === "submit" ? "์ œ์ถœ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค." : "์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."; // ์ปค์Šคํ…€ ๋ฉ”์‹œ์ง€ ์‚ฌ์šฉ ์กฐ๊ฑด: // 1. ์ปค์Šคํ…€ ๋ฉ”์‹œ์ง€๊ฐ€ ์žˆ๊ณ  // 2. (์•ก์…˜ ํƒ€์ž…์ด save์ด๊ฑฐ๋‚˜ OR ๋ฉ”์‹œ์ง€์— "์ €์žฅ"์ด ํฌํ•จ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ) const useCustomMessage = actionConfig.errorMessage && (actionConfig.type === "save" || !actionConfig.errorMessage.includes("์ €์žฅ")); const errorMessage = useCustomMessage ? actionConfig.errorMessage : defaultErrorMessage; toast.error(errorMessage); return; } // ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ์—๋งŒ ์„ฑ๊ณต ํ† ์ŠคํŠธ ํ‘œ์‹œ // edit, modal, navigate, excel_upload, barcode_scan ์•ก์…˜์€ ์กฐ์šฉํžˆ ์ฒ˜๋ฆฌ // (UI ์ „ํ™˜๋งŒ ํ•˜๊ฑฐ๋‚˜ ๋ชจ๋‹ฌ ๋‚ด๋ถ€์—์„œ ์ž์ฒด์ ์œผ๋กœ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ) const silentSuccessActions = ["edit", "modal", "navigate", "excel_upload", "barcode_scan"]; if (!silentSuccessActions.includes(actionConfig.type)) { // ๊ธฐ๋ณธ ์„ฑ๊ณต ๋ฉ”์‹œ์ง€ ๊ฒฐ์ • const defaultSuccessMessage = actionConfig.type === "save" ? "์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค." : actionConfig.type === "delete" ? "์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค." : actionConfig.type === "submit" ? "์ œ์ถœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค." : "์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."; // ์ปค์Šคํ…€ ๋ฉ”์‹œ์ง€ ์‚ฌ์šฉ ์กฐ๊ฑด: // 1. ์ปค์Šคํ…€ ๋ฉ”์‹œ์ง€๊ฐ€ ์žˆ๊ณ  // 2. (์•ก์…˜ ํƒ€์ž…์ด save์ด๊ฑฐ๋‚˜ OR ๋ฉ”์‹œ์ง€์— "์ €์žฅ"์ด ํฌํ•จ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ) const useCustomMessage = actionConfig.successMessage && (actionConfig.type === "save" || !actionConfig.successMessage.includes("์ €์žฅ")); const successMessage = useCustomMessage ? actionConfig.successMessage : defaultSuccessMessage; toast.success(successMessage); } // ์ €์žฅ/์ˆ˜์ • ์„ฑ๊ณต ์‹œ ์ž๋™ ์ฒ˜๋ฆฌ if (actionConfig.type === "save" || actionConfig.type === "edit") { if (typeof window !== "undefined") { // 1. ํ…Œ์ด๋ธ” ์ƒˆ๋กœ๊ณ ์นจ ์ด๋ฒคํŠธ ๋จผ์ € ๋ฐœ์†ก (๋ชจ๋‹ฌ์ด ๋‹ซํžˆ๊ธฐ ์ „์—) window.dispatchEvent(new CustomEvent("refreshTable")); // 2. ๋ชจ๋‹ฌ ๋‹ซ๊ธฐ (์•ฝ๊ฐ„์˜ ๋”œ๋ ˆ์ด) setTimeout(() => { // EditModal ๋‚ด๋ถ€์ธ์ง€ ํ™•์ธ (isInModal prop ์‚ฌ์šฉ) const isInEditModal = (props as any).isInModal; if (isInEditModal) { window.dispatchEvent(new CustomEvent("closeEditModal")); } // ScreenModal์€ ์—ฐ์† ๋“ฑ๋ก ๋ชจ๋“œ๋ฅผ ์ง€์›ํ•˜๋ฏ€๋กœ saveSuccessInModal ์ด๋ฒคํŠธ ๋ฐœ์ƒ window.dispatchEvent(new CustomEvent("saveSuccessInModal")); }, 100); } } } catch (error) { // ๋กœ๋”ฉ ํ† ์ŠคํŠธ ์ œ๊ฑฐ if (currentLoadingToastRef.current !== undefined) { toast.dismiss(currentLoadingToastRef.current); currentLoadingToastRef.current = undefined; } console.error("โŒ ๋ฒ„ํŠผ ์•ก์…˜ ์‹คํ–‰ ์˜ค๋ฅ˜:", error); // ์˜ค๋ฅ˜ ํ† ์ŠคํŠธ๋Š” buttonActions.ts์—์„œ ์ด๋ฏธ ํ‘œ์‹œ๋˜๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ๋Š” ์ œ๊ฑฐ // (์ค‘๋ณต ํ† ์ŠคํŠธ ๋ฐฉ์ง€) } }; // ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ /** * transferData ์•ก์…˜ ์ฒ˜๋ฆฌ */ const handleTransferDataAction = async (actionConfig: any) => { const dataTransferConfig = actionConfig.dataTransfer; if (!dataTransferConfig) { toast.error("๋ฐ์ดํ„ฐ ์ „๋‹ฌ ์„ค์ •์ด ์—†์Šต๋‹ˆ๋‹ค."); return; } if (!screenContext) { toast.error("ํ™”๋ฉด ์ปจํ…์ŠคํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); return; } try { // 1. ์†Œ์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ let sourceProvider = screenContext.getDataProvider(dataTransferConfig.sourceComponentId); // ๐Ÿ†• ์†Œ์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์œผ๋ฉด, ํ˜„์žฌ ํ™”๋ฉด์—์„œ ํ…Œ์ด๋ธ” ๋ฆฌ์ŠคํŠธ ์ž๋™ ํƒ์ƒ‰ // (์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ์˜ ๋‹ค๋ฅธ ์„น์…˜์œผ๋กœ ์ „ํ™˜ํ–ˆ์„ ๋•Œ ์ด์ „ ์ปดํฌ๋„ŒํŠธ ID๊ฐ€ ๋‚จ์•„์žˆ๋Š” ๊ฒฝ์šฐ ๋Œ€์‘) if (!sourceProvider) { console.log(`โš ๏ธ [ButtonPrimary] ์ง€์ •๋œ ์†Œ์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ: ${dataTransferConfig.sourceComponentId}`); console.log(`๐Ÿ” [ButtonPrimary] ํ˜„์žฌ ํ™”๋ฉด์—์„œ DataProvider ์ž๋™ ํƒ์ƒ‰...`); const allProviders = screenContext.getAllDataProviders(); // ํ…Œ์ด๋ธ” ๋ฆฌ์ŠคํŠธ ์šฐ์„  ํƒ์ƒ‰ for (const [id, provider] of allProviders) { if (provider.componentType === "table-list") { sourceProvider = provider; console.log(`โœ… [ButtonPrimary] ํ…Œ์ด๋ธ” ๋ฆฌ์ŠคํŠธ ์ž๋™ ๋ฐœ๊ฒฌ: ${id}`); break; } } // ํ…Œ์ด๋ธ” ๋ฆฌ์ŠคํŠธ๊ฐ€ ์—†์œผ๋ฉด ์ฒซ ๋ฒˆ์งธ DataProvider ์‚ฌ์šฉ if (!sourceProvider && allProviders.size > 0) { const firstEntry = allProviders.entries().next().value; if (firstEntry) { sourceProvider = firstEntry[1]; console.log(`โœ… [ButtonPrimary] ์ฒซ ๋ฒˆ์งธ DataProvider ์‚ฌ์šฉ: ${firstEntry[0]} (${sourceProvider.componentType})`); } } if (!sourceProvider) { toast.error("๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); return; } } const rawSourceData = sourceProvider.getSelectedData(); // ๐Ÿ†• ๋ฐฐ์—ด์ด ์•„๋‹Œ ๊ฒฝ์šฐ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ const sourceData = Array.isArray(rawSourceData) ? rawSourceData : (rawSourceData ? [rawSourceData] : []); console.log("๐Ÿ“ฆ ์†Œ์Šค ๋ฐ์ดํ„ฐ:", { rawSourceData, sourceData, isArray: Array.isArray(rawSourceData) }); if (!sourceData || sourceData.length === 0) { toast.warning("์„ ํƒ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค."); return; } // 1.5. ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ ์†Œ์Šค ์ฒ˜๋ฆฌ (์˜ˆ: ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ์˜ ์นดํ…Œ๊ณ ๋ฆฌ ๊ฐ’) let additionalData: Record = {}; // ๋ฐฉ๋ฒ• 1: additionalSources ์„ค์ •์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ if (dataTransferConfig.additionalSources && Array.isArray(dataTransferConfig.additionalSources)) { for (const additionalSource of dataTransferConfig.additionalSources) { const additionalProvider = screenContext.getDataProvider(additionalSource.componentId); if (additionalProvider) { const additionalValues = additionalProvider.getSelectedData(); if (additionalValues && additionalValues.length > 0) { // ์ฒซ ๋ฒˆ์งธ ๊ฐ’ ์‚ฌ์šฉ (์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ๋Š” ํ•ญ์ƒ 1๊ฐœ) const firstValue = additionalValues[0]; // fieldName์ด ์ง€์ •๋˜์–ด ์žˆ์œผ๋ฉด ๊ทธ ํ•„๋“œ๋งŒ ์ถ”์ถœ if (additionalSource.fieldName) { additionalData[additionalSource.fieldName] = firstValue[additionalSource.fieldName] || firstValue.condition || firstValue; } else { // fieldName์ด ์—†์œผ๋ฉด ์ „์ฒด ๊ฐ์ฒด ๋ณ‘ํ•ฉ additionalData = { ...additionalData, ...firstValue }; } console.log("๐Ÿ“ฆ ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ (additionalSources):", { sourceId: additionalSource.componentId, fieldName: additionalSource.fieldName, value: additionalData[additionalSource.fieldName || 'all'], }); } } } } // ๋ฐฉ๋ฒ• 2: formData์—์„œ ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ (์ž๋™) // ConditionalSectionViewer๊ฐ€ __conditionalContainerValue, __conditionalContainerControlField๋ฅผ formData์— ํฌํ•จ์‹œํ‚ด if (formData && formData.__conditionalContainerValue) { // includeConditionalValue ์„ค์ •์ด true์ด๊ฑฐ๋‚˜ ์„ค์ •์ด ์—†์œผ๋ฉด ์ž๋™ ํฌํ•จ if (dataTransferConfig.includeConditionalValue !== false) { const conditionalValue = formData.__conditionalContainerValue; const conditionalLabel = formData.__conditionalContainerLabel; const controlField = formData.__conditionalContainerControlField; // ๐Ÿ†• ์ œ์–ด ํ•„๋“œ๋ช… ์ง์ ‘ ์‚ฌ์šฉ // ๐Ÿ†• controlField๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ์„ ํ•„๋“œ๋ช…์œผ๋กœ ์‚ฌ์šฉ (์ž๋™ ๋งคํ•‘!) if (controlField) { additionalData[controlField] = conditionalValue; console.log("๐Ÿ“ฆ ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๊ฐ’ ์ž๋™ ๋งคํ•‘:", { controlField, value: conditionalValue, label: conditionalLabel, }); } else { // controlField๊ฐ€ ์—†์œผ๋ฉด ๊ธฐ์กด ๋ฐฉ์‹: formData์—์„œ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง„ ํ‚ค ์ฐพ๊ธฐ for (const [key, value] of Object.entries(formData)) { if (value === conditionalValue && !key.startsWith('__')) { additionalData[key] = conditionalValue; console.log("๐Ÿ“ฆ ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๊ฐ’ ์ž๋™ ํฌํ•จ:", { fieldName: key, value: conditionalValue, label: conditionalLabel, }); break; } } // ๋ชป ์ฐพ์•˜์œผ๋ฉด ๊ธฐ๋ณธ ํ•„๋“œ๋ช… ์‚ฌ์šฉ if (!Object.keys(additionalData).some(k => !k.startsWith('__'))) { additionalData['condition_type'] = conditionalValue; console.log("๐Ÿ“ฆ ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๊ฐ’ (๊ธฐ๋ณธ ํ•„๋“œ๋ช…):", { fieldName: 'condition_type', value: conditionalValue, }); } } } } // 2. ๊ฒ€์ฆ const validation = dataTransferConfig.validation; if (validation) { if (validation.minSelection && sourceData.length < validation.minSelection) { toast.error(`์ตœ์†Œ ${validation.minSelection}๊ฐœ ์ด์ƒ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.`); return; } if (validation.maxSelection && sourceData.length > validation.maxSelection) { toast.error(`์ตœ๋Œ€ ${validation.maxSelection}๊ฐœ๊นŒ์ง€ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.`); return; } } // 3. ํ™•์ธ ๋ฉ”์‹œ์ง€ if (dataTransferConfig.confirmBeforeTransfer) { const confirmMessage = dataTransferConfig.confirmMessage || `${sourceData.length}๊ฐœ ํ•ญ๋ชฉ์„ ์ „๋‹ฌํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?`; if (!window.confirm(confirmMessage)) { return; } } // 4. ๋งคํ•‘ ๊ทœ์น™ ์ ์šฉ + ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ ๋ณ‘ํ•ฉ const mappedData = sourceData.map((row) => { const mappedRow = applyMappingRules(row, dataTransferConfig.mappingRules || []); // ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋“  ํ–‰์— ํฌํ•จ return { ...mappedRow, ...additionalData, }; }); console.log("๐Ÿ“ฆ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ:", { sourceData, mappedData, targetType: dataTransferConfig.targetType, targetComponentId: dataTransferConfig.targetComponentId, targetScreenId: dataTransferConfig.targetScreenId, }); // 5. ํƒ€๊ฒŸ์œผ๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ if (dataTransferConfig.targetType === "component") { // ๊ฐ™์€ ํ™”๋ฉด์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌ const targetReceiver = screenContext.getDataReceiver(dataTransferConfig.targetComponentId); if (!targetReceiver) { toast.error(`ํƒ€๊ฒŸ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: ${dataTransferConfig.targetComponentId}`); return; } await targetReceiver.receiveData(mappedData, { targetComponentId: dataTransferConfig.targetComponentId, targetComponentType: targetReceiver.componentType, mode: dataTransferConfig.mode || "append", mappingRules: dataTransferConfig.mappingRules || [], }); toast.success(`${sourceData.length}๊ฐœ ํ•ญ๋ชฉ์ด ์ „๋‹ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`); } else if (dataTransferConfig.targetType === "splitPanel") { // ๐Ÿ†• ๋ถ„ํ•  ํŒจ๋„์˜ ๋ฐ˜๋Œ€ํŽธ ํ™”๋ฉด์œผ๋กœ ์ „๋‹ฌ if (!splitPanelContext) { toast.error("๋ถ„ํ•  ํŒจ๋„ ์ปจํ…์ŠคํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋ฒ„ํŠผ์ด ๋ถ„ํ•  ํŒจ๋„ ๋‚ด๋ถ€์— ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”."); return; } // ๐Ÿ†• useSplitPanelPosition ํ›…์œผ๋กœ ์œ„์น˜ ๊ฐ€์ ธ์˜ค๊ธฐ (์ค‘์ฒฉ๋œ ํ™”๋ฉด์—์„œ๋„ ์ž‘๋™) // screenId๋กœ ์ฐพ๋Š” ๊ฒƒ์€ ์ง์ ‘ ์ž„๋ฒ ๋“œ๋œ ํ™”๋ฉด์—์„œ๋งŒ ์ž‘๋™ํ•˜๋ฏ€๋กœ, // SplitPanelPositionProvider๋กœ ์ „๋‹ฌ๋œ ์œ„์น˜๋ฅผ ์šฐ์„  ์‚ฌ์šฉ const currentPosition = splitPanelPosition || (screenId ? splitPanelContext.getPositionByScreenId(screenId) : null); if (!currentPosition) { toast.error("๋ถ„ํ•  ํŒจ๋„ ๋‚ด ์œ„์น˜๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. screenId: " + screenId); return; } console.log("๐Ÿ“ฆ ๋ถ„ํ•  ํŒจ๋„ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ:", { currentPosition, splitPanelPositionFromHook: splitPanelPosition, screenId, leftScreenId: splitPanelContext.leftScreenId, rightScreenId: splitPanelContext.rightScreenId, }); const result = await splitPanelContext.transferToOtherSide( currentPosition, mappedData, dataTransferConfig.targetComponentId, // ํŠน์ • ์ปดํฌ๋„ŒํŠธ ์ง€์ • (์„ ํƒ์‚ฌํ•ญ) dataTransferConfig.mode || "append" ); if (result.success) { toast.success(result.message); } else { toast.error(result.message); return; } } else if (dataTransferConfig.targetType === "screen") { // ๋‹ค๋ฅธ ํ™”๋ฉด์œผ๋กœ ์ „๋‹ฌ (๊ตฌํ˜„ ์˜ˆ์ •) toast.info("๋‹ค๋ฅธ ํ™”๋ฉด์œผ๋กœ์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์€ ์ถ”ํ›„ ๊ตฌํ˜„ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค."); return; } else { toast.success(`${sourceData.length}๊ฐœ ํ•ญ๋ชฉ์ด ์ „๋‹ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`); } // 6. ์ „๋‹ฌ ํ›„ ์ •๋ฆฌ if (dataTransferConfig.clearAfterTransfer) { sourceProvider.clearSelection(); } } catch (error: any) { console.error("โŒ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ์‹คํŒจ:", error); toast.error(error.message || "๋ฐ์ดํ„ฐ ์ „๋‹ฌ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."); } }; const handleClick = async (e: React.MouseEvent) => { e.stopPropagation(); // ํ”„๋ฆฌ๋ทฐ ๋ชจ๋“œ์—์„œ๋Š” ๋ฒ„ํŠผ ๋™์ž‘ ์ฐจ๋‹จ if (isPreviewMode) { return; } // ๋””์ž์ธ ๋ชจ๋“œ์—์„œ๋Š” ๊ธฐ๋ณธ onClick๋งŒ ์‹คํ–‰ if (isDesignMode) { onClick?.(); return; } // ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ๋ชจ๋“œ์—์„œ ์•ก์…˜ ์‹คํ–‰ if (isInteractive && processedConfig.action) { // transferData ์•ก์…˜ ์ฒ˜๋ฆฌ (ํ™”๋ฉด ์ปจํ…์ŠคํŠธ ํ•„์š”) if (processedConfig.action.type === "transferData") { await handleTransferDataAction(processedConfig.action); return; } // ๐Ÿ†• modalDataStore์—์„œ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (๋ถ„ํ•  ํŒจ๋„ ๋“ฑ์—์„œ ์„ ํƒํ•œ ๋ฐ์ดํ„ฐ) let effectiveSelectedRowsData = selectedRowsData; if ((!selectedRowsData || selectedRowsData.length === 0) && effectiveTableName) { try { const { useModalDataStore } = await import("@/stores/modalDataStore"); const dataRegistry = useModalDataStore.getState().dataRegistry; const modalData = dataRegistry[effectiveTableName]; if (modalData && modalData.length > 0) { effectiveSelectedRowsData = modalData; console.log("๐Ÿ”— [ButtonPrimaryComponent] modalDataStore์—์„œ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ด:", { tableName: effectiveTableName, count: modalData.length, data: modalData, }); } } catch (error) { console.warn("modalDataStore ์ ‘๊ทผ ์‹คํŒจ:", error); } } // ์‚ญ์ œ ์•ก์…˜์ธ๋ฐ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€ ํ‘œ์‹œํ•˜๊ณ  ์ค‘๋‹จ const hasDataToDelete = (effectiveSelectedRowsData && effectiveSelectedRowsData.length > 0) || (flowSelectedData && flowSelectedData.length > 0); if (processedConfig.action.type === "delete" && !hasDataToDelete) { toast.warning("์‚ญ์ œํ•  ํ•ญ๋ชฉ์„ ๋จผ์ € ์„ ํƒํ•ด์ฃผ์„ธ์š”."); return; } // ๐Ÿ†• ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์˜ ์„ค์ • ์ˆ˜์ง‘ (parentDataMapping ๋“ฑ) const componentConfigs: Record = {}; if (allComponents && Array.isArray(allComponents)) { for (const comp of allComponents) { if (comp.id && comp.componentConfig) { componentConfigs[comp.id] = comp.componentConfig; } } } // ๐Ÿ†• ๋””๋ฒ„๊น…: tableName ํ™•์ธ console.log("๐Ÿ” [ButtonPrimaryComponent] context ์ƒ์„ฑ:", { propsTableName: tableName, contextTableName: screenContext?.tableName, effectiveTableName, propsScreenId: screenId, contextScreenId: screenContext?.screenId, effectiveScreenId, }); // ๐Ÿ†• ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (์šฐ์ธก ํ™”๋ฉด์—์„œ ์ €์žฅ ์‹œ ์ขŒ์ธก ์„ ํƒ ๋ฐ์ดํ„ฐ ํฌํ•จ) // ์กฐ๊ฑด ์™„ํ™”: splitPanelContext๊ฐ€ ์žˆ๊ณ  selectedLeftData๊ฐ€ ์žˆ์œผ๋ฉด ๊ฐ€์ ธ์˜ด // (ํƒญ ์•ˆ์—์„œ๋„ ๋ถ„ํ•  ํŒจ๋„ ์ปจํ…์ŠคํŠธ์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก) let splitPanelParentData: Record | undefined; if (splitPanelContext) { // ์šฐ์ธก ํ™”๋ฉด์ด๊ฑฐ๋‚˜, ํƒญ ์•ˆ์˜ ํ™”๋ฉด(splitPanelPosition์ด undefined)์ธ ๊ฒฝ์šฐ ๋ชจ๋‘ ์ฒ˜๋ฆฌ // ์ขŒ์ธก ํ™”๋ฉด์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ํฌํ•จ (์ขŒ์ธก์—์„œ ์ €์žฅ ์‹œ ์ž์‹ ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ€๋ชจ๋กœ ํฌํ•จํ•˜๋ฉด ์•ˆ๋จ) if (splitPanelPosition !== "left") { splitPanelParentData = splitPanelContext.getMappedParentData(); if (Object.keys(splitPanelParentData).length > 0) { console.log("๐Ÿ”— [ButtonPrimaryComponent] ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ํฌํ•จ:", { splitPanelParentData, splitPanelPosition, isInTab: !splitPanelPosition, // splitPanelPosition์ด ์—†์œผ๋ฉด ํƒญ ์•ˆ }); } } } const context: ButtonActionContext = { formData: formData || {}, originalData: originalData, // ๐Ÿ”ง ๋นˆ ๊ฐ์ฒด ๋Œ€์‹  undefined ์œ ์ง€ (UPDATE ํŒ๋‹จ์— ์‚ฌ์šฉ) screenId: effectiveScreenId, // ๐Ÿ†• ScreenContext์—์„œ ๊ฐ€์ ธ์˜จ ๊ฐ’ ์‚ฌ์šฉ tableName: effectiveTableName, // ๐Ÿ†• ScreenContext์—์„œ ๊ฐ€์ ธ์˜จ ๊ฐ’ ์‚ฌ์šฉ userId, // ๐Ÿ†• ์‚ฌ์šฉ์ž ID userName, // ๐Ÿ†• ์‚ฌ์šฉ์ž ์ด๋ฆ„ companyCode, // ๐Ÿ†• ํšŒ์‚ฌ ์ฝ”๋“œ onFormDataChange, onRefresh, onClose, onFlowRefresh, // ํ”Œ๋กœ์šฐ ์ƒˆ๋กœ๊ณ ์นจ ์ฝœ๋ฐฑ ์ถ”๊ฐ€ onSave: finalOnSave, // ๐Ÿ†• EditModal์˜ handleSave ์ฝœ๋ฐฑ (props์—์„œ๋„ ์ถ”์ถœ) // ํ…Œ์ด๋ธ” ์„ ํƒ๋œ ํ–‰ ์ •๋ณด ์ถ”๊ฐ€ (modalDataStore์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ ์šฐ์„ ) selectedRows, selectedRowsData: effectiveSelectedRowsData, // ํ…Œ์ด๋ธ” ์ •๋ ฌ ์ •๋ณด ์ถ”๊ฐ€ sortBy, // ๐Ÿ†• ์ •๋ ฌ ์ปฌ๋Ÿผ sortOrder, // ๐Ÿ†• ์ •๋ ฌ ๋ฐฉํ–ฅ columnOrder, // ๐Ÿ†• ์ปฌ๋Ÿผ ์ˆœ์„œ tableDisplayData, // ๐Ÿ†• ํ™”๋ฉด์— ํ‘œ์‹œ๋œ ๋ฐ์ดํ„ฐ // ๐Ÿ†• ๊ฐ™์€ ํ™”๋ฉด์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ (TableList ์ž๋™ ๊ฐ์ง€์šฉ) allComponents, // ํ”Œ๋กœ์šฐ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ ์ •๋ณด ์ถ”๊ฐ€ flowSelectedData, flowSelectedStepId, // ๐Ÿ†• ์ปดํฌ๋„ŒํŠธ๋ณ„ ์„ค์ • (parentDataMapping ๋“ฑ) componentConfigs, // ๐Ÿ†• ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ (์ขŒ์ธก ํ™”๋ฉด์—์„œ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ) splitPanelParentData, } as ButtonActionContext; // ํ™•์ธ์ด ํ•„์š”ํ•œ ์•ก์…˜์ธ์ง€ ํ™•์ธ if (confirmationRequiredActions.includes(processedConfig.action.type)) { // ํ™•์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ ํ‘œ์‹œ setPendingAction({ type: processedConfig.action.type, config: processedConfig.action, context, }); setShowConfirmDialog(true); } else { // ํ™•์ธ์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ์•ก์…˜์€ ๋ฐ”๋กœ ์‹คํ–‰ await executeAction(processedConfig.action, context); } } else { // ์•ก์…˜์ด ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๊ธฐ๋ณธ onClick ์‹คํ–‰ onClick?.(); } }; // ํ™•์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ์—์„œ ํ™•์ธ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ const handleConfirmAction = async () => { if (pendingAction) { await executeAction(pendingAction.config, pendingAction.context); } setShowConfirmDialog(false); setPendingAction(null); }; // ํ™•์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ์—์„œ ์ทจ์†Œ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ const handleCancelAction = () => { setShowConfirmDialog(false); setPendingAction(null); }; // DOM์— ์ „๋‹ฌํ•˜๋ฉด ์•ˆ ๋˜๋Š” React-specific props ํ•„ํ„ฐ๋ง const { selectedScreen, onZoneComponentDrop, onZoneClick, componentConfig: _componentConfig, component: _component, isSelected: _isSelected, onClick: _onClick, onDragStart: _onDragStart, onDragEnd: _onDragEnd, size: _size, position: _position, style: _style, screenId: _screenId, tableName: _tableName, onRefresh: _onRefresh, onClose: _onClose, selectedRows: _selectedRows, selectedRowsData: _selectedRowsData, onSelectedRowsChange: _onSelectedRowsChange, flowSelectedData: _flowSelectedData, // ํ”Œ๋กœ์šฐ ์„ ํƒ ๋ฐ์ดํ„ฐ ํ•„ํ„ฐ๋ง flowSelectedStepId: _flowSelectedStepId, // ํ”Œ๋กœ์šฐ ์„ ํƒ ์Šคํ… ID ํ•„ํ„ฐ๋ง onFlowRefresh: _onFlowRefresh, // ํ”Œ๋กœ์šฐ ์ƒˆ๋กœ๊ณ ์นจ ์ฝœ๋ฐฑ ํ•„ํ„ฐ๋ง originalData: _originalData, // ๋ถ€๋ถ„ ์—…๋ฐ์ดํŠธ์šฉ ์›๋ณธ ๋ฐ์ดํ„ฐ ํ•„ํ„ฐ๋ง refreshKey: _refreshKey, // ํ•„ํ„ฐ๋ง ์ถ”๊ฐ€ isInModal: _isInModal, // ํ•„ํ„ฐ๋ง ์ถ”๊ฐ€ mode: _mode, // ํ•„ํ„ฐ๋ง ์ถ”๊ฐ€ ...domProps } = props; // ๋‹ค์ด์–ผ๋กœ๊ทธ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ const getConfirmMessage = () => { if (!pendingAction) return ""; const customMessage = pendingAction.config.confirmMessage; if (customMessage) return customMessage; switch (pendingAction.type) { case "save": return "๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ €์žฅํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?"; case "delete": return "์ •๋ง๋กœ ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์ด ์ž‘์—…์€ ๋˜๋Œ๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."; case "submit": return "์ œ์ถœํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?"; default: return "์ด ์ž‘์—…์„ ์‹คํ–‰ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?"; } }; const getConfirmTitle = () => { if (!pendingAction) return ""; switch (pendingAction.type) { case "save": return "์ €์žฅ ํ™•์ธ"; case "delete": return "์‚ญ์ œ ํ™•์ธ"; case "submit": return "์ œ์ถœ ํ™•์ธ"; default: return "์ž‘์—… ํ™•์ธ"; } }; // DOM ์•ˆ์ „ํ•œ props๋งŒ ํ•„ํ„ฐ๋ง const safeDomProps = filterDOMProps(domProps); // ๐Ÿ†• ํ”Œ๋กœ์šฐ ๋‹จ๊ณ„๋ณ„ ํ‘œ์‹œ ์ œ์–ด if (!shouldShowButton) { // ๋ ˆ์ด์•„์›ƒ ๋™์ž‘์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ if (flowConfig?.layoutBehavior === "preserve-position") { // ์œ„์น˜ ์œ ์ง€ (๋นˆ ๊ณต๊ฐ„, display: none) return
; } else { // ์™„์ „ํžˆ ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Œ (auto-compact, ๋นˆ ๊ณต๊ฐ„ ์ œ๊ฑฐ) return null; } } // ๊ณตํ†ต ๋ฒ„ํŠผ ์Šคํƒ€์ผ const buttonElementStyle: React.CSSProperties = { width: "100%", height: "100%", minHeight: "40px", border: "none", borderRadius: "0.5rem", background: componentConfig.disabled ? "#e5e7eb" : buttonColor, color: componentConfig.disabled ? "#9ca3af" : "white", // ๐Ÿ”ง ํฌ๊ธฐ ์„ค์ • ์ ์šฉ (sm/md/lg) fontSize: componentConfig.size === "sm" ? "0.75rem" : componentConfig.size === "lg" ? "1rem" : "0.875rem", fontWeight: "600", cursor: componentConfig.disabled ? "not-allowed" : "pointer", outline: "none", boxSizing: "border-box", display: "flex", alignItems: "center", justifyContent: "center", // ๐Ÿ”ง ํฌ๊ธฐ์— ๋”ฐ๋ฅธ ํŒจ๋”ฉ ์กฐ์ • padding: componentConfig.size === "sm" ? "0 0.75rem" : componentConfig.size === "lg" ? "0 1.25rem" : "0 1rem", margin: "0", lineHeight: "1.25", boxShadow: componentConfig.disabled ? "none" : "0 1px 2px 0 rgba(0, 0, 0, 0.05)", // ๋””์ž์ธ ๋ชจ๋“œ์™€ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ๋ชจ๋“œ ๋ชจ๋‘์—์„œ ์‚ฌ์šฉ์ž ์Šคํƒ€์ผ ์ ์šฉ (width/height ์ œ์™ธ) ...(component.style ? Object.fromEntries( Object.entries(component.style).filter(([key]) => key !== 'width' && key !== 'height') ) : {}), }; const buttonContent = processedConfig.text !== undefined ? processedConfig.text : component.label || "๋ฒ„ํŠผ"; return ( <>
{isDesignMode ? ( // ๋””์ž์ธ ๋ชจ๋“œ: div๋กœ ๋ Œ๋”๋งํ•˜์—ฌ ์„ ํƒ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ
{buttonContent}
) : ( // ์ผ๋ฐ˜ ๋ชจ๋“œ: button์œผ๋กœ ๋ Œ๋”๋ง )}
{/* ํ™•์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ - EditModal๋ณด๋‹ค ์œ„์— ํ‘œ์‹œํ•˜๋„๋ก z-index ์ตœ์ƒ์œ„๋กœ ์„ค์ • */} {getConfirmTitle()} {getConfirmMessage()} ์ทจ์†Œ {pendingAction?.type === "save" ? "์ €์žฅ" : pendingAction?.type === "delete" ? "์‚ญ์ œ" : pendingAction?.type === "submit" ? "์ œ์ถœ" : "ํ™•์ธ"} ); }; /** * ButtonPrimary ๋ž˜ํผ ์ปดํฌ๋„ŒํŠธ * ์ถ”๊ฐ€์ ์ธ ๋กœ์ง์ด๋‚˜ ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ */ export const ButtonPrimaryWrapper: React.FC = (props) => { return ; };