import React from "react"; import CookieBanner from "./CookieBanner"; export const CONSENT_COOKIE_NAME = "omniasr_transcription_consent"; // Declare gtag global function declare global { interface Window { gtag: (...args: any[]) => void; dataLayer: any[]; } } const Analytics = () => { const [analyticsEnabled, setAnalyticsEnabled] = React.useState(false); const [consentState, setConsentState] = React.useState(null); // In-memory fallback const [showBanner, setShowBanner] = React.useState(false); // Control banner visibility // Check if we're in iframe (like HuggingFace Spaces) const isInIframe = () => { try { return window.self !== window.top; } catch (e) { return true; } }; // Get consent with fallback chain: memory -> localStorage -> sessionStorage -> cookies const getConsent = (): boolean => { // First check in-memory state (for HF spaces that block all storage) if (consentState !== null) { return consentState; } // Try localStorage try { const localValue = window.localStorage.getItem(CONSENT_COOKIE_NAME); if (localValue !== null) { return localValue === "true"; } } catch (e) {} // Try sessionStorage try { const sessionValue = window.sessionStorage.getItem(CONSENT_COOKIE_NAME); if (sessionValue !== null) { return sessionValue === "true"; } } catch (e) {} // Try cookies try { return document.cookie.includes(`${CONSENT_COOKIE_NAME}=true`); } catch (e) {} return false; }; // Set consent with fallback chain const setConsent = (accepted: boolean) => { // Always set in-memory state first (works in all environments) setConsentState(accepted); // Try localStorage try { window.localStorage.setItem(CONSENT_COOKIE_NAME, accepted.toString()); } catch (e) {} // Try sessionStorage as fallback try { window.sessionStorage.setItem(CONSENT_COOKIE_NAME, accepted.toString()); } catch (e) {} // Try cookies (mainly for non-iframe environments) if (!isInIframe()) { try { const expires = new Date(); expires.setFullYear(expires.getFullYear() + 1); document.cookie = `${CONSENT_COOKIE_NAME}=${accepted}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`; } catch (e) {} } }; // Load gtag script dynamically const loadGtagScript = (gaId: string) => { return new Promise((resolve, reject) => { // Check if gtag is already loaded if (window.gtag) { resolve(); return; } // Create script element const script = document.createElement('script'); script.async = true; script.src = `https://www.googletagmanager.com/gtag/js?id=${gaId}`; script.onload = () => { // Initialize gtag window.dataLayer = window.dataLayer || []; window.gtag = function gtag() { window.dataLayer.push(arguments); }; window.gtag('js', new Date()); window.gtag('config', gaId, { // Settings for iframe environments send_page_view: false, // We'll send manually cookie_flags: 'max-age=7200;secure;samesite=none', // For iframe support }); console.log('GA: gtag script loaded'); resolve(); }; script.onerror = () => { console.error('❌ Failed to load gtag script'); reject(new Error('Failed to load gtag script')); }; document.head.appendChild(script); }); }; // Enable analytics if consent given const handleAcceptCookie = React.useCallback(() => { console.log('User accepted analytics cookies'); setConsent(true); setShowBanner(false); // Hide banner after acceptance const gaId = import.meta.env.VITE_REACT_APP_GOOGLE_ANALYTICS_ID; const analyticsEnabled = import.meta.env.VITE_ENABLE_ANALYTICS === 'true'; if (gaId && analyticsEnabled) { loadGtagScript(gaId) .then(() => { setAnalyticsEnabled(true); console.log('GA initialized successfully'); // Send initial pageview const pathname = window.location.pathname; window.gtag('event', 'page_view', { page_title: document.title, page_location: window.location.href, page_path: pathname, }); }) .catch((e) => { console.error('GA initialization failed:', e); }); } }, []); const handleDeclineCookie = React.useCallback(() => { console.log('User declined analytics cookies'); setConsent(false); setShowBanner(false); // Hide banner after decline }, []); // Check for existing consent on mount React.useEffect(() => { const existingConsent = getConsent(); if (existingConsent) { console.log('GA: Found existing consent, initializing...'); handleAcceptCookie(); setShowBanner(false); // Don't show banner if consent already exists } else { setShowBanner(true); // Show banner if no consent } }, [handleAcceptCookie]); // Note: pageview is now sent directly in handleAcceptCookie when gtag is loaded return showBanner ? ( ) : null; }; export default Analytics;