/** * Analytics utilities and tracking setup * Supports Google Analytics, Plausible, and custom tracking */ // Types for analytics events export interface AnalyticsEvent { action: string category: string label?: string value?: number } export interface PageViewEvent { page_title: string page_location: string page_path: string } export interface CustomEvent { event_name: string [key: string]: any } // Analytics providers configuration interface AnalyticsConfig { googleAnalytics?: { measurementId: string enabled: boolean } plausible?: { domain: string enabled: boolean } customTracking?: { enabled: boolean endpoint?: string } debug?: boolean } class Analytics { private config: AnalyticsConfig private isInitialized = false constructor(config: AnalyticsConfig) { this.config = config } // Initialize analytics init() { if (this.isInitialized || typeof window === 'undefined') return // Initialize Google Analytics if (this.config.googleAnalytics?.enabled && this.config.googleAnalytics.measurementId) { this.initGoogleAnalytics(this.config.googleAnalytics.measurementId) } // Initialize Plausible if (this.config.plausible?.enabled && this.config.plausible.domain) { this.initPlausible(this.config.plausible.domain) } this.isInitialized = true if (this.config.debug) { console.log('Analytics initialized with config:', this.config) } } // Initialize Google Analytics private initGoogleAnalytics(measurementId: string) { // Load gtag script const script1 = document.createElement('script') script1.async = true script1.src = `https://www.googletagmanager.com/gtag/js?id=${measurementId}` document.head.appendChild(script1) // Initialize gtag const script2 = document.createElement('script') script2.innerHTML = ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '${measurementId}', { page_title: document.title, page_location: window.location.href, }); ` document.head.appendChild(script2) // Make gtag available globally ;(window as any).gtag = (window as any).gtag || function () { ;(window as any).dataLayer = (window as any).dataLayer || [] ;(window as any).dataLayer.push(arguments) } } // Initialize Plausible private initPlausible(domain: string) { const script = document.createElement('script') script.defer = true script.setAttribute('data-domain', domain) script.src = 'https://plausible.io/js/script.js' document.head.appendChild(script) } // Track page view pageView(event: Partial = {}) { if (typeof window === 'undefined') return const pageViewData = { page_title: document.title, page_location: window.location.href, page_path: window.location.pathname, ...event, } // Google Analytics if (this.config.googleAnalytics?.enabled && (window as any).gtag) { ;(window as any).gtag('config', this.config.googleAnalytics.measurementId, { page_title: pageViewData.page_title, page_location: pageViewData.page_location, }) } // Plausible (automatically tracks page views) // Custom tracking if (this.config.customTracking?.enabled) { this.customTrack('page_view', pageViewData) } if (this.config.debug) { console.log('Page view tracked:', pageViewData) } } // Track custom event track(eventName: string, properties: Record = {}) { if (typeof window === 'undefined') return // Google Analytics if (this.config.googleAnalytics?.enabled && (window as any).gtag) { ;(window as any).gtag('event', eventName, properties) } // Plausible if (this.config.plausible?.enabled && (window as any).plausible) { ;(window as any).plausible(eventName, { props: properties }) } // Custom tracking if (this.config.customTracking?.enabled) { this.customTrack(eventName, properties) } if (this.config.debug) { console.log('Event tracked:', eventName, properties) } } // Track user signup trackSignup(method: string = 'email') { this.track('sign_up', { method }) } // Track user login trackLogin(method: string = 'email') { this.track('login', { method }) } // Track user logout trackLogout() { this.track('logout') } // Track form submission trackFormSubmit(formName: string, success: boolean = true) { this.track('form_submit', { form_name: formName, success, }) } // Track button click trackButtonClick(buttonName: string, location?: string) { this.track('button_click', { button_name: buttonName, location, }) } // Track search trackSearch(searchTerm: string, resultCount?: number) { this.track('search', { search_term: searchTerm, result_count: resultCount, }) } // Track file download trackDownload(fileName: string, fileType?: string) { this.track('file_download', { file_name: fileName, file_type: fileType, }) } // Custom tracking implementation private async customTrack(eventName: string, properties: Record) { if (!this.config.customTracking?.endpoint) return try { await fetch(this.config.customTracking.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ event: eventName, properties: { ...properties, timestamp: new Date().toISOString(), user_agent: navigator.userAgent, url: window.location.href, }, }), }) } catch (error) { if (this.config.debug) { console.error('Custom tracking failed:', error) } } } // Identify user identify(userId: string, traits: Record = {}) { // Google Analytics if (this.config.googleAnalytics?.enabled && (window as any).gtag) { ;(window as any).gtag('config', this.config.googleAnalytics.measurementId, { user_id: userId, custom_map: traits, }) } // Custom tracking if (this.config.customTracking?.enabled) { this.customTrack('identify', { user_id: userId, traits }) } if (this.config.debug) { console.log('User identified:', userId, traits) } } } // Create analytics instance const analyticsConfig: AnalyticsConfig = { googleAnalytics: { measurementId: process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID || '', enabled: !!(process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID && process.env.NODE_ENV === 'production'), }, plausible: { domain: process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN || '', enabled: !!(process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN && process.env.NODE_ENV === 'production'), }, customTracking: { enabled: false, endpoint: process.env.NEXT_PUBLIC_ANALYTICS_ENDPOINT, }, debug: process.env.NODE_ENV === 'development', } export const analytics = new Analytics(analyticsConfig) // React hook for analytics import { useEffect } from 'react' import { usePathname } from 'next/navigation' export function useAnalytics() { const pathname = usePathname() useEffect(() => { analytics.init() }, []) useEffect(() => { analytics.pageView({ page_path: pathname, }) }, [pathname]) return analytics } // Higher-order component for analytics import React from 'react' export function withAnalytics

(Component: React.ComponentType

) { return function AnalyticsWrapper(props: P) { useAnalytics() return } } // Export analytics instance export default analytics