ERP-node/frontend/lib/registry/utils/createLayoutDefinition.ts

175 lines
4.5 KiB
TypeScript
Raw Normal View History

2025-09-10 18:36:28 +09:00
"use client";
import { LayoutDefinition, LayoutType, LayoutCategory } from "@/types/layout";
import React from "react";
/**
*
* .
*/
export interface CreateLayoutDefinitionOptions {
id: string;
name: string;
nameEng?: string;
description: string;
category: LayoutCategory;
icon?: string;
component: React.ComponentType<any>;
defaultConfig?: Record<string, any>;
defaultZones?: Array<{
id: string;
name: string;
position?: Record<string, any>;
size?: {
width: number | string;
height: number | string;
minWidth?: number;
minHeight?: number;
maxWidth?: number;
maxHeight?: number;
};
[key: string]: any;
}>;
tags?: string[];
isActive?: boolean;
version?: string;
author?: string;
documentation?: string;
}
/**
* .
*/
export function createLayoutDefinition(options: CreateLayoutDefinitionOptions): LayoutDefinition {
const {
id,
name,
nameEng = name,
description,
category,
icon = "layout",
component,
defaultConfig = {},
defaultZones = [],
tags = [],
isActive = true,
version = "1.0.0",
author = "Developer",
documentation = "",
} = options;
// ID 유효성 검사
if (!id || typeof id !== "string" || !/^[a-z][a-z0-9-]*$/.test(id)) {
throw new Error(
`Invalid layout ID: "${id}". ID must start with a letter and contain only lowercase letters, numbers, and hyphens.`,
);
}
// 필수 필드 검사
if (!name.trim()) {
throw new Error("Layout name is required");
}
if (!description.trim()) {
throw new Error("Layout description is required");
}
if (!component) {
throw new Error("Layout component is required");
}
// 기본 태그 자동 추가
const autoTags = [id, category, "layout"];
const allTags = [...new Set([...autoTags, ...tags])];
const definition: LayoutDefinition = {
id: id as LayoutType,
name,
nameEng,
description,
category,
icon,
component,
defaultConfig,
defaultZones,
tags: allTags,
isActive,
metadata: {
version,
author,
documentation,
createdAt: new Date().toISOString(),
lastUpdated: new Date().toISOString(),
},
};
console.log(`📦 레이아웃 정의 생성: ${id} (${name})`);
return definition;
}
/**
* .
*/
export function validateLayoutDefinition(definition: LayoutDefinition): {
isValid: boolean;
errors: string[];
warnings: string[];
} {
const errors: string[] = [];
const warnings: string[] = [];
// 필수 필드 검사
if (!definition.id) errors.push("ID is required");
if (!definition.name) errors.push("Name is required");
if (!definition.description) errors.push("Description is required");
if (!definition.category) errors.push("Category is required");
if (!definition.component) errors.push("Component is required");
// ID 형식 검사
if (definition.id && !/^[a-z][a-z0-9-]*$/.test(definition.id)) {
errors.push("ID must start with a letter and contain only lowercase letters, numbers, and hyphens");
}
// defaultZones 검사
if (definition.defaultZones) {
definition.defaultZones.forEach((zone, index) => {
if (!zone.id) errors.push(`Zone ${index}: ID is required`);
if (!zone.name) errors.push(`Zone ${index}: Name is required`);
});
}
// 경고사항 검사
if (!definition.nameEng) warnings.push("English name is recommended");
if (!definition.icon || definition.icon === "layout") warnings.push("Custom icon is recommended");
if (!definition.defaultZones || definition.defaultZones.length === 0) {
warnings.push("Default zones are recommended for better UX");
}
return {
isValid: errors.length === 0,
errors,
warnings,
};
}
/**
* .
*/
export function debugLayoutDefinition(definition: LayoutDefinition): void {
console.group(`🔍 Layout Debug: ${definition.id}`);
console.log("📋 Definition:", definition);
const validation = validateLayoutDefinition(definition);
if (validation.errors.length > 0) {
console.error("❌ Errors:", validation.errors);
}
if (validation.warnings.length > 0) {
console.warn("⚠️ Warnings:", validation.warnings);
}
if (validation.isValid) {
console.log("✅ Definition is valid");
}
console.groupEnd();
}