2025-12-03 21:56:50 +00:00
|
|
|
import { useState, useEffect, useCallback } from 'react';
|
2026-01-07 09:35:04 +00:00
|
|
|
import { logger } from '@/utils/logger';
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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);
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
try {
|
|
|
|
|
// Simuler le préchargement de la route
|
2025-12-13 02:34:34 +00:00
|
|
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
// Ici, vous pourriez importer dynamiquement le composant
|
|
|
|
|
// const component = await import(`@/pages${routePath}`);
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
setIsPreloaded(true);
|
|
|
|
|
} catch (error) {
|
2026-01-07 09:35:04 +00:00
|
|
|
logger.error('Error preloading route', {
|
2026-01-13 18:47:57 +00:00
|
|
|
error: error instanceof Error ? error.message : String(error),
|
|
|
|
|
stack: error instanceof Error ? error.stack : undefined,
|
|
|
|
|
routePath,
|
2026-01-07 09:35:04 +00:00
|
|
|
});
|
2025-12-03 21:56:50 +00:00
|
|
|
} 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);
|
|
|
|
|
};
|
|
|
|
|
}, []);
|
|
|
|
|
|
2025-12-13 02:34:34 +00:00
|
|
|
const optimizeForVisibility = useCallback(
|
|
|
|
|
(callback: () => void) => {
|
|
|
|
|
if (isVisible) {
|
|
|
|
|
callback();
|
2025-12-03 21:56:50 +00:00
|
|
|
}
|
2025-12-13 02:34:34 +00:00
|
|
|
},
|
|
|
|
|
[isVisible],
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
2025-12-13 02:34:34 +00:00
|
|
|
const throttle = useCallback(
|
|
|
|
|
<T extends (...args: any[]) => any>(func: T, delay: number): T => {
|
|
|
|
|
let timeoutId: NodeJS.Timeout | null = null;
|
|
|
|
|
let lastExecTime = 0;
|
2025-12-03 21:56:50 +00:00
|
|
|
|
2025-12-13 02:34:34 +00:00
|
|
|
return ((...args: Parameters<T>) => {
|
|
|
|
|
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(
|
|
|
|
|
<T extends (...args: any[]) => any>(func: T, delay: number): T => {
|
|
|
|
|
let timeoutId: NodeJS.Timeout | null = null;
|
|
|
|
|
|
|
|
|
|
return ((...args: Parameters<T>) => {
|
|
|
|
|
if (timeoutId) {
|
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
|
}
|
|
|
|
|
timeoutId = setTimeout(() => func(...args), delay);
|
|
|
|
|
}) as T;
|
|
|
|
|
},
|
|
|
|
|
[],
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
*/
|
2025-12-13 02:34:34 +00:00
|
|
|
export function useErrorHandler(
|
|
|
|
|
onError?: (error: Error, errorInfo?: any) => void,
|
|
|
|
|
) {
|
2025-12-03 21:56:50 +00:00
|
|
|
const [error, setError] = useState<Error | null>(null);
|
|
|
|
|
|
2025-12-13 02:34:34 +00:00
|
|
|
const handleError = useCallback(
|
|
|
|
|
(error: Error, errorInfo?: any) => {
|
|
|
|
|
setError(error);
|
|
|
|
|
onError?.(error, errorInfo);
|
|
|
|
|
|
|
|
|
|
// Log l'erreur pour le monitoring
|
2026-01-07 09:35:04 +00:00
|
|
|
logger.error('Error caught by useErrorHandler', {
|
2026-01-13 18:47:57 +00:00
|
|
|
error: error.message,
|
|
|
|
|
stack: error.stack,
|
|
|
|
|
errorInfo,
|
2026-01-07 09:35:04 +00:00
|
|
|
});
|
2025-12-13 02:34:34 +00:00
|
|
|
},
|
|
|
|
|
[onError],
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
const clearError = useCallback(() => {
|
|
|
|
|
setError(null);
|
|
|
|
|
}, []);
|
|
|
|
|
|
2025-12-13 02:34:34 +00:00
|
|
|
const withErrorHandling = useCallback(
|
|
|
|
|
<T extends (...args: any[]) => any>(fn: T): T => {
|
|
|
|
|
return ((...args: Parameters<T>) => {
|
|
|
|
|
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;
|
2025-12-03 21:56:50 +00:00
|
|
|
}
|
2025-12-13 02:34:34 +00:00
|
|
|
}) as T;
|
|
|
|
|
},
|
|
|
|
|
[handleError],
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
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);
|
2025-12-13 02:34:34 +00:00
|
|
|
const [loadingStates, setLoadingStates] = useState<Record<string, boolean>>(
|
|
|
|
|
{},
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
const setLoading = useCallback((loading: boolean) => {
|
|
|
|
|
setIsLoading(loading);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const setLoadingFor = useCallback((key: string, loading: boolean) => {
|
2025-12-13 02:34:34 +00:00
|
|
|
setLoadingStates((prev) => ({
|
2025-12-03 21:56:50 +00:00
|
|
|
...prev,
|
|
|
|
|
[key]: loading,
|
|
|
|
|
}));
|
|
|
|
|
}, []);
|
|
|
|
|
|
2025-12-13 02:34:34 +00:00
|
|
|
const isLoadingFor = useCallback(
|
|
|
|
|
(key: string) => {
|
|
|
|
|
return loadingStates[key] || false;
|
|
|
|
|
},
|
|
|
|
|
[loadingStates],
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
2025-12-13 02:34:34 +00:00
|
|
|
const withLoading = useCallback(
|
|
|
|
|
async <T>(asyncFn: () => Promise<T>, key?: string): Promise<T> => {
|
|
|
|
|
try {
|
|
|
|
|
if (key) {
|
|
|
|
|
setLoadingFor(key, true);
|
|
|
|
|
} else {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const result = await asyncFn();
|
|
|
|
|
return result;
|
|
|
|
|
} finally {
|
|
|
|
|
if (key) {
|
|
|
|
|
setLoadingFor(key, false);
|
|
|
|
|
} else {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
2025-12-03 21:56:50 +00:00
|
|
|
}
|
2025-12-13 02:34:34 +00:00
|
|
|
},
|
|
|
|
|
[setLoading, setLoadingFor],
|
|
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
isLoading,
|
|
|
|
|
loadingStates,
|
|
|
|
|
setLoading,
|
|
|
|
|
setLoadingFor,
|
|
|
|
|
isLoadingFor,
|
|
|
|
|
withLoading,
|
|
|
|
|
};
|
2025-12-13 02:34:34 +00:00
|
|
|
}
|