"use client"; import { useEffect, useRef } from 'react'; import { useCookieConsentStore } from '../../store/cookieConsentStore'; declare global { interface Window { dataLayer?: any[]; gtag?: (...args: any[]) => void; fbq?: any; _fbq?: any; ttq?: any; } } export default function ScriptManager() { const { record, isHydrated } = useCookieConsentStore(); const consentInitializedRef = useRef(false); const gaInjectedRef = useRef(false); const metaInjectedRef = useRef(false); const tiktokInjectedRef = useRef(false); // 1. Initialize Google Consent Mode v2 Defaults useEffect(() => { if (typeof window === 'undefined' || consentInitializedRef.current) return; consentInitializedRef.current = true; window.dataLayer = window.dataLayer || []; if (!window.gtag) { window.gtag = function () { window.dataLayer?.push(arguments); }; } // Default to 'denied' as required by GDPR/PDPA prior to user choice window.gtag('consent', 'default', { analytics_storage: 'denied', ad_storage: 'denied', ad_user_data: 'denied', ad_personalization: 'denied', }); }, []); // 2. Sync consent updates whenever state changes useEffect(() => { if (!isHydrated || typeof window === 'undefined') return; const { preferences, hasResponded } = record; if (window.gtag) { window.gtag('consent', 'update', { analytics_storage: hasResponded && preferences.analytics ? 'granted' : 'denied', ad_storage: hasResponded && preferences.marketing ? 'granted' : 'denied', ad_user_data: hasResponded && preferences.marketing ? 'granted' : 'denied', ad_personalization: hasResponded && preferences.marketing ? 'granted' : 'denied', }); } // Dispatch custom browser event for any other custom tags/scripts window.dispatchEvent( new CustomEvent('homaroma:consent-change', { detail: { hasResponded, preferences, }, }) ); // 3. Inject GA4 dynamically if enabled and configured const gaId = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID; if (gaId && hasResponded && preferences.analytics && !gaInjectedRef.current) { gaInjectedRef.current = true; const script = document.createElement('script'); script.src = `https://www.googletagmanager.com/gtag/js?id=${gaId}`; script.async = true; document.head.appendChild(script); window.gtag?.('js', new Date()); window.gtag?.('config', gaId, { anonymize_ip: true, }); } // 4. Inject Meta Pixel dynamically if enabled and configured const metaPixelId = process.env.NEXT_PUBLIC_META_PIXEL_ID; if (metaPixelId && hasResponded && preferences.marketing && !metaInjectedRef.current) { metaInjectedRef.current = true; (function (f: any, b: any, e: any, v: any, n?: any, t?: any, s?: any) { if (f.fbq) return; n = f.fbq = function () { n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments); }; if (!f._fbq) f._fbq = n; n.push = n; n.loaded = true; n.version = '2.0'; n.queue = []; t = b.createElement(e); t.async = true; t.src = v; s = b.getElementsByTagName(e)[0]; s.parentNode.insertBefore(t, s); })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js'); window.fbq('init', metaPixelId); window.fbq('track', 'PageView'); } // 5. Inject TikTok Pixel dynamically if enabled and configured const tiktokPixelId = process.env.NEXT_PUBLIC_TIKTOK_PIXEL_ID; if (tiktokPixelId && hasResponded && preferences.marketing && !tiktokInjectedRef.current) { tiktokInjectedRef.current = true; (function (w: any, d: any, t: any) { w.TiktokAnalyticsObject = t; const ttq = (w[t] = w[t] || []); ttq.methods = [ 'page', 'track', 'identify', 'instances', 'debug', 'on', 'off', 'once', 'ready', 'alias', 'group', 'enableCookie', 'disableCookie', ]; ttq.setAndDefer = function (t: any, e: any) { t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))); }; }; for (let i = 0; i < ttq.methods.length; i++) { ttq.setAndDefer(ttq, ttq.methods[i]); } ttq.instance = function (t: any) { const e = ttq._i[t] || []; for (let n = 0; n < ttq.methods.length; n++) { ttq.setAndDefer(e, ttq.methods[n]); } return e; }; ttq.load = function (e: any, n: any) { const i = 'https://analytics.tiktok.com/i18n/pixel/events.js'; ttq._i = ttq._i || {}; ttq._i[e] = []; ttq._i[e]._u = i; ttq._t = ttq._t || {}; ttq._t[e] = +new Date(); ttq._o = ttq._o || {}; ttq._o[e] = n || {}; const o = d.createElement('script'); o.type = 'text/javascript'; o.async = true; o.src = `${i}?sdkid=${e}&lib=${t}`; const a = d.getElementsByTagName('script')[0]; a.parentNode.insertBefore(o, a); }; })(window, document, 'ttq'); window.ttq?.load(tiktokPixelId); window.ttq?.page(); } }, [record, isHydrated]); return null; }