feat: V2 Core 및 이벤트 시스템 추가
- V2 Core 라이브러리를 추가하여 느슨한 결합 아키텍처를 지원합니다. - V2 EventBus를 통해 타입 안전한 이벤트 발행 및 구독 기능을 구현하였습니다. - V2ErrorBoundary 컴포넌트를 추가하여 각 컴포넌트의 에러를 격리하고, 사용자 정의 폴백 UI 및 재시도 기능을 제공합니다. - UnifiedRepeater 및 ButtonPrimaryComponent에서 V2 EventBus를 활용하여 이벤트 처리 로직을 개선하였습니다. - 레거시 이벤트와의 호환성을 위해 LegacyEventAdapter를 추가하여 점진적 마이그레이션을 지원합니다. - V2 컴포넌트 간의 통신을 위한 이벤트 타입을 정의하였습니다.
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
} from "@/types/unified-repeater";
|
||||
import { apiClient } from "@/lib/api/client";
|
||||
import { allocateNumberingCode } from "@/lib/api/numberingRule";
|
||||
import { v2EventBus, V2_EVENTS, V2ErrorBoundary } from "@/lib/v2-core";
|
||||
|
||||
// modal-repeater-table 컴포넌트 재사용
|
||||
import { RepeaterTable } from "@/lib/registry/components/modal-repeater-table/RepeaterTable";
|
||||
@@ -201,8 +202,24 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
// V2 EventBus 구독
|
||||
const unsubscribe = v2EventBus.subscribe(
|
||||
V2_EVENTS.REPEATER_SAVE,
|
||||
async (payload) => {
|
||||
const tableName = config.useCustomTable && config.mainTableName
|
||||
? config.mainTableName
|
||||
: config.dataSource?.tableName;
|
||||
if (payload.tableName === tableName) {
|
||||
await handleSaveEvent({ detail: payload } as CustomEvent);
|
||||
}
|
||||
},
|
||||
{ componentId: `unified-repeater-${config.dataSource?.tableName}` }
|
||||
);
|
||||
|
||||
// 레거시 이벤트도 계속 지원 (점진적 마이그레이션)
|
||||
window.addEventListener("repeaterSave" as any, handleSaveEvent);
|
||||
return () => {
|
||||
unsubscribe();
|
||||
window.removeEventListener("repeaterSave" as any, handleSaveEvent);
|
||||
};
|
||||
}, [data, config.dataSource?.tableName, config.useCustomTable, config.mainTableName, config.foreignKeyColumn, parentId]);
|
||||
@@ -696,9 +713,24 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
|
||||
formData[fieldName] = processedData;
|
||||
};
|
||||
|
||||
// V2 EventBus 구독
|
||||
const unsubscribe = v2EventBus.subscribe(
|
||||
V2_EVENTS.FORM_SAVE_COLLECT,
|
||||
async (payload) => {
|
||||
// formData 객체가 있으면 데이터 수집
|
||||
const fakeEvent = {
|
||||
detail: { formData: payload.formData },
|
||||
} as CustomEvent;
|
||||
await handleBeforeFormSave(fakeEvent);
|
||||
},
|
||||
{ componentId: `unified-repeater-${config.dataSource?.tableName}` }
|
||||
);
|
||||
|
||||
// 레거시 이벤트도 계속 지원 (점진적 마이그레이션)
|
||||
window.addEventListener("beforeFormSave", handleBeforeFormSave);
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
window.removeEventListener("beforeFormSave", handleBeforeFormSave);
|
||||
};
|
||||
}, [config.fieldName]);
|
||||
@@ -782,10 +814,45 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
// V2 EventBus 구독
|
||||
const unsubscribeComponent = v2EventBus.subscribe(
|
||||
V2_EVENTS.COMPONENT_DATA_TRANSFER,
|
||||
(payload) => {
|
||||
const fakeEvent = {
|
||||
detail: {
|
||||
targetComponentId: payload.targetComponentId,
|
||||
transferData: [payload.data],
|
||||
mappingRules: [],
|
||||
mode: "append",
|
||||
},
|
||||
} as CustomEvent;
|
||||
handleComponentDataTransfer(fakeEvent);
|
||||
},
|
||||
{ componentId: `unified-repeater-${config.dataSource?.tableName}` }
|
||||
);
|
||||
|
||||
const unsubscribeSplitPanel = v2EventBus.subscribe(
|
||||
V2_EVENTS.SPLIT_PANEL_DATA_TRANSFER,
|
||||
(payload) => {
|
||||
const fakeEvent = {
|
||||
detail: {
|
||||
transferData: [payload.data],
|
||||
mappingRules: [],
|
||||
mode: "append",
|
||||
},
|
||||
} as CustomEvent;
|
||||
handleSplitPanelDataTransfer(fakeEvent);
|
||||
},
|
||||
{ componentId: `unified-repeater-${config.dataSource?.tableName}` }
|
||||
);
|
||||
|
||||
// 레거시 이벤트도 계속 지원 (점진적 마이그레이션)
|
||||
window.addEventListener("componentDataTransfer", handleComponentDataTransfer as EventListener);
|
||||
window.addEventListener("splitPanelDataTransfer", handleSplitPanelDataTransfer as EventListener);
|
||||
|
||||
return () => {
|
||||
unsubscribeComponent();
|
||||
unsubscribeSplitPanel();
|
||||
window.removeEventListener("componentDataTransfer", handleComponentDataTransfer as EventListener);
|
||||
window.removeEventListener("splitPanelDataTransfer", handleSplitPanelDataTransfer as EventListener);
|
||||
};
|
||||
@@ -855,4 +922,17 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
|
||||
|
||||
UnifiedRepeater.displayName = "UnifiedRepeater";
|
||||
|
||||
// V2ErrorBoundary로 래핑된 안전한 버전 export
|
||||
export const SafeUnifiedRepeater: React.FC<UnifiedRepeaterProps> = (props) => {
|
||||
return (
|
||||
<V2ErrorBoundary
|
||||
componentId={props.parentId || "unified-repeater"}
|
||||
componentType="UnifiedRepeater"
|
||||
fallbackStyle="compact"
|
||||
>
|
||||
<UnifiedRepeater {...props} />
|
||||
</V2ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
export default UnifiedRepeater;
|
||||
|
||||
Reference in New Issue
Block a user