From d56e46b17ca8586c932d6aeac0266168880ef456 Mon Sep 17 00:00:00 2001 From: kjs Date: Tue, 10 Mar 2026 15:19:50 +0900 Subject: [PATCH] refactor: Update TabBar and EditModal components for improved styling and validation - Removed unnecessary box shadow from active tab in TabBar for a cleaner look. - Updated TabBar background to use the main background color for better consistency. - Enhanced SaveModal to include validation for required fields, providing user feedback for missing inputs. - Removed unused master data loading function in EditModal to streamline the component. These changes improve the overall user interface and ensure that required fields are validated before submission, enhancing user experience. --- frontend/components/layout/TabBar.tsx | 8 +-- frontend/components/screen/EditModal.tsx | 86 ------------------------ frontend/components/screen/SaveModal.tsx | 7 ++ 3 files changed, 11 insertions(+), 90 deletions(-) diff --git a/frontend/components/layout/TabBar.tsx b/frontend/components/layout/TabBar.tsx index 8a850d20..e86ada2e 100644 --- a/frontend/components/layout/TabBar.tsx +++ b/frontend/components/layout/TabBar.tsx @@ -501,7 +501,7 @@ export function TabBar() { touchAction: "none", ...animStyle, ...(hiddenByGhost ? { opacity: 0 } : {}), - ...(isActive ? { boxShadow: "0 -1px 28px rgba(0,0,0,0.9)" } : {}), + ...(isActive ? {} : {}), }} title={tab.title} > @@ -542,13 +542,13 @@ export function TabBar() { <>
-
+
{displayVisible.map((tab, i) => renderTab(tab, i))} {hasOverflow && ( @@ -587,7 +587,7 @@ export function TabBar() { {ghostStyle && draggedTab && (
{draggedTab.title} diff --git a/frontend/components/screen/EditModal.tsx b/frontend/components/screen/EditModal.tsx index 1300886b..372132d4 100644 --- a/frontend/components/screen/EditModal.tsx +++ b/frontend/components/screen/EditModal.tsx @@ -335,92 +335,6 @@ export const EditModal: React.FC = ({ className }) => { } }; - /** - * 디테일 행의 FK를 통해 마스터 테이블 데이터를 자동 조회 - * - entity join 설정에서 FK 관계 탐지 - * - FK 값으로 마스터 테이블 전체 row 조회 - * - editData에 없는 필드만 병합 (디테일 데이터를 덮어쓰지 않음) - */ - const loadMasterDataForDetailRow = async ( - editData: Record, - targetScreenId: number, - eventTableName?: string, - ): Promise> => { - try { - let detailTableName = eventTableName; - if (!detailTableName) { - const screenInfo = await screenApi.getScreen(targetScreenId); - detailTableName = screenInfo?.tableName; - } - - if (!detailTableName) { - console.log("[EditModal:MasterLoad] 테이블명을 알 수 없음 - 스킵"); - return {}; - } - - console.log("[EditModal:MasterLoad] 시작:", { detailTableName, editDataKeys: Object.keys(editData) }); - - const entityJoinRes = await entityJoinApi.getEntityJoinConfigs(detailTableName); - const joinConfigs = entityJoinRes?.joinConfigs || []; - - if (joinConfigs.length === 0) { - console.log("[EditModal:MasterLoad] entity join 없음 - 스킵"); - return {}; - } - - console.log( - "[EditModal:MasterLoad] entity join:", - joinConfigs.map((c) => `${c.sourceColumn} → ${c.referenceTable}`), - ); - - const masterDataResult: Record = {}; - const processedTables = new Set(); - const { apiClient } = await import("@/lib/api/client"); - - for (const joinConfig of joinConfigs) { - const { sourceColumn, referenceTable, referenceColumn } = joinConfig; - if (processedTables.has(referenceTable)) continue; - - const fkValue = editData[sourceColumn]; - if (!fkValue) continue; - - try { - const response = await apiClient.post(`/table-management/tables/${referenceTable}/data`, { - search: { [referenceColumn || "id"]: fkValue }, - size: 1, - page: 1, - autoFilter: true, - }); - - const rows = response.data?.data?.data || response.data?.data?.rows || []; - if (rows.length > 0) { - const masterRow = rows[0]; - for (const [col, val] of Object.entries(masterRow)) { - if (val !== undefined && val !== null && editData[col] === undefined) { - masterDataResult[col] = val; - } - } - console.log("[EditModal:MasterLoad] 조회 성공:", { - table: referenceTable, - fk: `${sourceColumn}=${fkValue}`, - loadedFields: Object.keys(masterDataResult), - }); - } - } catch (queryError) { - console.warn("[EditModal:MasterLoad] 조회 실패:", referenceTable, queryError); - } - - processedTables.add(referenceTable); - } - - console.log("[EditModal:MasterLoad] 최종 결과:", Object.keys(masterDataResult)); - return masterDataResult; - } catch (error) { - console.warn("[EditModal:MasterLoad] 전체 오류:", error); - return {}; - } - }; - // 전역 모달 이벤트 리스너 (활성 탭에서만 처리) useEffect(() => { const handleOpenEditModal = async (event: CustomEvent) => { diff --git a/frontend/components/screen/SaveModal.tsx b/frontend/components/screen/SaveModal.tsx index 2b6a9c78..e8868cfb 100644 --- a/frontend/components/screen/SaveModal.tsx +++ b/frontend/components/screen/SaveModal.tsx @@ -173,6 +173,13 @@ export const SaveModal: React.FC = ({ return; } + // ✅ 필수 항목 검증 + const validation = validateRequiredFields(); + if (!validation.isValid) { + toast.error(`필수 항목을 입력해주세요: ${validation.missingFields.join(", ")}`); + return; + } + try { setIsSaving(true);