feat(03-03): module loader utility with category page and lazy cards
- Create module-loader.ts with MODULE_REGISTRY mapping slugs to dynamic imports (ssr:false) - Create [category] page fetching active modules from API, filtering by category - Create ModuleCard component with icon, name, description, and link to expanded view - Add i18n keys for modules namespace (de + en)
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Module Loader — Lazy-loading registry for Tessera modules.
|
||||
*
|
||||
* Maps module slugs to dynamically imported components.
|
||||
* Only modules listed in MODULE_REGISTRY will have their code loaded;
|
||||
* inactive/unregistered modules never trigger an import (MOD-04).
|
||||
*
|
||||
* Security: Only whitelisted slugs are resolved — arbitrary slugs
|
||||
* from URL params return null (T-03-09).
|
||||
*/
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
import type { ComponentType } from 'react';
|
||||
|
||||
/**
|
||||
* Registry entry for a module's lazy-loaded components.
|
||||
*/
|
||||
interface ModuleRegistryEntry {
|
||||
/** Main module page component (loaded on demand) */
|
||||
component: ComponentType;
|
||||
/** Optional card component for category grid view */
|
||||
cardComponent?: ComponentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Module registry mapping slugs to lazy-loaded components.
|
||||
*
|
||||
* To register a new module, add its slug and dynamic imports here.
|
||||
* Components are only fetched when React renders them (code-splitting).
|
||||
*/
|
||||
export const MODULE_REGISTRY: Record<string, ModuleRegistryEntry> = {
|
||||
domaincheck: {
|
||||
component: dynamic(
|
||||
() => import('@/app/(portal)/modules/domaincheck/page'),
|
||||
{ ssr: false },
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the main component for a module by slug.
|
||||
*
|
||||
* @param slug - Module slug (e.g., 'domaincheck')
|
||||
* @returns The dynamic component, or null if the slug is not registered
|
||||
*/
|
||||
export function loadModuleComponent(
|
||||
slug: string,
|
||||
): ComponentType | null {
|
||||
const entry = MODULE_REGISTRY[slug];
|
||||
return entry?.component ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the card component for a module by slug.
|
||||
*
|
||||
* Falls back to null if no card component is registered.
|
||||
*
|
||||
* @param slug - Module slug (e.g., 'domaincheck')
|
||||
* @returns The card component, or null if not available
|
||||
*/
|
||||
export function loadModuleCard(
|
||||
slug: string,
|
||||
): ComponentType | null {
|
||||
const entry = MODULE_REGISTRY[slug];
|
||||
return entry?.cardComponent ?? null;
|
||||
}
|
||||
Reference in New Issue
Block a user