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.
This commit is contained in:
parent
7ff76741af
commit
d56e46b17c
|
|
@ -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() {
|
|||
<>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="border-border bg-muted/30 relative flex h-[33px] shrink-0 items-end gap-[2px] overflow-hidden px-1.5"
|
||||
className="border-border bg-background relative flex h-[33px] shrink-0 items-end gap-[2px] overflow-hidden px-1.5"
|
||||
onDragOver={handleBarDragOver}
|
||||
onDragLeave={handleBarDragLeave}
|
||||
onDrop={handleBarDrop}
|
||||
>
|
||||
<div className="border-border pointer-events-none absolute inset-x-0 bottom-0 z-0 border-b" />
|
||||
<div className="pointer-events-none absolute inset-0 z-5 bg-black/15" />
|
||||
<div className="pointer-events-none absolute inset-0 z-5" />
|
||||
{displayVisible.map((tab, i) => renderTab(tab, i))}
|
||||
|
||||
{hasOverflow && (
|
||||
|
|
@ -587,7 +587,7 @@ export function TabBar() {
|
|||
{ghostStyle && draggedTab && (
|
||||
<div
|
||||
style={ghostStyle}
|
||||
className="border-primary/50 bg-background rounded-t-md border border-b-0 px-3 shadow-lg"
|
||||
className="border-primary/50 bg-background rounded-t-md border border-b-0 px-3"
|
||||
>
|
||||
<div className="flex h-full items-center">
|
||||
<span className="truncate text-[11px] font-medium">{draggedTab.title}</span>
|
||||
|
|
|
|||
|
|
@ -335,92 +335,6 @@ export const EditModal: React.FC<EditModalProps> = ({ className }) => {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 디테일 행의 FK를 통해 마스터 테이블 데이터를 자동 조회
|
||||
* - entity join 설정에서 FK 관계 탐지
|
||||
* - FK 값으로 마스터 테이블 전체 row 조회
|
||||
* - editData에 없는 필드만 병합 (디테일 데이터를 덮어쓰지 않음)
|
||||
*/
|
||||
const loadMasterDataForDetailRow = async (
|
||||
editData: Record<string, any>,
|
||||
targetScreenId: number,
|
||||
eventTableName?: string,
|
||||
): Promise<Record<string, any>> => {
|
||||
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<string, any> = {};
|
||||
const processedTables = new Set<string>();
|
||||
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) => {
|
||||
|
|
|
|||
|
|
@ -173,6 +173,13 @@ export const SaveModal: React.FC<SaveModalProps> = ({
|
|||
return;
|
||||
}
|
||||
|
||||
// ✅ 필수 항목 검증
|
||||
const validation = validateRequiredFields();
|
||||
if (!validation.isValid) {
|
||||
toast.error(`필수 항목을 입력해주세요: ${validation.missingFields.join(", ")}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsSaving(true);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue