Files
sam-react-prod/src/lib/dashboard-invalidation.ts
유병철 a99c3b3908 refactor: [Phase 0] 공통→테넌트 모듈 의존성 해소
- 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>
2026-03-18 14:40:28 +09:00

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;