반응형 및 테이블 리스트 컴포넌트 오류 수정

This commit is contained in:
kjs
2025-10-17 15:31:23 +09:00
parent 54e9f45823
commit 2a8081a253
21 changed files with 886 additions and 262 deletions

View File

@@ -88,18 +88,19 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
// 삭제 액션 감지 로직 (실제 필드명 사용)
const isDeleteAction = () => {
const deleteKeywords = ['삭제', 'delete', 'remove', '제거', 'del'];
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)
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),
)
);
};
@@ -109,9 +110,9 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
if (isDeleteAction() && !component.style?.labelColor) {
// 삭제 액션이고 라벨 색상이 설정되지 않은 경우 빨간색으로 자동 설정
if (component.style) {
component.style.labelColor = '#ef4444';
component.style.labelColor = "#ef4444";
} else {
component.style = { labelColor: '#ef4444' };
component.style = { labelColor: "#ef4444" };
}
}
}, [component.componentConfig?.action?.type, component.config?.action?.type, component.webTypeConfig?.actionType]);
@@ -125,20 +126,20 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
// 🎨 동적 색상 설정 (속성편집 모달의 "색상" 필드와 연동)
const getLabelColor = () => {
if (isDeleteAction()) {
return component.style?.labelColor || '#ef4444'; // 빨간색 기본값 (Tailwind red-500)
return component.style?.labelColor || "#ef4444"; // 빨간색 기본값 (Tailwind red-500)
}
return component.style?.labelColor || '#212121'; // 검은색 기본값 (shadcn/ui primary)
return component.style?.labelColor || "#212121"; // 검은색 기본값 (shadcn/ui primary)
};
const buttonColor = getLabelColor();
// 그라데이션용 어두운 색상 계산
const getDarkColor = (baseColor: string) => {
const hex = baseColor.replace('#', '');
const hex = baseColor.replace("#", "");
const r = Math.max(0, parseInt(hex.substr(0, 2), 16) - 40);
const g = Math.max(0, parseInt(hex.substr(2, 2), 16) - 40);
const b = Math.max(0, parseInt(hex.substr(4, 2), 16) - 40);
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
};
const buttonDarkColor = getDarkColor(buttonColor);
@@ -246,6 +247,23 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
currentLoadingToastRef.current = undefined;
}
// 실패한 경우 오류 처리
if (!success) {
console.log("❌ 액션 실패, 오류 토스트 표시");
const errorMessage =
actionConfig.errorMessage ||
(actionConfig.type === "save"
? "저장 중 오류가 발생했습니다."
: actionConfig.type === "delete"
? "삭제 중 오류가 발생했습니다."
: actionConfig.type === "submit"
? "제출 중 오류가 발생했습니다."
: "처리 중 오류가 발생했습니다.");
toast.error(errorMessage);
return;
}
// 성공한 경우에만 성공 토스트 표시
// edit 액션은 조용히 처리 (모달 열기만 하므로 토스트 불필요)
if (actionConfig.type !== "edit") {
const successMessage =
@@ -268,24 +286,24 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
// 저장/수정 성공 시 자동 처리
if (actionConfig.type === "save" || actionConfig.type === "edit") {
if (typeof window !== 'undefined') {
if (typeof window !== "undefined") {
// 1. 테이블 새로고침 이벤트 먼저 발송 (모달이 닫히기 전에)
console.log("🔄 저장/수정 후 테이블 새로고침 이벤트 발송");
window.dispatchEvent(new CustomEvent('refreshTable'));
window.dispatchEvent(new CustomEvent("refreshTable"));
// 2. 모달 닫기 (약간의 딜레이)
setTimeout(() => {
// EditModal 내부인지 확인 (isInModal prop 사용)
const isInEditModal = (props as any).isInModal;
if (isInEditModal) {
console.log("🚪 EditModal 닫기 이벤트 발송");
window.dispatchEvent(new CustomEvent('closeEditModal'));
window.dispatchEvent(new CustomEvent("closeEditModal"));
}
// ScreenModal은 항상 닫기
console.log("🚪 ScreenModal 닫기 이벤트 발송");
window.dispatchEvent(new CustomEvent('closeSaveModal'));
window.dispatchEvent(new CustomEvent("closeSaveModal"));
}, 100);
}
}
@@ -301,19 +319,8 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
console.error("❌ 버튼 액션 실행 오류:", error);
// 오류 토스트 표시
const errorMessage =
actionConfig.errorMessage ||
(actionConfig.type === "save"
? "저장 중 오류가 발생했습니다."
: actionConfig.type === "delete"
? "삭제 중 오류가 발생했습니다."
: actionConfig.type === "submit"
? "제출 중 오류가 발생했습니다."
: "처리 중 오류가 발생했습니다.");
console.log("💥 오류 토스트 표시:", errorMessage);
toast.error(errorMessage);
// 오류 토스트는 buttonActions.ts에서 이미 표시되므로 여기서는 제거
// (중복 토스트 방지)
}
};
@@ -379,7 +386,7 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
console.log("⚠️ 액션 실행 조건 불만족:", {
isInteractive,
hasAction: !!processedConfig.action,
"이유": !isInteractive ? "인터랙티브 모드 아님" : "액션 없음",
: !isInteractive ? "인터랙티브 모드 아님" : "액션 없음",
});
// 액션이 설정되지 않은 경우 기본 onClick 실행
onClick?.();
@@ -479,7 +486,7 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
maxHeight: "100%",
border: "none",
borderRadius: "8px",
background: componentConfig.disabled
background: componentConfig.disabled
? "linear-gradient(135deg, #e5e7eb 0%, #d1d5db 100%)"
: `linear-gradient(135deg, ${buttonColor} 0%, ${buttonDarkColor} 100%)`,
color: componentConfig.disabled ? "#9ca3af" : "white",
@@ -495,9 +502,7 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
margin: "0",
lineHeight: "1",
minHeight: "36px",
boxShadow: componentConfig.disabled
? "0 1px 2px 0 rgba(0, 0, 0, 0.05)"
: `0 2px 4px 0 ${buttonColor}33`, // 33은 20% 투명도
boxShadow: componentConfig.disabled ? "0 1px 2px 0 rgba(0, 0, 0, 0.05)" : `0 2px 4px 0 ${buttonColor}33`, // 33은 20% 투명도
// isInteractive 모드에서는 사용자 스타일 우선 적용
...(isInteractive && component.style ? component.style : {}),
}}