- InspectionReportModal/WorkLogModal/AssigneeSelectModal → document-system/modals/ dynamic import 래퍼 - ProductionOrders 타입/액션 → lib/api/production-orders/ 공유 영역 분리 - 결재(ApprovalBox), 품질(QMS), 영업(production-orders) import 경로 수정 - 하드코딩 경로 /production/work-orders → 영업 내부 경로로 변경 - dashboard-invalidation DomainKey 하드코딩 → registerDashboardDomain() 동적 레지스트리 공통 ERP에서 테넌트(생산) 직접 import 0건 달성 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
113 lines
4.2 KiB
TypeScript
113 lines
4.2 KiB
TypeScript
/**
|
|
* CEO 대시보드 targeted refetch 시스템
|
|
*
|
|
* CUD 발생 시 sessionStorage + CustomEvent로 대시보드 섹션별 갱신 트리거
|
|
*
|
|
* 도메인→섹션 매핑은 동적 레지스트리 패턴:
|
|
* - 공통 ERP 도메인은 여기서 직접 등록
|
|
* - 테넌트 전용 도메인은 각 모듈에서 registerDashboardDomain()으로 자기 등록
|
|
*/
|
|
|
|
// 대시보드 섹션 키 (useCEODashboard의 refetchMap과 1:1 매핑)
|
|
export type DashboardSectionKey =
|
|
| 'dailyReport'
|
|
| 'receivable'
|
|
| 'debtCollection'
|
|
| 'monthlyExpense'
|
|
| 'cardManagement'
|
|
| 'statusBoard'
|
|
| 'salesStatus'
|
|
| 'purchaseStatus'
|
|
| 'dailyProduction'
|
|
| 'unshipped'
|
|
| 'construction'
|
|
| 'dailyAttendance'
|
|
| 'entertainment'
|
|
| 'welfare';
|
|
|
|
// 동적 도메인→섹션 레지스트리
|
|
const domainSectionRegistry = new Map<string, DashboardSectionKey[]>();
|
|
|
|
/**
|
|
* 도메인→섹션 매핑 등록 (각 모듈에서 호출)
|
|
*
|
|
* @example
|
|
* // 생산 모듈 초기화 시
|
|
* registerDashboardDomain('production', ['statusBoard', 'dailyProduction']);
|
|
*
|
|
* // 건설 모듈 초기화 시
|
|
* registerDashboardDomain('construction', ['statusBoard', 'construction']);
|
|
*/
|
|
export function registerDashboardDomain(domain: string, sections: DashboardSectionKey[]): void {
|
|
domainSectionRegistry.set(domain, sections);
|
|
}
|
|
|
|
// ===== 공통 ERP 도메인 (테넌트 무관, 항상 등록) =====
|
|
registerDashboardDomain('deposit', ['dailyReport', 'receivable']);
|
|
registerDashboardDomain('withdrawal', ['dailyReport', 'monthlyExpense']);
|
|
registerDashboardDomain('sales', ['dailyReport', 'salesStatus', 'receivable']);
|
|
registerDashboardDomain('purchase', ['dailyReport', 'purchaseStatus', 'monthlyExpense']);
|
|
registerDashboardDomain('badDebt', ['debtCollection', 'receivable']);
|
|
registerDashboardDomain('expectedExpense', ['monthlyExpense']);
|
|
registerDashboardDomain('bill', ['dailyReport', 'receivable']);
|
|
registerDashboardDomain('giftCertificate', ['entertainment', 'cardManagement']);
|
|
registerDashboardDomain('journalEntry', ['entertainment', 'welfare', 'monthlyExpense']);
|
|
registerDashboardDomain('order', ['statusBoard', 'salesStatus']);
|
|
registerDashboardDomain('stock', ['statusBoard']);
|
|
registerDashboardDomain('schedule', ['statusBoard']);
|
|
registerDashboardDomain('client', ['statusBoard']);
|
|
registerDashboardDomain('leave', ['statusBoard', 'dailyAttendance']);
|
|
registerDashboardDomain('approval', ['statusBoard']);
|
|
registerDashboardDomain('attendance', ['statusBoard', 'dailyAttendance']);
|
|
registerDashboardDomain('shipment', ['statusBoard', 'unshipped']);
|
|
|
|
// ===== 테넌트 전용 도메인 (각 모듈에서 등록 — 현재는 하위 호환을 위해 여기서도 등록) =====
|
|
// TODO: Phase 1 완료 후 각 모듈의 초기화 코드로 이동
|
|
registerDashboardDomain('production', ['statusBoard', 'dailyProduction']);
|
|
registerDashboardDomain('construction', ['statusBoard', 'construction']);
|
|
|
|
const STORAGE_KEY = 'dashboard:stale-sections';
|
|
const EVENT_NAME = 'dashboard:invalidate';
|
|
|
|
/**
|
|
* CUD 성공 후 호출 — 해당 도메인이 영향 주는 대시보드 섹션을 stale 처리
|
|
*/
|
|
export function invalidateDashboard(domain: string): void {
|
|
const sections = domainSectionRegistry.get(domain);
|
|
if (!sections || sections.length === 0) return;
|
|
|
|
// 1. sessionStorage에 stale 섹션 저장 (navigation 사이 유지)
|
|
try {
|
|
const existing = sessionStorage.getItem(STORAGE_KEY);
|
|
const current: string[] = existing ? JSON.parse(existing) : [];
|
|
const merged = Array.from(new Set([...current, ...sections]));
|
|
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(merged));
|
|
} catch {
|
|
// sessionStorage 접근 불가 시 무시
|
|
}
|
|
|
|
// 2. CustomEvent 발행 (대시보드가 마운트 중이면 즉시 처리)
|
|
if (typeof window !== 'undefined') {
|
|
window.dispatchEvent(
|
|
new CustomEvent(EVENT_NAME, { detail: { sections } }),
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 대시보드 마운트 시 호출 — stale 섹션 읽고 클리어
|
|
*/
|
|
export function consumeStaleSections(): DashboardSectionKey[] {
|
|
try {
|
|
const raw = sessionStorage.getItem(STORAGE_KEY);
|
|
if (!raw) return [];
|
|
sessionStorage.removeItem(STORAGE_KEY);
|
|
return JSON.parse(raw) as DashboardSectionKey[];
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/** CustomEvent 이름 (리스너 등록용) */
|
|
export const DASHBOARD_INVALIDATE_EVENT = EVENT_NAME;
|