import React, { lazy } from 'react' import type { RouteDto } from '@/proxy/routes/models' import type { CustomComponent } from '@/proxy/developerKit/models' // Tüm view bileşenlerini import et (vite özel) // shared klasörü hariç, çünkü bu bileşenler genellikle başka yerlerde statik import ediliyor const modules = import.meta.glob(['../views/**/*.tsx', '!../views/shared/**/*.tsx']) // Only physical modules are safe to cache. Runtime components depend on the // latest ComponentContext render function and must not retain an old closure. const physicalComponentCache = new Map< string, React.LazyExoticComponent> >() // Fiziksel komponent yükleme (mevcut mantık) function loadPhysicalComponent(componentPath: string) { const cleanedPath = componentPath.replace(/^@\//, '') const fullPath = `../${cleanedPath}.tsx` if (physicalComponentCache.has(fullPath)) { return physicalComponentCache.get(fullPath)! } const loader = modules[fullPath] if (!loader) { console.error(`Physical component not found for path: ${fullPath}`) throw new Error(`Physical component not found for path: ${fullPath}`) } const LazyComponent = lazy(loader as () => Promise<{ default: React.ComponentType }>) physicalComponentCache.set(fullPath, LazyComponent) return LazyComponent } // Dinamik komponent yükleme (yeni mantık) function loadDynamicComponent( componentPath: string, registeredComponents: Record>, renderComponent?: (name: string, props?: any) => React.ReactNode, isComponentRegistered?: (name: string) => boolean, ) { // Önce manuel registered komponentleri kontrol et let DynamicComponent = registeredComponents[componentPath] // Eğer manuel registered'da yoksa, database compiled komponentleri kontrol et if ( !DynamicComponent && isComponentRegistered && renderComponent && isComponentRegistered(componentPath) ) { DynamicComponent = (props: any) => renderComponent(componentPath, props) as React.ReactElement } if (!DynamicComponent) { if (isComponentRegistered) { console.log('Database component registry available - checking...') } throw new Error(`Dynamic component not found: ${componentPath}`) } // Do not put this wrapper in a module-level cache. renderComponent changes // after the asynchronous database bundle compilation finishes. Caching this // function would keep the pre-compilation closure and render an empty page. return DynamicComponent as React.ComponentType } export function loadComponent( componentType: string, componentPath: string, registeredComponents?: Record>, renderComponent?: (name: string, props?: any) => React.ReactNode, isComponentRegistered?: (name: string) => boolean, ) { if (componentType === 'normal') { return loadPhysicalComponent(componentPath) } else if (componentType === 'dynamic') { if (!registeredComponents) { throw new Error('Registered components required for dynamic component loading') } return loadDynamicComponent( componentPath, registeredComponents, renderComponent, isComponentRegistered, ) } else { // Backward compatibility: varsayılan olarak fiziksel komponent kabul et return loadPhysicalComponent(componentPath) } } // React Router için uygun bir route tipi export interface DynamicReactRoute { key: string path: string getComponent: ( registeredComponents?: Record>, renderComponent?: (name: string, props?: any) => React.ReactNode, isComponentRegistered?: (name: string) => boolean, ) => React.ComponentType routeType: string authority?: string[] componentType: string componentPath: string /** Browser tab title; only runtime components carry a human readable label. */ title?: string } // API'den gelen route objesini, React Router için uygun hale getirir export function mapDynamicRoutes(routes: RouteDto[]): DynamicReactRoute[] { return routes.map((route) => ({ key: route.path, path: route.path, getComponent: (registeredComponents, renderComponent, isComponentRegistered) => loadComponent( route.componentType, route.componentPath, registeredComponents, renderComponent, isComponentRegistered, ), routeType: route.routeType, authority: route.authority, componentType: route.componentType, componentPath: route.componentPath, })) } // Custom components are the single source of truth for runtime routes. export function mapCustomComponentRoutes( components: Pick[], ): DynamicReactRoute[] { return components .filter((component) => component.isActive && component.routePath?.trim()) .map((component) => ({ key: `custom-component-${component.id}`, path: component.routePath.startsWith('/') ? component.routePath : `/${component.routePath}`, getComponent: (registeredComponents, renderComponent, isComponentRegistered) => loadComponent( 'dynamic', component.name, registeredComponents, renderComponent, isComponentRegistered, ), routeType: component.routePath.startsWith('/admin/') ? 'protected' : 'public', authority: [], componentType: 'dynamic', componentPath: component.name, // A runtime component has no module of its own to set the page title, so // the description entered in the designer names the tab. title: component.description?.trim() || component.name, })) }