155 lines
5.3 KiB
TypeScript
155 lines
5.3 KiB
TypeScript
import React, { lazy } from 'react'
|
||
import { RouteDto } from '@/proxy/routes/models'
|
||
import { 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'])
|
||
|
||
const lazyComponentCache = new Map<string, React.LazyExoticComponent<React.ComponentType<any>>>()
|
||
|
||
// Fiziksel komponent yükleme (mevcut mantık)
|
||
function loadPhysicalComponent(componentPath: string) {
|
||
const cleanedPath = componentPath.replace(/^@\//, '')
|
||
const fullPath = `../${cleanedPath}.tsx`
|
||
|
||
if (lazyComponentCache.has(fullPath)) {
|
||
return lazyComponentCache.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<any> }>)
|
||
lazyComponentCache.set(fullPath, LazyComponent)
|
||
return LazyComponent
|
||
}
|
||
|
||
// Dinamik komponent yükleme (yeni mantık)
|
||
function loadDynamicComponent(
|
||
componentPath: string,
|
||
registeredComponents: Record<string, React.ComponentType<unknown>>,
|
||
renderComponent?: (name: string, props?: any) => React.ReactNode,
|
||
isComponentRegistered?: (name: string) => boolean,
|
||
) {
|
||
|
||
if (lazyComponentCache.has(componentPath)) {
|
||
// console.log(`Dynamic component loaded from cache: ${componentName}`)
|
||
return lazyComponentCache.get(componentPath)!
|
||
}
|
||
|
||
// Ö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}`)
|
||
}
|
||
|
||
// console.log(`Dynamic component loaded: ${componentPath}`)
|
||
// Dinamik komponent için lazy wrapper oluştur
|
||
const LazyComponent = lazy(() =>
|
||
Promise.resolve({ default: DynamicComponent as React.ComponentType<any> }),
|
||
)
|
||
lazyComponentCache.set(componentPath, LazyComponent)
|
||
return LazyComponent
|
||
}
|
||
|
||
export function loadComponent(
|
||
componentType: string,
|
||
componentPath: string,
|
||
registeredComponents?: Record<string, React.ComponentType<unknown>>,
|
||
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<string, React.ComponentType<unknown>>,
|
||
renderComponent?: (name: string, props?: any) => React.ReactNode,
|
||
isComponentRegistered?: (name: string) => boolean,
|
||
) => React.LazyExoticComponent<React.ComponentType<any>>
|
||
routeType: string
|
||
authority?: string[]
|
||
componentType: string
|
||
componentPath: 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<CustomComponent, 'id' | 'name' | 'routePath' | 'isActive'>[],
|
||
): 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,
|
||
}))
|
||
}
|