버튼 액션 안되는 버그 수정
This commit is contained in:
@@ -64,6 +64,15 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
||||
selectedRowsData,
|
||||
...props
|
||||
}) => {
|
||||
console.log("🔵 ButtonPrimaryComponent 렌더링, 받은 props:", {
|
||||
componentId: component.id,
|
||||
hasSelectedRowsData: !!selectedRowsData,
|
||||
selectedRowsDataLength: selectedRowsData?.length,
|
||||
selectedRowsData,
|
||||
tableName,
|
||||
screenId,
|
||||
});
|
||||
|
||||
// 확인 다이얼로그 상태
|
||||
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
||||
const [pendingAction, setPendingAction] = useState<{
|
||||
@@ -204,7 +213,7 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
||||
}
|
||||
|
||||
// 확인 다이얼로그가 필요한 액션 타입들
|
||||
const confirmationRequiredActions: ButtonActionType[] = ["save", "submit", "delete"];
|
||||
const confirmationRequiredActions: ButtonActionType[] = ["save", "delete"];
|
||||
|
||||
// 실제 액션 실행 함수
|
||||
const executeAction = async (actionConfig: any, context: ButtonActionContext) => {
|
||||
@@ -221,8 +230,9 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
||||
// 추가 안전장치: 모든 로딩 토스트 제거
|
||||
toast.dismiss();
|
||||
|
||||
// edit 액션을 제외하고만 로딩 토스트 표시
|
||||
if (actionConfig.type !== "edit") {
|
||||
// UI 전환 액션(edit, modal, navigate)을 제외하고만 로딩 토스트 표시
|
||||
const silentActions = ["edit", "modal", "navigate"];
|
||||
if (!silentActions.includes(actionConfig.type)) {
|
||||
console.log("📱 로딩 토스트 표시 시작");
|
||||
currentLoadingToastRef.current = toast.loading(
|
||||
actionConfig.type === "save"
|
||||
@@ -237,9 +247,16 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
||||
},
|
||||
);
|
||||
console.log("📱 로딩 토스트 ID:", currentLoadingToastRef.current);
|
||||
} else {
|
||||
console.log("🔕 UI 전환 액션은 로딩 토스트 표시 안함:", actionConfig.type);
|
||||
}
|
||||
|
||||
console.log("⚡ ButtonActionExecutor.executeAction 호출 시작");
|
||||
console.log("🔍 actionConfig 확인:", {
|
||||
type: actionConfig.type,
|
||||
successMessage: actionConfig.successMessage,
|
||||
errorMessage: actionConfig.errorMessage,
|
||||
});
|
||||
const success = await ButtonActionExecutor.executeAction(actionConfig, context);
|
||||
console.log("⚡ ButtonActionExecutor.executeAction 완료, success:", success);
|
||||
|
||||
@@ -252,37 +269,70 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
||||
|
||||
// 실패한 경우 오류 처리
|
||||
if (!success) {
|
||||
// UI 전환 액션(edit, modal, navigate)은 에러도 조용히 처리
|
||||
const silentActions = ["edit", "modal", "navigate"];
|
||||
if (silentActions.includes(actionConfig.type)) {
|
||||
console.log("🔕 UI 전환 액션 실패지만 에러 토스트 표시 안함:", actionConfig.type);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("❌ 액션 실패, 오류 토스트 표시");
|
||||
const errorMessage =
|
||||
actionConfig.errorMessage ||
|
||||
(actionConfig.type === "save"
|
||||
// 기본 에러 메시지 결정
|
||||
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;
|
||||
|
||||
console.log("🔍 에러 메시지 결정:", {
|
||||
actionType: actionConfig.type,
|
||||
customMessage: actionConfig.errorMessage,
|
||||
useCustom: useCustomMessage,
|
||||
finalMessage: errorMessage
|
||||
});
|
||||
|
||||
toast.error(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
// 성공한 경우에만 성공 토스트 표시
|
||||
// edit 액션은 조용히 처리 (모달 열기만 하므로 토스트 불필요)
|
||||
if (actionConfig.type !== "edit") {
|
||||
const successMessage =
|
||||
actionConfig.successMessage ||
|
||||
(actionConfig.type === "save"
|
||||
// edit, modal, navigate 액션은 조용히 처리 (UI 전환만 하므로 토스트 불필요)
|
||||
if (actionConfig.type !== "edit" && actionConfig.type !== "modal" && actionConfig.type !== "navigate") {
|
||||
// 기본 성공 메시지 결정
|
||||
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;
|
||||
|
||||
console.log("🎉 성공 토스트 표시:", successMessage);
|
||||
toast.success(successMessage);
|
||||
} else {
|
||||
console.log("🔕 edit 액션은 조용히 처리 (토스트 없음)");
|
||||
console.log("🔕 UI 전환 액션은 조용히 처리 (토스트 없음):", actionConfig.type);
|
||||
}
|
||||
|
||||
console.log("✅ 버튼 액션 실행 성공:", actionConfig.type);
|
||||
@@ -357,6 +407,13 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
||||
requiresConfirmation: confirmationRequiredActions.includes(processedConfig.action.type),
|
||||
});
|
||||
|
||||
// 삭제 액션인데 선택된 데이터가 없으면 경고 메시지 표시하고 중단
|
||||
if (processedConfig.action.type === "delete" && (!selectedRowsData || selectedRowsData.length === 0)) {
|
||||
console.log("⚠️ 삭제할 데이터가 선택되지 않았습니다.");
|
||||
toast.warning("삭제할 항목을 먼저 선택해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
const context: ButtonActionContext = {
|
||||
formData: formData || {},
|
||||
originalData: originalData || {}, // 부분 업데이트용 원본 데이터 추가
|
||||
@@ -370,6 +427,15 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
||||
selectedRowsData,
|
||||
};
|
||||
|
||||
console.log("🔍 버튼 액션 실행 전 context 확인:", {
|
||||
hasSelectedRowsData: !!selectedRowsData,
|
||||
selectedRowsDataLength: selectedRowsData?.length,
|
||||
selectedRowsData,
|
||||
tableName,
|
||||
screenId,
|
||||
formData,
|
||||
});
|
||||
|
||||
// 확인이 필요한 액션인지 확인
|
||||
if (confirmationRequiredActions.includes(processedConfig.action.type)) {
|
||||
console.log("📋 확인 다이얼로그 표시 중...");
|
||||
|
||||
@@ -11,18 +11,11 @@ import type { ExtendedControlContext } from "@/types/control-management";
|
||||
*/
|
||||
export type ButtonActionType =
|
||||
| "save" // 저장
|
||||
| "cancel" // 취소
|
||||
| "delete" // 삭제
|
||||
| "edit" // 편집
|
||||
| "add" // 추가
|
||||
| "search" // 검색
|
||||
| "reset" // 초기화
|
||||
| "submit" // 제출
|
||||
| "close" // 닫기
|
||||
| "popup" // 팝업 열기
|
||||
| "navigate" // 페이지 이동
|
||||
| "modal" // 모달 열기
|
||||
| "newWindow"; // 새 창 열기
|
||||
| "control"; // 제어 흐름
|
||||
|
||||
/**
|
||||
* 버튼 액션 설정
|
||||
@@ -92,42 +85,18 @@ export class ButtonActionExecutor {
|
||||
case "save":
|
||||
return await this.handleSave(config, context);
|
||||
|
||||
case "submit":
|
||||
return await this.handleSubmit(config, context);
|
||||
|
||||
case "delete":
|
||||
return await this.handleDelete(config, context);
|
||||
|
||||
case "reset":
|
||||
return this.handleReset(config, context);
|
||||
|
||||
case "cancel":
|
||||
return this.handleCancel(config, context);
|
||||
|
||||
case "navigate":
|
||||
return this.handleNavigate(config, context);
|
||||
|
||||
case "modal":
|
||||
return this.handleModal(config, context);
|
||||
|
||||
case "newWindow":
|
||||
return this.handleNewWindow(config, context);
|
||||
|
||||
case "popup":
|
||||
return this.handlePopup(config, context);
|
||||
|
||||
case "search":
|
||||
return this.handleSearch(config, context);
|
||||
|
||||
case "add":
|
||||
return this.handleAdd(config, context);
|
||||
|
||||
case "edit":
|
||||
return this.handleEdit(config, context);
|
||||
|
||||
case "close":
|
||||
return this.handleClose(config, context);
|
||||
|
||||
case "control":
|
||||
return this.handleControl(config, context);
|
||||
|
||||
@@ -515,9 +484,9 @@ export class ButtonActionExecutor {
|
||||
});
|
||||
|
||||
window.dispatchEvent(modalEvent);
|
||||
toast.success("모달 화면이 열렸습니다.");
|
||||
// 모달 열기는 조용히 처리 (토스트 불필요)
|
||||
} else {
|
||||
toast.error("모달로 열 화면이 지정되지 않았습니다.");
|
||||
console.error("모달로 열 화면이 지정되지 않았습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1421,26 +1390,12 @@ export const DEFAULT_BUTTON_ACTIONS: Record<ButtonActionType, Partial<ButtonActi
|
||||
successMessage: "저장되었습니다.",
|
||||
errorMessage: "저장 중 오류가 발생했습니다.",
|
||||
},
|
||||
submit: {
|
||||
type: "submit",
|
||||
validateForm: true,
|
||||
successMessage: "제출되었습니다.",
|
||||
errorMessage: "제출 중 오류가 발생했습니다.",
|
||||
},
|
||||
delete: {
|
||||
type: "delete",
|
||||
confirmMessage: "정말 삭제하시겠습니까?",
|
||||
successMessage: "삭제되었습니다.",
|
||||
errorMessage: "삭제 중 오류가 발생했습니다.",
|
||||
},
|
||||
reset: {
|
||||
type: "reset",
|
||||
confirmMessage: "초기화하시겠습니까?",
|
||||
successMessage: "초기화되었습니다.",
|
||||
},
|
||||
cancel: {
|
||||
type: "cancel",
|
||||
},
|
||||
navigate: {
|
||||
type: "navigate",
|
||||
},
|
||||
@@ -1448,29 +1403,11 @@ export const DEFAULT_BUTTON_ACTIONS: Record<ButtonActionType, Partial<ButtonActi
|
||||
type: "modal",
|
||||
modalSize: "md",
|
||||
},
|
||||
newWindow: {
|
||||
type: "newWindow",
|
||||
popupWidth: 800,
|
||||
popupHeight: 600,
|
||||
},
|
||||
popup: {
|
||||
type: "popup",
|
||||
popupWidth: 600,
|
||||
popupHeight: 400,
|
||||
},
|
||||
search: {
|
||||
type: "search",
|
||||
successMessage: "검색을 실행했습니다.",
|
||||
},
|
||||
add: {
|
||||
type: "add",
|
||||
successMessage: "추가되었습니다.",
|
||||
},
|
||||
edit: {
|
||||
type: "edit",
|
||||
successMessage: "편집되었습니다.",
|
||||
},
|
||||
close: {
|
||||
type: "close",
|
||||
control: {
|
||||
type: "control",
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user