declare global { interface Window { gtag: (...args: unknown[]) => void; dataLayer: unknown[]; } } const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID || ''; export interface CookiePreferences { necessary: boolean; analytics: boolean; marketing: boolean; functionality: boolean; timestamp?: number; } const DEFAULT_PREFERENCES: CookiePreferences = { necessary: true, analytics: true, marketing: false, functionality: true, }; export function getDefaultPreferences(): CookiePreferences { return { ...DEFAULT_PREFERENCES }; } export function getStoredPreferences(): CookiePreferences | null { if (typeof window === 'undefined') return null; try { const stored = localStorage.getItem('novalon-cookie-preferences'); if (stored) { return JSON.parse(stored) as CookiePreferences; } } catch (e) { console.warn('[Analytics] Failed to read cookie preferences:', e); } return null; } export function storePreferences(preferences: CookiePreferences): void { if (typeof window === 'undefined') return; try { localStorage.setItem( 'novalon-cookie-preferences', JSON.stringify(preferences) ); } catch (e) { console.warn('[Analytics] Failed to store cookie preferences:', e); } } export function updateConsentDetailed(preferences: CookiePreferences): void { if (typeof window === 'undefined' || !window.gtag) return; window.gtag('consent', 'update', { analytics_storage: preferences.analytics ? 'granted' : 'denied', ad_storage: preferences.marketing ? 'granted' : 'denied', functionality_storage: preferences.functionality ? 'granted' : 'denied', }); } export function trackEvent( action: string, category: string, label?: string, value?: number ): void { if (typeof window === 'undefined' || !window.gtag || !GA_MEASUREMENT_ID) { return; } window.gtag('event', action, { event_category: category, event_label: label, event_value: value, send_to: GA_MEASUREMENT_ID, }); } export function trackButtonClick( buttonName: string, _pageLocation?: string ): void { trackEvent('button_click', 'engagement', buttonName, undefined); } export function trackError( errorType: string, message: string, fatal: boolean = false, additionalContext?: Record ): void { if (typeof window === 'undefined' || !window.gtag || !GA_MEASUREMENT_ID) { console.warn('[GA4] Error tracking not available:', { errorType, message }); return; } const errorData: Record = { description: `[${errorType}] ${message}`, fatal: fatal ? 'true' : 'false', url: typeof window !== 'undefined' ? window.location.href : '', timestamp: new Date().toISOString(), ...additionalContext, }; window.gtag('event', 'exception', { ...errorData, send_to: GA_MEASUREMENT_ID, }); if (process.env.NODE_ENV === 'development') { console.log('[GA4] Error tracked:', errorData); } } export function trackPageView(url: string, title: string): void { if (typeof window === 'undefined' || !window.gtag || !GA_MEASUREMENT_ID) { return; } window.gtag('config', GA_MEASUREMENT_ID, { page_path: url, page_title: title, }); } export function trackPerformance( metricName: string, value: number, category: string = 'web_vitals' ): void { if (typeof window === 'undefined' || !window.gtag || !GA_MEASUREMENT_ID) { return; } window.gtag('event', metricName, { event_category: category, event_value: Math.round(value), value: Math.round(value), send_to: GA_MEASUREMENT_ID, }); } export function trackContactForm( formData: { name: string; email: string; company: string } | string, success?: boolean ): void { if (typeof formData === 'string') { trackEvent('form_submit', 'contact', formData, success ? 1 : 0); } else { trackEvent('form_submit', 'contact', formData.company, success !== false ? 1 : 0); } if (success !== false) { trackConversion('contact_form_submit', 1); } } export function trackConversion(conversionLabel: string, value?: number): void { if (typeof window === 'undefined' || !window.gtag || !GA_MEASUREMENT_ID) { return; } window.gtag('event', 'conversion', { send_to: GA_MEASUREMENT_ID, transaction_id: `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`, value: value || 1, currency: 'CNY', conversion_label: conversionLabel, }); } export function trackOutboundLink(url: string, _linkText?: string): void { trackEvent('outbound_click', 'engagement', url); if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) { window.gtag('event', 'click', { event_category: 'outbound', event_label: url, transport_type: 'beacon', send_to: GA_MEASUREMENT_ID, }); } } export function trackScrollDepth(percentage: number, _maxScroll?: number): void { trackEvent(`scroll_${percentage}`, 'engagement', `${percentage}%`); }