import { useState, useEffect, useCallback } from 'react'; /** * Hook pour précharger les routes * @param routePath - Le chemin de la route à précharger * @param delay - Délai avant le préchargement (ms) */ export function useRoutePreload(routePath: string, delay: number = 0) { const [isPreloading, setIsPreloading] = useState(false); const [isPreloaded, setIsPreloaded] = useState(false); const preloadRoute = useCallback(async () => { if (isPreloaded) return; setIsPreloading(true); try { // Simuler le préchargement de la route await new Promise(resolve => setTimeout(resolve, delay)); // Ici, vous pourriez importer dynamiquement le composant // const component = await import(`@/pages${routePath}`); setIsPreloaded(true); } catch (error) { console.error('Error preloading route:', error); } finally { setIsPreloading(false); } }, [routePath, delay, isPreloaded]); return { preloadRoute, isPreloading, isPreloaded }; } /** * Hook pour gérer les performances et optimisations * @returns Fonctions d'optimisation */ export function usePerformanceOptimization() { const [isVisible, setIsVisible] = useState(true); useEffect(() => { const handleVisibilityChange = () => { setIsVisible(!document.hidden); }; document.addEventListener('visibilitychange', handleVisibilityChange); return () => { document.removeEventListener('visibilitychange', handleVisibilityChange); }; }, []); const optimizeForVisibility = useCallback((callback: () => void) => { if (isVisible) { callback(); } }, [isVisible]); const throttle = useCallback( any>( func: T, delay: number ): T => { let timeoutId: NodeJS.Timeout | null = null; let lastExecTime = 0; return ((...args: Parameters) => { const currentTime = Date.now(); if (currentTime - lastExecTime > delay) { func(...args); lastExecTime = currentTime; } else { if (timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => { func(...args); lastExecTime = Date.now(); }, delay - (currentTime - lastExecTime)); } }) as T; }, []); const debounce = useCallback( any>( func: T, delay: number ): T => { let timeoutId: NodeJS.Timeout | null = null; return ((...args: Parameters) => { if (timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => func(...args), delay); }) as T; }, []); return { isVisible, optimizeForVisibility, throttle, debounce, }; } /** * Hook pour gérer les erreurs de manière centralisée * @param onError - Callback appelé en cas d'erreur * @returns Fonctions de gestion d'erreur */ export function useErrorHandler(onError?: (error: Error, errorInfo?: any) => void) { const [error, setError] = useState(null); const handleError = useCallback((error: Error, errorInfo?: any) => { setError(error); onError?.(error, errorInfo); // Log l'erreur pour le monitoring console.error('Error caught by useErrorHandler:', error, errorInfo); }, [onError]); const clearError = useCallback(() => { setError(null); }, []); const withErrorHandling = useCallback( any>( fn: T ): T => { return ((...args: Parameters) => { try { const result = fn(...args); // Si c'est une Promise, gérer les erreurs asynchrones if (result instanceof Promise) { return result.catch((error) => { handleError(error); throw error; }); } return result; } catch (error) { handleError(error as Error); throw error; } }) as T; }, [handleError]); return { error, handleError, clearError, withErrorHandling, }; } /** * Hook pour gérer les états de chargement * @param initialState - État initial * @returns Fonctions de gestion des états */ export function useLoadingState(initialState: boolean = false) { const [isLoading, setIsLoading] = useState(initialState); const [loadingStates, setLoadingStates] = useState>({}); const setLoading = useCallback((loading: boolean) => { setIsLoading(loading); }, []); const setLoadingFor = useCallback((key: string, loading: boolean) => { setLoadingStates(prev => ({ ...prev, [key]: loading, })); }, []); const isLoadingFor = useCallback((key: string) => { return loadingStates[key] || false; }, [loadingStates]); const withLoading = useCallback(async ( asyncFn: () => Promise, key?: string ): Promise => { try { if (key) { setLoadingFor(key, true); } else { setLoading(true); } const result = await asyncFn(); return result; } finally { if (key) { setLoadingFor(key, false); } else { setLoading(false); } } }, [setLoading, setLoadingFor]); return { isLoading, loadingStates, setLoading, setLoadingFor, isLoadingFor, withLoading, }; }