/** * Analytics Module * * Provides unified analytics system for event tracking, page views, and user behavior. * Features: * - Event tracking * - Page view tracking * - User behavior tracking * - Custom events * - Integration with LiveComponents * - GDPR compliance */ import { Logger } from '../../core/logger.js'; /** * AnalyticsProvider - Base class for analytics providers */ export class AnalyticsProvider { constructor(config = {}) { this.config = config; this.enabled = config.enabled ?? true; } /** * Track event */ async track(eventName, properties = {}) { if (!this.enabled) return; // Override in subclasses } /** * Track page view */ async pageView(path, properties = {}) { if (!this.enabled) return; // Override in subclasses } /** * Identify user */ async identify(userId, traits = {}) { if (!this.enabled) return; // Override in subclasses } } /** * GoogleAnalyticsProvider - Google Analytics integration */ export class GoogleAnalyticsProvider extends AnalyticsProvider { constructor(config = {}) { super(config); this.measurementId = config.measurementId || config.gaId; } async track(eventName, properties = {}) { if (typeof gtag !== 'undefined') { gtag('event', eventName, properties); } } async pageView(path, properties = {}) { if (typeof gtag !== 'undefined') { gtag('config', this.measurementId, { page_path: path, ...properties }); } } } /** * CustomProvider - Custom analytics endpoint */ export class CustomProvider extends AnalyticsProvider { constructor(config = {}) { super(config); this.endpoint = config.endpoint || '/api/analytics'; } async track(eventName, properties = {}) { try { await fetch(this.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }, body: JSON.stringify({ type: 'event', name: eventName, properties, timestamp: Date.now() }) }); } catch (error) { Logger.error('[Analytics] Failed to track event', error); } } async pageView(path, properties = {}) { try { await fetch(this.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }, body: JSON.stringify({ type: 'page_view', path, properties, timestamp: Date.now() }) }); } catch (error) { Logger.error('[Analytics] Failed to track page view', error); } } } /** * Analytics - Unified analytics system */ export class Analytics { constructor(config = {}) { this.config = { enabled: config.enabled ?? true, providers: config.providers || [], gdprCompliant: config.gdprCompliant ?? true, requireConsent: config.requireConsent ?? false, consentGiven: config.consentGiven ?? false, anonymizeIp: config.anonymizeIp ?? true, ...config }; this.providers = []; this.eventQueue = []; this.userId = null; this.userTraits = {}; // Initialize providers this.initProviders(); // Track initial page view if (this.config.enabled && this.hasConsent()) { this.trackPageView(); } Logger.info('[Analytics] Initialized', { enabled: this.config.enabled, providers: this.providers.length, gdprCompliant: this.config.gdprCompliant }); } /** * Create a new Analytics instance */ static create(config = {}) { return new Analytics(config); } /** * Initialize providers */ initProviders() { for (const providerConfig of this.config.providers) { let provider; if (typeof providerConfig === 'string') { // Provider name if (providerConfig === 'google-analytics' || providerConfig === 'ga') { provider = new GoogleAnalyticsProvider({}); } else if (providerConfig === 'custom') { provider = new CustomProvider({}); } } else if (typeof providerConfig === 'object') { // Provider config if (providerConfig.type === 'google-analytics' || providerConfig.type === 'ga') { provider = new GoogleAnalyticsProvider(providerConfig); } else if (providerConfig.type === 'custom') { provider = new CustomProvider(providerConfig); } else if (providerConfig instanceof AnalyticsProvider) { provider = providerConfig; } } if (provider) { this.providers.push(provider); } } } /** * Check if consent is given (GDPR) */ hasConsent() { if (!this.config.requireConsent) { return true; } return this.config.consentGiven; } /** * Give consent (GDPR) */ giveConsent() { this.config.consentGiven = true; // Process queued events this.processEventQueue(); Logger.info('[Analytics] Consent given'); } /** * Revoke consent (GDPR) */ revokeConsent() { this.config.consentGiven = false; Logger.info('[Analytics] Consent revoked'); } /** * Track event */ async track(eventName, properties = {}) { if (!this.config.enabled || !this.hasConsent()) { // Queue event if consent required if (this.config.requireConsent && !this.config.consentGiven) { this.eventQueue.push({ type: 'event', name: eventName, properties }); } return; } const eventData = { name: eventName, properties: this.anonymizeData(properties), timestamp: Date.now(), userId: this.userId }; // Send to all providers for (const provider of this.providers) { try { await provider.track(eventName, eventData.properties); } catch (error) { Logger.error('[Analytics] Provider error', error); } } Logger.debug('[Analytics] Event tracked', eventData); // Trigger event this.triggerAnalyticsEvent('track', eventData); } /** * Track page view */ async trackPageView(path = null, properties = {}) { if (!this.config.enabled || !this.hasConsent()) { return; } const pagePath = path || window.location.pathname; const pageData = { path: pagePath, title: document.title, properties: this.anonymizeData(properties), timestamp: Date.now() }; // Send to all providers for (const provider of this.providers) { try { await provider.pageView(pagePath, pageData.properties); } catch (error) { Logger.error('[Analytics] Provider error', error); } } Logger.debug('[Analytics] Page view tracked', pageData); // Trigger event this.triggerAnalyticsEvent('page_view', pageData); } /** * Identify user */ async identify(userId, traits = {}) { if (!this.config.enabled || !this.hasConsent()) { return; } this.userId = userId; this.userTraits = { ...this.userTraits, ...traits }; // Send to all providers for (const provider of this.providers) { try { if (typeof provider.identify === 'function') { await provider.identify(userId, this.userTraits); } } catch (error) { Logger.error('[Analytics] Provider error', error); } } Logger.debug('[Analytics] User identified', { userId, traits: this.userTraits }); } /** * Track user behavior */ async trackBehavior(action, target, properties = {}) { await this.track('user_behavior', { action, target, ...properties }); } /** * Anonymize data for GDPR compliance */ anonymizeData(data) { if (!this.config.gdprCompliant) { return data; } const anonymized = { ...data }; // Anonymize IP if enabled if (this.config.anonymizeIp && anonymized.ip) { anonymized.ip = anonymized.ip.split('.').slice(0, 3).join('.') + '.0'; } // Remove PII if present const piiFields = ['email', 'phone', 'address', 'ssn', 'credit_card']; piiFields.forEach(field => { if (anonymized[field]) { delete anonymized[field]; } }); return anonymized; } /** * Process queued events */ processEventQueue() { while (this.eventQueue.length > 0) { const event = this.eventQueue.shift(); if (event.type === 'event') { this.track(event.name, event.properties); } } } /** * Trigger analytics event */ triggerAnalyticsEvent(type, data) { const event = new CustomEvent(`analytics:${type}`, { detail: data, bubbles: true }); window.dispatchEvent(event); } /** * Enable analytics */ enable() { this.config.enabled = true; Logger.info('[Analytics] Enabled'); } /** * Disable analytics */ disable() { this.config.enabled = false; Logger.info('[Analytics] Disabled'); } /** * Destroy analytics */ destroy() { this.providers = []; this.eventQueue = []; this.userId = null; this.userTraits = {}; Logger.info('[Analytics] Destroyed'); } }