Amba-Agent-App/lib/navigation/routerLoader.ts
2026-01-16 00:22:35 +03:00

94 lines
3.1 KiB
TypeScript

import { InteractionManager } from 'react-native';
import { router } from 'expo-router';
import { showGlobalLoader, hideGlobalLoader } from '../stores/uiStore';
let loaderEnhancementEnabled = false;
// Performance monitoring (only in dev)
const isDev = process.env.NODE_ENV !== 'production';
const perfLogs: Record<string, number[]> = {};
const logPerformance = (methodName: string, duration: number) => {
if (!isDev) return;
if (!perfLogs[methodName]) {
perfLogs[methodName] = [];
}
perfLogs[methodName].push(duration);
// Log average every 5 calls
if (perfLogs[methodName].length % 5 === 0) {
const avg = perfLogs[methodName].reduce((a, b) => a + b, 0) / perfLogs[methodName].length;
console.log(`[nav-perf] ${methodName}: avg ${avg.toFixed(2)}ms (${perfLogs[methodName].length} calls)`);
}
};
const scheduleHide = () => {
// Use requestIdleCallback if available, otherwise InteractionManager
if (typeof requestIdleCallback !== 'undefined') {
requestIdleCallback(() => {
hideGlobalLoader();
}, { timeout: 100 });
} else {
InteractionManager.runAfterInteractions(() => {
hideGlobalLoader();
});
}
};
const wrapNavigationMethod = <T extends (...args: any[]) => any>(
methodName: string,
originalMethod: T
): T => {
const wrapped = ((...args: Parameters<T>) => {
const startTime = isDev && typeof performance !== 'undefined' ? performance.now() : 0;
console.log(`[router-loader] ${methodName} invoked`);
// Show loader after a small delay to avoid flicker on fast navigations
const loaderTimeout = setTimeout(() => {
showGlobalLoader();
}, 100);
try {
const result = originalMethod(...args);
// Clear loader timeout and schedule hide
clearTimeout(loaderTimeout);
scheduleHide();
if (isDev && typeof performance !== 'undefined') {
const duration = performance.now() - startTime;
logPerformance(methodName, duration);
if (duration > 300) {
console.warn(`[nav-perf] Slow navigation: ${methodName} took ${duration.toFixed(2)}ms`);
}
}
return result;
} catch (error) {
clearTimeout(loaderTimeout);
hideGlobalLoader();
throw error;
}
}) as T;
return wrapped;
};
export const enableRouterLoader = () => {
if (loaderEnhancementEnabled) {
return;
}
loaderEnhancementEnabled = true;
const originalPush = router.push.bind(router);
const originalReplace = router.replace.bind(router);
const originalNavigate = router.navigate.bind(router);
const originalBack = router.back.bind(router);
(router as any).push = wrapNavigationMethod('push', originalPush);
(router as any).replace = wrapNavigationMethod('replace', originalReplace);
(router as any).navigate = wrapNavigationMethod('navigate', originalNavigate);
(router as any).back = wrapNavigationMethod('back', originalBack);
};