100 lines
2.3 KiB
TypeScript
100 lines
2.3 KiB
TypeScript
|
|
/**
|
||
|
|
* usePageTracking - Automatic page view tracking for React Router
|
||
|
|
*
|
||
|
|
* This hook automatically tracks page views when the route changes.
|
||
|
|
* Place it in your root layout component.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { useEffect, useRef } from 'react';
|
||
|
|
import { useLocation } from 'react-router-dom'; // or your router of choice
|
||
|
|
import { useAnalytics } from '@analytics/client/react';
|
||
|
|
|
||
|
|
interface PageTrackingOptions {
|
||
|
|
/**
|
||
|
|
* Extract page title from the current route.
|
||
|
|
* Default: Uses document.title
|
||
|
|
*/
|
||
|
|
getPageTitle?: (pathname: string) => string;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Additional metadata to include with every page view.
|
||
|
|
*/
|
||
|
|
metadata?: Record<string, unknown>;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Skip tracking for certain paths.
|
||
|
|
*/
|
||
|
|
excludePaths?: string[];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Track page views automatically on route changes.
|
||
|
|
*
|
||
|
|
* @example
|
||
|
|
* ```tsx
|
||
|
|
* function RootLayout({ children }) {
|
||
|
|
* usePageTracking();
|
||
|
|
* return <main>{children}</main>;
|
||
|
|
* }
|
||
|
|
* ```
|
||
|
|
*/
|
||
|
|
export function usePageTracking(options: PageTrackingOptions = {}) {
|
||
|
|
const { trackView } = useAnalytics();
|
||
|
|
const location = useLocation();
|
||
|
|
const previousPathRef = useRef<string | null>(null);
|
||
|
|
|
||
|
|
const {
|
||
|
|
getPageTitle = () => document.title,
|
||
|
|
metadata = {},
|
||
|
|
excludePaths = [],
|
||
|
|
} = options;
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
const currentPath = location.pathname;
|
||
|
|
|
||
|
|
// Skip if path is excluded
|
||
|
|
if (excludePaths.some((path) => currentPath.startsWith(path))) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Skip if same path (prevents double-tracking on hash changes)
|
||
|
|
if (previousPathRef.current === currentPath) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
previousPathRef.current = currentPath;
|
||
|
|
|
||
|
|
// Small delay to ensure document.title is updated
|
||
|
|
const timeoutId = setTimeout(() => {
|
||
|
|
trackView({
|
||
|
|
pageUrl: window.location.href,
|
||
|
|
pageTitle: getPageTitle(currentPath),
|
||
|
|
...metadata,
|
||
|
|
});
|
||
|
|
}, 0);
|
||
|
|
|
||
|
|
return () => clearTimeout(timeoutId);
|
||
|
|
}, [location.pathname, trackView, getPageTitle, metadata, excludePaths]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Example with custom page titles:
|
||
|
|
*
|
||
|
|
* ```tsx
|
||
|
|
* const PAGE_TITLES: Record<string, string> = {
|
||
|
|
* '/': 'Home',
|
||
|
|
* '/products': 'Products',
|
||
|
|
* '/about': 'About Us',
|
||
|
|
* };
|
||
|
|
*
|
||
|
|
* function RootLayout({ children }) {
|
||
|
|
* usePageTracking({
|
||
|
|
* getPageTitle: (pathname) => PAGE_TITLES[pathname] || 'My App',
|
||
|
|
* excludePaths: ['/admin', '/api'],
|
||
|
|
* });
|
||
|
|
*
|
||
|
|
* return <main>{children}</main>;
|
||
|
|
* }
|
||
|
|
* ```
|
||
|
|
*/
|