import { useEffect, useRef } from 'react';
import { getAnalytics } from '../core/AnalyticsManager';
/**
* Hook that auto-tracks screen views from React Navigation.
*
* Attach the returned `onStateChange` and `ref` to your NavigationContainer:
*
* ```tsx
* const { ref, onStateChange } = useReactNavigationTracking();
*
*
* ...
*
* ```
*/
export function useReactNavigationTracking(options?: {
/** Custom function to extract screen name from navigation state */
getActiveRouteName?: (state: any) => string | undefined;
/** Extra properties to attach to every screen event */
extraProperties?: Record;
}) {
const navigationRef = useRef(null);
const routeNameRef = useRef(undefined);
const getActiveRouteName = options?.getActiveRouteName ?? defaultGetActiveRouteName;
const onStateChange = (state: any) => {
const currentRoute = getActiveRouteName(state);
const previousRoute = routeNameRef.current;
if (currentRoute && currentRoute !== previousRoute) {
try {
getAnalytics().screen(currentRoute, {
previous_screen: previousRoute,
...options?.extraProperties,
});
} catch {
// Analytics not yet initialized — skip silently
}
}
routeNameRef.current = currentRoute;
};
useEffect(() => {
// Track initial screen on mount
if (navigationRef.current) {
const state = navigationRef.current.getRootState?.();
if (state) {
routeNameRef.current = getActiveRouteName(state);
if (routeNameRef.current) {
try {
getAnalytics().screen(routeNameRef.current, options?.extraProperties);
} catch {
// ignore
}
}
}
}
}, []);
return { ref: navigationRef, onStateChange };
}
/**
* Recursively finds the active route name from a navigation state object.
*/
function defaultGetActiveRouteName(state: any): string | undefined {
if (!state) return undefined;
const route = state.routes?.[state.index];
if (!route) return undefined;
if (route.state) {
return defaultGetActiveRouteName(route.state);
}
return route.name;
}
/**
* Standalone helper: get active screen name from navigation state.
* Useful if you need to read the screen name outside of a hook.
*/
export { defaultGetActiveRouteName as getActiveRouteName };