- Improve localStorage access in ActivityFeed, ChatWidget, and AdminPage with try-catch blocks to handle potential errors gracefully. - Update performance tracking in AnalyticsProvider and analytics.ts to ensure robust error handling and prevent failures from affecting user experience. - Refactor Web Vitals tracking to include error handling for observer initialization and data collection. - Ensure consistent handling of hydration mismatches in components like BackgroundBlobs and ChatWidget to improve rendering reliability.
136 lines
3.9 KiB
TypeScript
136 lines
3.9 KiB
TypeScript
// Analytics utilities for Umami with Performance Tracking
|
|
declare global {
|
|
interface Window {
|
|
umami?: {
|
|
track: (event: string, data?: Record<string, unknown>) => void;
|
|
};
|
|
}
|
|
}
|
|
|
|
export interface PerformanceMetric {
|
|
name: string;
|
|
value: number;
|
|
url: string;
|
|
timestamp: number;
|
|
userAgent?: string;
|
|
}
|
|
|
|
export interface WebVitalsMetric {
|
|
name: 'CLS' | 'FID' | 'FCP' | 'LCP' | 'TTFB';
|
|
value: number;
|
|
delta: number;
|
|
id: string;
|
|
url: string;
|
|
}
|
|
|
|
// Track custom events to Umami
|
|
export const trackEvent = (event: string, data?: Record<string, unknown>) => {
|
|
if (typeof window !== 'undefined' && window.umami) {
|
|
window.umami.track(event, {
|
|
...data,
|
|
timestamp: Date.now(),
|
|
url: window.location.pathname,
|
|
});
|
|
}
|
|
};
|
|
|
|
// Track performance metrics
|
|
export const trackPerformance = (metric: PerformanceMetric) => {
|
|
trackEvent('performance', {
|
|
metric: metric.name,
|
|
value: Math.round(metric.value),
|
|
url: metric.url,
|
|
userAgent: metric.userAgent,
|
|
});
|
|
};
|
|
|
|
// Track Web Vitals
|
|
export const trackWebVitals = (metric: WebVitalsMetric) => {
|
|
trackEvent('web-vitals', {
|
|
name: metric.name,
|
|
value: Math.round(metric.value),
|
|
delta: Math.round(metric.delta),
|
|
id: metric.id,
|
|
url: metric.url,
|
|
});
|
|
};
|
|
|
|
// Track page load performance
|
|
export const trackPageLoad = () => {
|
|
if (typeof window === 'undefined' || typeof performance === 'undefined') return;
|
|
|
|
try {
|
|
const navigationEntries = performance.getEntriesByType('navigation');
|
|
const navigation = navigationEntries[0] as PerformanceNavigationTiming | undefined;
|
|
|
|
if (navigation && navigation.loadEventEnd && navigation.fetchStart) {
|
|
trackPerformance({
|
|
name: 'page-load',
|
|
value: navigation.loadEventEnd - navigation.fetchStart,
|
|
url: window.location.pathname,
|
|
timestamp: Date.now(),
|
|
userAgent: navigator.userAgent,
|
|
});
|
|
|
|
// Track individual timing phases
|
|
trackEvent('page-timing', {
|
|
dns: navigation.domainLookupEnd && navigation.domainLookupStart
|
|
? Math.round(navigation.domainLookupEnd - navigation.domainLookupStart)
|
|
: 0,
|
|
tcp: navigation.connectEnd && navigation.connectStart
|
|
? Math.round(navigation.connectEnd - navigation.connectStart)
|
|
: 0,
|
|
request: navigation.responseStart && navigation.requestStart
|
|
? Math.round(navigation.responseStart - navigation.requestStart)
|
|
: 0,
|
|
response: navigation.responseEnd && navigation.responseStart
|
|
? Math.round(navigation.responseEnd - navigation.responseStart)
|
|
: 0,
|
|
dom: navigation.domContentLoadedEventEnd && navigation.responseEnd
|
|
? Math.round(navigation.domContentLoadedEventEnd - navigation.responseEnd)
|
|
: 0,
|
|
load: navigation.loadEventEnd && navigation.domContentLoadedEventEnd
|
|
? Math.round(navigation.loadEventEnd - navigation.domContentLoadedEventEnd)
|
|
: 0,
|
|
url: window.location.pathname,
|
|
});
|
|
}
|
|
} catch (error) {
|
|
// Silently fail - performance tracking is not critical
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.warn('Error tracking page load:', error);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Track API response times
|
|
export const trackApiCall = (endpoint: string, duration: number, status: number) => {
|
|
if (typeof window === 'undefined') return;
|
|
trackEvent('api-call', {
|
|
endpoint,
|
|
duration: Math.round(duration),
|
|
status,
|
|
url: window.location.pathname,
|
|
});
|
|
};
|
|
|
|
// Track user interactions
|
|
export const trackInteraction = (action: string, element?: string) => {
|
|
if (typeof window === 'undefined') return;
|
|
trackEvent('interaction', {
|
|
action,
|
|
element,
|
|
url: window.location.pathname,
|
|
});
|
|
};
|
|
|
|
// Track errors
|
|
export const trackError = (error: string, context?: string) => {
|
|
if (typeof window === 'undefined') return;
|
|
trackEvent('error', {
|
|
error,
|
|
context,
|
|
url: window.location.pathname,
|
|
});
|
|
};
|