Some checks failed
Build & Deploy Mintel Blog / build-and-deploy (push) Failing after 1m26s
90 lines
3.0 KiB
TypeScript
90 lines
3.0 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect } from 'react';
|
|
import { getDefaultAnalytics } from '../utils/analytics';
|
|
import { getDefaultErrorTracking } from '../utils/error-tracking';
|
|
|
|
export const Analytics: React.FC = () => {
|
|
useEffect(() => {
|
|
const analytics = getDefaultAnalytics();
|
|
const errorTracking = getDefaultErrorTracking();
|
|
|
|
// Track page load performance
|
|
const trackPageLoad = () => {
|
|
const perfData = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
|
|
if (perfData && typeof perfData.loadEventEnd === 'number' && typeof perfData.startTime === 'number') {
|
|
const loadTime = perfData.loadEventEnd - perfData.startTime;
|
|
analytics.trackPageLoad(
|
|
loadTime,
|
|
window.location.pathname,
|
|
navigator.userAgent
|
|
);
|
|
}
|
|
};
|
|
|
|
// Track outbound links
|
|
const trackOutboundLinks = () => {
|
|
document.querySelectorAll('a[href^="http"]').forEach(link => {
|
|
const anchor = link as HTMLAnchorElement;
|
|
if (!anchor.href.includes(window.location.hostname)) {
|
|
anchor.addEventListener('click', () => {
|
|
analytics.trackOutboundLink(anchor.href, anchor.textContent?.trim() || 'unknown');
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
// Track search
|
|
const trackSearch = () => {
|
|
const searchInput = document.querySelector('input[type="search"]') as HTMLInputElement;
|
|
if (searchInput) {
|
|
const handleSearch = (e: Event) => {
|
|
const target = e.target as HTMLInputElement;
|
|
if (target.value) {
|
|
analytics.trackSearch(target.value, window.location.pathname);
|
|
}
|
|
};
|
|
searchInput.addEventListener('search', handleSearch);
|
|
return () => searchInput.removeEventListener('search', handleSearch);
|
|
}
|
|
};
|
|
|
|
// Global error handler for error tracking
|
|
const handleGlobalError = (event: ErrorEvent) => {
|
|
errorTracking.captureException(event.error || event.message);
|
|
};
|
|
|
|
const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
|
|
errorTracking.captureException(event.reason);
|
|
};
|
|
|
|
window.addEventListener('error', handleGlobalError);
|
|
window.addEventListener('unhandledrejection', handleUnhandledRejection);
|
|
|
|
trackPageLoad();
|
|
trackOutboundLinks();
|
|
const cleanupSearch = trackSearch();
|
|
|
|
return () => {
|
|
if (cleanupSearch) cleanupSearch();
|
|
window.removeEventListener('error', handleGlobalError);
|
|
window.removeEventListener('unhandledrejection', handleUnhandledRejection);
|
|
};
|
|
}, []);
|
|
|
|
const analytics = getDefaultAnalytics();
|
|
const adapter = analytics.getAdapter();
|
|
const scriptTag = adapter.getScriptTag ? adapter.getScriptTag() : null;
|
|
|
|
if (!scriptTag) return null;
|
|
|
|
// We use dangerouslySetInnerHTML to inject the script tag from the adapter
|
|
// This is safe here because the script URLs and IDs come from our own config/env
|
|
return (
|
|
<div
|
|
dangerouslySetInnerHTML={{ __html: scriptTag }}
|
|
style={{ display: 'none' }}
|
|
/>
|
|
);
|
|
};
|