GA integration
This commit is contained in:
+3
-2
@@ -12,8 +12,9 @@ const CONFIG = {
|
||||
WEBSITE_URL: 'https://portfoliojournal.app',
|
||||
EFFECTIVE_DATE: 'today',
|
||||
COPYRIGHT_YEAR: new Date().getFullYear(),
|
||||
ENABLE_ANALYTICS: false,
|
||||
ANALYTICS_ID: '', // Add your analytics ID if enabled
|
||||
ENABLE_ANALYTICS: true,
|
||||
ANALYTICS_ID: 'G-R3YRQZ8XZ7', // GA4 Measurement ID
|
||||
ANALYTICS_DEBUG: false, // When true, logs events and marks GA events for DebugView
|
||||
|
||||
// Social links (optional)
|
||||
SOCIAL: {
|
||||
|
||||
+99
-3
@@ -7,8 +7,18 @@
|
||||
'use strict';
|
||||
|
||||
function trackEvent(eventName, props) {
|
||||
if (window.plausible) {
|
||||
window.plausible(eventName, { props: props || {} });
|
||||
const params = Object.assign({}, props || {});
|
||||
if (CONFIG.ANALYTICS_DEBUG) {
|
||||
params.debug_mode = true; // Highlight in GA4 DebugView
|
||||
try { console.debug('[analytics] event', eventName, params); } catch (_) {}
|
||||
}
|
||||
// GA4 (gtag) event
|
||||
if (typeof window.gtag === 'function') {
|
||||
try { window.gtag('event', eventName, params); } catch (_) {}
|
||||
}
|
||||
// Plausible (if present)
|
||||
if (typeof window.plausible === 'function') {
|
||||
try { window.plausible(eventName, { props: params }); } catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +70,69 @@
|
||||
}
|
||||
};
|
||||
|
||||
// Google Analytics (GA4) Loader — gated by cookie consent
|
||||
const AnalyticsLoader = {
|
||||
loaded: false,
|
||||
init() {
|
||||
if (!CONFIG.ENABLE_ANALYTICS) return;
|
||||
try {
|
||||
const consent = localStorage.getItem('pj-cookies-accepted');
|
||||
if (consent === 'true') {
|
||||
this.load();
|
||||
}
|
||||
} catch (err) {
|
||||
// ignore storage errors
|
||||
}
|
||||
},
|
||||
load() {
|
||||
if (this.loaded) return;
|
||||
if (!CONFIG.ANALYTICS_ID) return;
|
||||
this.loaded = true;
|
||||
|
||||
// Define dataLayer and gtag shim before loading script
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){ window.dataLayer.push(arguments); }
|
||||
window.gtag = gtag;
|
||||
|
||||
gtag('js', new Date());
|
||||
// Consent granted for analytics after explicit acceptance
|
||||
gtag('consent', 'update', {
|
||||
ad_storage: 'denied',
|
||||
analytics_storage: 'granted',
|
||||
functionality_storage: 'granted',
|
||||
security_storage: 'granted'
|
||||
});
|
||||
gtag('config', CONFIG.ANALYTICS_ID, {
|
||||
anonymize_ip: true,
|
||||
send_page_view: false
|
||||
});
|
||||
|
||||
const s = document.createElement('script');
|
||||
s.async = true;
|
||||
s.src = 'https://www.googletagmanager.com/gtag/js?id=' + encodeURIComponent(CONFIG.ANALYTICS_ID);
|
||||
document.head.appendChild(s);
|
||||
// Fire a page_view once available
|
||||
if (document.readyState === 'complete') {
|
||||
this.pageView();
|
||||
} else {
|
||||
window.addEventListener('load', () => this.pageView(), { once: true });
|
||||
}
|
||||
},
|
||||
pageView() {
|
||||
if (!this.loaded || typeof window.gtag !== 'function') return;
|
||||
const params = {
|
||||
page_title: document.title,
|
||||
page_location: window.location.href,
|
||||
page_path: window.location.pathname
|
||||
};
|
||||
if (CONFIG.ANALYTICS_DEBUG) params.debug_mode = true;
|
||||
try {
|
||||
window.gtag('event', 'page_view', params);
|
||||
if (CONFIG.ANALYTICS_DEBUG) console.debug('[analytics] page_view', params);
|
||||
} catch (_) {}
|
||||
}
|
||||
};
|
||||
|
||||
// Navigation Management
|
||||
const Navigation = {
|
||||
init() {
|
||||
@@ -382,7 +455,10 @@
|
||||
accept() {
|
||||
localStorage.setItem(this.STORAGE_KEY, 'true');
|
||||
this.hide();
|
||||
// Initialize analytics here if needed
|
||||
// Initialize GA4 after consent
|
||||
if (typeof AnalyticsLoader !== 'undefined') {
|
||||
AnalyticsLoader.load();
|
||||
}
|
||||
},
|
||||
|
||||
decline() {
|
||||
@@ -431,6 +507,25 @@
|
||||
|
||||
// Initialize everything on DOM ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Initialize analytics (if enabled and consented previously)
|
||||
if (typeof AnalyticsLoader !== 'undefined') {
|
||||
AnalyticsLoader.init();
|
||||
}
|
||||
// Track SPA-style navigation changes (pushState/replaceState/popstate)
|
||||
(function setupSPAViews() {
|
||||
const origPush = history.pushState;
|
||||
const origReplace = history.replaceState;
|
||||
function handleNav(){
|
||||
// Minimal debounce
|
||||
clearTimeout(handleNav._tid);
|
||||
handleNav._tid = setTimeout(() => {
|
||||
if (typeof AnalyticsLoader !== 'undefined') AnalyticsLoader.pageView();
|
||||
}, 0);
|
||||
}
|
||||
history.pushState = function() { const r = origPush.apply(this, arguments); handleNav(); return r; };
|
||||
history.replaceState = function() { const r = origReplace.apply(this, arguments); handleNav(); return r; };
|
||||
window.addEventListener('popstate', handleNav);
|
||||
})();
|
||||
DarkMode.init();
|
||||
DarkMode.updateToggleButton();
|
||||
Navigation.init();
|
||||
@@ -456,4 +551,5 @@
|
||||
window.DarkMode = DarkMode;
|
||||
window.CookieNotice = CookieNotice;
|
||||
window.trackEvent = trackEvent;
|
||||
window.AnalyticsLoader = AnalyticsLoader;
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user