ERP-node/frontend/lib/registry/LayoutRegistry.ts

318 lines
9.2 KiB
TypeScript

"use client";
import React from "react";
import { LayoutDefinition, LayoutType, LayoutCategory } from "@/types/layout";
/**
* 레이아웃 레지스트리 클래스
* 동적으로 레이아웃 컴포넌트를 등록, 관리, 조회할 수 있는 중앙 레지스트리
*/
export class LayoutRegistry {
private static layouts = new Map<string, LayoutDefinition>();
private static eventListeners: Array<(event: LayoutRegistryEvent) => void> = [];
/**
* 레이아웃 등록
*/
static registerLayout(definition: LayoutDefinition): void {
this.layouts.set(definition.id, definition);
this.emitEvent({
type: "layout_registered",
data: definition,
timestamp: new Date(),
});
console.log(`✅ 레이아웃 등록: ${definition.id} (${definition.name})`);
// 개발자 도구 등록 (개발 모드에서만)
if (process.env.NODE_ENV === "development") {
this.registerGlobalDevTools();
}
}
/**
* 레이아웃 등록 해제
*/
static unregisterLayout(id: string): void {
const definition = this.layouts.get(id);
if (definition) {
this.layouts.delete(id);
this.emitEvent({
type: "layout_unregistered",
data: definition,
timestamp: new Date(),
});
console.log(`❌ 레이아웃 등록 해제: ${id}`);
}
}
/**
* 레이아웃 조회
*/
static getLayout(layoutType: string): LayoutDefinition | undefined {
return this.layouts.get(layoutType);
}
/**
* 카테고리별 레이아웃 조회
*/
static getLayoutsByCategory(category: LayoutCategory): LayoutDefinition[] {
return Array.from(this.layouts.values()).filter((layout) => layout.category === category);
}
/**
* 모든 레이아웃 조회
*/
static getAllLayouts(): LayoutDefinition[] {
return Array.from(this.layouts.values());
}
/**
* 활성화된 레이아웃만 조회
*/
static getActiveLayouts(): LayoutDefinition[] {
return Array.from(this.layouts.values()).filter((layout) => layout.isActive !== false);
}
/**
* 레이아웃 검색
*/
static searchLayouts(query: string): LayoutDefinition[] {
const searchTerm = query.toLowerCase();
return Array.from(this.layouts.values()).filter(
(layout) =>
layout.name.toLowerCase().includes(searchTerm) ||
layout.nameEng?.toLowerCase().includes(searchTerm) ||
layout.description?.toLowerCase().includes(searchTerm) ||
layout.tags?.some((tag) => tag.toLowerCase().includes(searchTerm)),
);
}
/**
* 레이아웃 존재 여부 확인
*/
static hasLayout(layoutType: string): boolean {
return this.layouts.has(layoutType);
}
/**
* 등록된 레이아웃 타입 목록
*/
static getRegisteredTypes(): string[] {
return Array.from(this.layouts.keys());
}
/**
* 레이아웃 수정
*/
static updateLayout(id: string, updates: Partial<LayoutDefinition>): boolean {
const existing = this.layouts.get(id);
if (existing) {
const updated = { ...existing, ...updates };
this.layouts.set(id, updated);
this.emitEvent({
type: "layout_updated",
data: updated,
timestamp: new Date(),
});
console.log(`🔄 레이아웃 수정: ${id}`);
return true;
}
return false;
}
/**
* 대량 레이아웃 등록
*/
static registerLayouts(definitions: LayoutDefinition[]): void {
definitions.forEach((definition) => {
this.registerLayout(definition);
});
}
/**
* 레지스트리 초기화
*/
static clear(): void {
this.layouts.clear();
this.emitEvent({
type: "registry_cleared",
data: null,
timestamp: new Date(),
});
console.log("🧹 레이아웃 레지스트리 초기화");
}
/**
* 이벤트 리스너 등록
*/
static addEventListener(listener: (event: LayoutRegistryEvent) => void): void {
this.eventListeners.push(listener);
}
/**
* 이벤트 리스너 제거
*/
static removeEventListener(listener: (event: LayoutRegistryEvent) => void): void {
const index = this.eventListeners.indexOf(listener);
if (index > -1) {
this.eventListeners.splice(index, 1);
}
}
/**
* 이벤트 발생
*/
private static emitEvent(event: LayoutRegistryEvent): void {
this.eventListeners.forEach((listener) => {
try {
listener(event);
} catch (error) {
console.error("레이아웃 레지스트리 이벤트 리스너 오류:", error);
}
});
}
/**
* 레지스트리 상태 정보
*/
static getRegistryInfo(): {
totalLayouts: number;
activeLayouts: number;
categoryCounts: Record<LayoutCategory, number>;
registeredTypes: string[];
} {
const allLayouts = this.getAllLayouts();
const activeLayouts = this.getActiveLayouts();
const categoryCounts = allLayouts.reduce(
(acc, layout) => {
acc[layout.category] = (acc[layout.category] || 0) + 1;
return acc;
},
{} as Record<LayoutCategory, number>,
);
return {
totalLayouts: allLayouts.length,
activeLayouts: activeLayouts.length,
categoryCounts,
registeredTypes: this.getRegisteredTypes(),
};
}
/**
* 개발자 도구를 브라우저 글로벌에 등록
*/
private static registerGlobalDevTools(): void {
if (typeof window !== "undefined") {
(window as any).__LAYOUT_REGISTRY__ = {
list: () => {
console.table(
this.getAllLayouts().map((l) => ({
ID: l.id,
Name: l.name,
Category: l.category,
Zones: l.defaultZones?.length || 0,
Tags: l.tags?.join(", ") || "none",
Version: l.metadata?.version || "1.0.0",
Active: l.isActive !== false ? "✅" : "❌",
})),
);
return this.getAllLayouts();
},
get: (id: string) => {
const layout = this.getLayout(id);
if (layout) {
console.group(`📦 Layout: ${id}`);
console.log("Definition:", layout);
console.log("Component:", layout.component);
console.log("Config:", layout.defaultConfig);
console.log("Zones:", layout.defaultZones);
console.groupEnd();
return layout;
} else {
console.warn(`❌ Layout not found: ${id}`);
console.log("Available layouts:", this.getRegisteredTypes());
return null;
}
},
stats: () => {
const info = this.getRegistryInfo();
console.group("📊 Layout Registry Statistics");
console.log(`📦 Total Layouts: ${info.totalLayouts}`);
console.log(`✅ Active Layouts: ${info.activeLayouts}`);
console.log("📂 Categories:", info.categoryCounts);
console.log("🏷️ Registered Types:", info.registeredTypes);
console.groupEnd();
return info;
},
search: (query: string) => {
const results = this.searchLayouts(query);
console.log(`🔍 Search results for "${query}":`, results);
return results;
},
categories: () => {
const byCategory = this.getAllLayouts().reduce(
(acc, layout) => {
if (!acc[layout.category]) acc[layout.category] = [];
acc[layout.category].push(layout.id);
return acc;
},
{} as Record<string, string[]>,
);
console.table(byCategory);
return byCategory;
},
clear: () => {
console.warn("🧹 Clearing layout registry...");
this.clear();
console.log("✅ Registry cleared");
},
reload: () => {
console.log("🔄 Registry reload not implemented yet");
console.log("Try refreshing the page or using HMR");
},
help: () => {
console.group("🛠️ Layout Registry DevTools Help");
console.log("__LAYOUT_REGISTRY__.list() - 모든 레이아웃 목록 표시");
console.log("__LAYOUT_REGISTRY__.get(id) - 특정 레이아웃 상세 정보");
console.log("__LAYOUT_REGISTRY__.stats() - 레지스트리 통계");
console.log("__LAYOUT_REGISTRY__.search(query) - 레이아웃 검색");
console.log("__LAYOUT_REGISTRY__.categories() - 카테고리별 레이아웃");
console.log("__LAYOUT_REGISTRY__.clear() - 레지스트리 초기화");
console.log("__LAYOUT_REGISTRY__.help() - 도움말");
console.groupEnd();
},
};
// 첫 등록 시에만 안내 메시지 출력
if (!(window as any).__LAYOUT_REGISTRY_INITIALIZED__) {
console.log("🛠️ Layout Registry DevTools initialized!");
console.log("Use __LAYOUT_REGISTRY__.help() for available commands");
(window as any).__LAYOUT_REGISTRY_INITIALIZED__ = true;
}
}
}
}
// 레지스트리 이벤트 타입
export interface LayoutRegistryEvent {
type: "layout_registered" | "layout_unregistered" | "layout_updated" | "registry_cleared";
data: LayoutDefinition | null;
timestamp: Date;
}
// 전역 레이아웃 레지스트리 인스턴스 (싱글톤)
export const layoutRegistry = LayoutRegistry;
// 기본 내보내기
export default LayoutRegistry;