@optic7409/resolvo-analytics
Version:
Simplified analytics client library for Next.js with automatic SSR handling, one-line integration, and comprehensive tracking
162 lines (161 loc) • 7.48 kB
JavaScript
import { useEffect, useState } from 'react';
import { AnalyticsClient } from '../../core/AnalyticsClient';
import { detectEnvironment, shouldEnableAnalytics } from '../../utils/environment';
let globalClient = null;
let isInitialized = false;
export function PageTracker({ config }) {
const [isReady, setIsReady] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
// SSR Safety: Don't run on server unless explicitly enabled
if (typeof window === 'undefined' && !config.ssr) {
return;
}
// Check if analytics should be enabled
if (!shouldEnableAnalytics(config)) {
return;
}
try {
// Initialize client if not already done
if (!globalClient && !isInitialized) {
globalClient = new AnalyticsClient(config);
isInitialized = true;
if (config.debug) {
console.log('[Resolvo Analytics] Initialized with config:', config);
}
}
// Track initial page load
const trackCurrentPage = () => {
if (typeof window !== 'undefined' && globalClient) {
const url = window.location.href;
const title = document.title;
globalClient.trackPageView(url, title).catch(err => {
if (config.debug) {
console.error('[Resolvo Analytics] Error tracking page view:', err);
}
});
}
};
// Track initial page after a small delay to ensure everything is loaded
const initialTimer = setTimeout(() => {
trackCurrentPage();
setIsReady(true);
}, 100);
// Setup route change tracking based on framework
const env = detectEnvironment();
let cleanup;
if (env.framework === 'nextjs') {
// Next.js specific route tracking
if (env.routerType === 'app') {
// App Router - use navigation events
const handleRouteChange = () => {
setTimeout(() => {
if (globalClient) {
const url = window.location.href;
const title = document.title;
globalClient.trackPageView(url, title).catch(err => {
if (config.debug) {
console.error('[Resolvo Analytics] Error tracking route change:', err);
}
});
}
}, 100);
};
// Listen for navigation events
window.addEventListener('popstate', handleRouteChange);
// For App Router, we also need to listen for pushState/replaceState
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = function (...args) {
originalPushState.apply(history, args);
handleRouteChange();
};
history.replaceState = function (...args) {
originalReplaceState.apply(history, args);
handleRouteChange();
};
cleanup = () => {
window.removeEventListener('popstate', handleRouteChange);
history.pushState = originalPushState;
history.replaceState = originalReplaceState;
};
}
else {
// Pages Router - use Next.js router events
try {
const { useRouter } = require('next/router');
const router = useRouter();
const handleRouteChange = (url) => {
setTimeout(() => {
if (globalClient) {
const title = document.title;
globalClient.trackPageView(url, title).catch(err => {
if (config.debug) {
console.error('[Resolvo Analytics] Error tracking route change:', err);
}
});
}
}, 100);
};
router.events.on('routeChangeComplete', handleRouteChange);
cleanup = () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}
catch (err) {
if (config.debug) {
console.warn('[Resolvo Analytics] Could not set up Next.js router tracking:', err);
}
}
}
}
else {
// Generic React/SPA route tracking
const handleRouteChange = () => {
setTimeout(() => {
if (globalClient) {
const url = window.location.href;
const title = document.title;
globalClient.trackPageView(url, title).catch(err => {
if (config.debug) {
console.error('[Resolvo Analytics] Error tracking route change:', err);
}
});
}
}, 100);
};
window.addEventListener('popstate', handleRouteChange);
cleanup = () => {
window.removeEventListener('popstate', handleRouteChange);
};
}
// Provide global access to analytics
if (typeof window !== 'undefined' && globalClient) {
window.analytics = {
track: (event, properties) => globalClient?.track(event, properties),
identify: (userId, properties) => globalClient?.identify(userId, properties),
trackPageView: (url, title) => globalClient?.trackPageView(url, title),
client: globalClient
};
}
return () => {
clearTimeout(initialTimer);
if (cleanup) {
cleanup();
}
};
}
catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
setError(errorMessage);
if (config.debug) {
console.error('[Resolvo Analytics] Initialization error:', err);
}
}
}, [config]);
// Show error in development
if (error && config.debug && typeof window !== 'undefined') {
console.error('[Resolvo Analytics] Error:', error);
}
return null; // This component doesn't render anything
}