import { Suspense, lazy, type ComponentType, Component, type ErrorInfo } from 'react'; import { LoadingSpinner } from './loading-spinner'; // import { ErrorBoundary } from '@/components/ErrorBoundary'; import { logger } from '@/utils/logger'; import { Button } from './button'; import { AlertTriangle, RefreshCw } from 'lucide-react'; // CRITIQUE FIX #16: Composant de fallback amélioré pour les erreurs de chargement lazy function LazyErrorFallback({ pageName, error, onRetry }: { pageName: string; error?: Error; onRetry?: () => void; }) { return (

{pageName}

Failed to load {pageName}

{error && (

{error.message || 'An error occurred while loading this page'}

)}
{onRetry && ( )}
); } // CRITIQUE FIX #16: ErrorBoundary spécifique pour les composants lazy class LazyErrorBoundary extends Component< { children: React.ReactNode; pageName: string; onError?: (error: Error, errorInfo: ErrorInfo) => void; }, { hasError: boolean; error?: Error } > { constructor(props: { children: React.ReactNode; pageName: string; onError?: (error: Error, errorInfo: ErrorInfo) => void }) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error: Error) { return { hasError: true, error }; } override componentDidCatch(error: Error, errorInfo: ErrorInfo) { // CRITIQUE FIX #16: Logger l'erreur avec le logger centralisé au lieu de console.error logger.error('[LazyComponent] Failed to load lazy component', { pageName: this.props.pageName, error: error.message, stack: error.stack, componentStack: errorInfo.componentStack, }); if (this.props.onError) { this.props.onError(error, errorInfo); } } handleRetry = () => { this.setState({ hasError: false, error: undefined }); }; override render() { if (this.state.hasError) { return ( ); } return this.props.children; } } /** * LazyComponentProps - Propriétés pour les composants lazy créés * * @interface LazyComponentProps */ interface LazyComponentProps { /** * Composant de fallback personnalisé à afficher pendant le chargement * Si non fourni, utilise LoadingSpinner par défaut */ fallback?: React.ReactNode; } /** * createLazyComponent - Factory pour créer des composants lazy avec Suspense * * Crée un composant lazy avec gestion automatique du Suspense et du fallback. * Utile pour le code splitting et le chargement à la demande des composants. * * @template T - Type du composant à charger * @param {() => Promise<{ default: T }>} importFunc - Fonction d'import dynamique * @param {React.ReactNode} fallback - Composant de fallback (optionnel) * @returns {ComponentType} Composant wrapper avec Suspense intégré * * @example * ```tsx * // Créer un composant lazy * const LazyDashboard = createLazyComponent( * () => import('@/pages/DashboardPage').then(m => ({ default: m.DashboardPage })) * ); * * // Utiliser le composant lazy * } /> * ``` * * @function */ // CRITIQUE FIX #16: Wrapper pour gérer les erreurs de chargement lazy de manière standardisée function createLazyWithErrorHandling>( importFunc: () => Promise<{ default: T }>, pageName: string, ) { return importFunc().catch((err) => { // CRITIQUE FIX #16: Logger l'erreur avec le logger centralisé logger.error('[LazyComponent] Failed to import lazy component', { pageName, error: err instanceof Error ? err.message : String(err), stack: err instanceof Error ? err.stack : undefined, }); // Retourner un composant d'erreur au lieu de laisser l'erreur se propager return Promise.resolve({ default: () => , }) as unknown as Promise<{ default: T }>; }); } export function createLazyComponent>( importFunc: () => Promise<{ default: T }>, fallback?: React.ReactNode, pageName?: string, ) { // CRITIQUE FIX #16: Utiliser la fonction avec gestion d'erreur si pageName est fourni const safeImportFunc = pageName ? () => createLazyWithErrorHandling(importFunc, pageName) : importFunc; const LazyComponent = lazy(safeImportFunc); return function WrappedLazyComponent( props: React.ComponentProps & LazyComponentProps, ) { // Extraire fallback des props pour ne pas le passer au composant lazy const { fallback: _fallback, ...componentProps } = props; // CRITIQUE FIX #16: Wrapper avec ErrorBoundary pour capturer les erreurs runtime const component = ( }> {/* @ts-expect-error - LazyComponent props are compatible but TypeScript can't infer it */} ); // Si pageName est fourni, wrapper avec LazyErrorBoundary if (pageName) { return ( {component} ); } return component; }; } // Composants lazy communs // CRITIQUE FIX #16: Ajouter pageName pour tous les composants lazy pour une meilleure gestion d'erreur export const LazyDashboard = createLazyComponent( () => import('@/pages/DashboardPage').then((m) => ({ default: m.DashboardPage })), undefined, 'Dashboard', ); export const LazyChat = createLazyComponent( () => import('@/features/chat/pages/ChatPage').then((m) => ({ default: m.ChatPage })), undefined, 'Chat', ); // CRITIQUE FIX #16: Tous les composants lazy utilisent maintenant la gestion d'erreur standardisée export const LazyLibrary = createLazyComponent( () => import('@/features/library/pages/LibraryPage').then((m) => ({ default: m.default })), undefined, 'Library', ); export const LazyProfile = createLazyComponent( () => import('@/pages/ProfilePage').then((m) => ({ default: m.ProfilePage })), undefined, 'Profile', ); export const LazySettings = createLazyComponent( () => import('@/features/settings/pages/SettingsPage').then((m) => ({ default: m.SettingsPage })), undefined, 'Settings', ); export const LazyLogin = createLazyComponent( () => import('@/pages/LoginPage').then((m) => ({ default: m.LoginPage })), undefined, 'Login', ); export const LazyRegister = createLazyComponent( () => import('@/pages/RegisterPage').then((m) => ({ default: m.RegisterPage })), undefined, 'Register', ); export const LazyForgotPassword = createLazyComponent( () => import('@/features/auth/pages/ForgotPasswordPage'), undefined, 'Forgot Password', ); export const LazyVerifyEmail = createLazyComponent( () => import('@/features/auth/pages/VerifyEmailPage'), undefined, 'Verify Email', ); export const LazyResetPassword = createLazyComponent( () => import('@/features/auth/pages/ResetPasswordPage'), undefined, 'Reset Password', ); export const LazySessions = createLazyComponent( () => import('@/features/auth/pages/SessionsPage'), undefined, 'Sessions', ); export const LazyNotFound = createLazyComponent( () => import('@/features/error/pages/NotFoundPage'), undefined, 'Not Found', ); export const LazyServerError = createLazyComponent( () => import('@/features/error/pages/ServerErrorPage'), undefined, 'Server Error', ); export const LazyUserProfile = createLazyComponent( () => import('@/features/profile/pages/UserProfilePage').then((m) => ({ default: m.UserProfilePage })), undefined, 'User Profile', ); export const LazyRoles = createLazyComponent( () => import('@/features/roles/pages/RolesPage').then((m) => ({ default: m.RolesPage })), undefined, 'Roles', ); export const LazyTrackDetail = createLazyComponent( () => import('@/features/tracks/pages/TrackDetailPage').then((m) => ({ default: m.TrackDetailPage })), undefined, 'Track Detail', ); export const LazyPlaylistRoutes = createLazyComponent( () => import('@/features/playlists/routes').then((m) => ({ default: m.PlaylistRoutes })), undefined, 'Playlists', ); export const LazySearch = createLazyComponent( () => import('@/pages/SearchPage').then((m) => ({ default: m.SearchPage })), undefined, 'Search', ); export const LazyNotifications = createLazyComponent( () => import('@/features/notifications/pages/NotificationsPage').then((m) => ({ default: m.NotificationsPage })), undefined, 'Notifications', ); export const LazyMarketplace = createLazyComponent( () => import('@/pages/marketplace/MarketplaceHome').then((m) => ({ default: m.MarketplaceHome })), undefined, 'Marketplace', ); export const LazyAnalytics = createLazyComponent( () => import('@/pages/AnalyticsPage').then((m) => ({ default: m.AnalyticsPage })), undefined, 'Analytics', ); export const LazyWebhooks = createLazyComponent( () => import('@/pages/WebhooksPage').then((m) => ({ default: m.WebhooksPage })), undefined, 'Webhooks', ); export const LazyAdminDashboard = createLazyComponent( () => import('@/pages/AdminDashboardPage').then((m) => ({ default: m.AdminDashboardPage })), undefined, 'Admin Dashboard', ); export const LazyDesignSystemDemo = createLazyComponent( () => import('@/pages/DesignSystemDemoPage').then((m) => ({ default: m.default })), undefined, 'Design System Demo', ); // New pages for navigation fix export const LazySocial = createLazyComponent( () => import('@/pages/SocialPage').then((m) => ({ default: m.SocialPage })), undefined, 'Social Feed', ); export const LazyGear = createLazyComponent( () => import('@/pages/GearPage').then((m) => ({ default: m.GearPage })), undefined, 'Gear Locker', ); export const LazyLive = createLazyComponent( () => import('@/pages/LivePage').then((m) => ({ default: m.LivePage })), undefined, 'Live Sessions', ); export const LazyEducation = createLazyComponent( () => import('@/pages/EducationPage').then((m) => ({ default: m.EducationPage })), undefined, 'Education', ); export const LazyQueue = createLazyComponent( () => import('@/pages/QueuePage').then((m) => ({ default: m.QueuePage })), undefined, 'Queue', ); export const LazyDeveloper = createLazyComponent( () => import('@/pages/DeveloperPage').then((m) => ({ default: m.DeveloperPage })), undefined, 'Developer API', );