Skip to content

Commit

Permalink
refactor(core): elevate consent mode into bodl provider (#1426)
Browse files Browse the repository at this point in the history
  • Loading branch information
chanceaclark authored Oct 7, 2024
1 parent 4874add commit 49a7ce3
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 76 deletions.
19 changes: 19 additions & 0 deletions core/lib/bodl/analytics.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,23 @@ declare namespace Analytics {
productRemoved: (payload: ProductRemovedPayload) => void;
}
}

export namespace Consent {
interface ConsentLoadedPayload {
functional: boolean;
analytics: boolean;
advertising: boolean;
}

interface ConsentUpdatedPayload {
functional: boolean;
analytics: boolean;
advertising: boolean;
}

export interface Events {
consentLoaded: (payload: ConsentLoadedPayload) => void;
consentUpdated: (payload: ConsentUpdatedPayload) => void;
}
}
}
67 changes: 67 additions & 0 deletions core/lib/bodl/bodl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class Bodl {

readonly cart = this.getCartEvents();
readonly navigation = this.getNavigationEvents();
readonly consent = this.getConsentEvents();

private readonly bodlScriptId = 'bodl-events-script';
private readonly dataLayerScriptId = 'data-layer-script';
Expand Down Expand Up @@ -65,6 +66,9 @@ export class Bodl {
this.initializeBodlEvents();
this.initializeDataLayer();
this.initializeGTM();
this.initializeConsentMode();

this.bindEvents();

Bodl.waitForBodlEvents(() => {
subscribeOnBodlEvents(
Expand Down Expand Up @@ -144,6 +148,24 @@ export class Bodl {
document.head.appendChild(script);
}

private initializeConsentMode() {
if (!this.config.googleAnalytics.consentModeEnabled) {
return;
}

gtag('consent', 'default', {
ad_personalization: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
analytics_storage: 'denied',
functionality_storage: 'denied',
});
}

private bindEvents() {
this.bindConsentEvents();
}

private getCartEvents() {
return {
productAdded: (payload) => {
Expand Down Expand Up @@ -198,4 +220,49 @@ export class Bodl {
},
} satisfies Analytics.Navigation.Events;
}

private getConsentEvents() {
return {
consentLoaded: (payload) => {
Bodl.waitForBodlEvents(() => {
window.bodlEvents?.consent.emit('bodl_v1_consent_loaded', {
event_id: uuidv4(),
...payload,
});
});
},
consentUpdated: (payload) => {
Bodl.waitForBodlEvents(() => {
window.bodlEvents?.consent.emit('bodl_v1_consent_updated', {
event_id: uuidv4(),
...payload,
});
});
},
} satisfies Analytics.Consent.Events;
}

private bindConsentEvents() {
Bodl.waitForBodlEvents(() => {
window.bodlEvents?.consent.loaded((payload) => {
gtag('consent', 'update', {
ad_personalization: payload.advertising ? 'granted' : 'denied',
ad_storage: payload.advertising ? 'granted' : 'denied',
ad_user_data: payload.advertising ? 'granted' : 'denied',
analytics_storage: payload.analytics ? 'granted' : 'denied',
functionality_storage: payload.functional ? 'granted' : 'denied',
});
});

window.bodlEvents?.consent.updated((payload) => {
gtag('consent', 'update', {
ad_personalization: payload.advertising ? 'granted' : 'denied',
ad_storage: payload.advertising ? 'granted' : 'denied',
ad_user_data: payload.advertising ? 'granted' : 'denied',
analytics_storage: payload.analytics ? 'granted' : 'denied',
functionality_storage: payload.functional ? 'granted' : 'denied',
});
});
});
}
}
69 changes: 0 additions & 69 deletions core/lib/bodl/providers/ga4/google_analytics4.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,81 +286,12 @@ export function subscribeOnBodlEvents(measurementId, consentModeEnabled) {
}
}

function setupConsent() {
if (!consentModeEnabled) {
return;
}

function transformConsentPayload(payload) {
var BODL_TO_GA4_CONSENT_CATEGORIES_MAP = {
advertising: ['ad_storage', 'ad_user_data', 'ad_personalization'],
analytics: ['analytics_storage'],
functional: ['functionality_storage'],
};

var transformed = {};

Object.keys(payload).forEach(function (category) {
var mapped = BODL_TO_GA4_CONSENT_CATEGORIES_MAP[category];
var permission = payload[category] ? 'granted' : 'denied';

if (Array.isArray(mapped)) {
mapped.forEach(function (ga4category) {
transformed[ga4category] = permission;
});
}
});

return transformed;
}

var DEFAULTS = {
advertising: false,
analytics: false,
functional: false,
};

function isConsentChanged(currentConsent) {
return Object.keys(DEFAULTS).some(function (category) {
return DEFAULTS[category] !== currentConsent[category];
});
}

function setupDefaults() {
gtag('consent', 'default', transformConsentPayload(DEFAULTS));
}

function subscribeOnConsentEvents() {
if (typeof window.bodlEvents.consent === 'undefined') {
return;
}

if (typeof window.bodlEvents.consent.loaded === 'function') {
window.bodlEvents.consent.loaded(function (payload) {
if (isConsentChanged(payload)) {
gtag('consent', 'update', transformConsentPayload(payload));
}
});
}

if (typeof window.bodlEvents.consent.updated === 'function') {
window.bodlEvents.consent.updated(function (payload) {
gtag('consent', 'update', transformConsentPayload(payload));
});
}
}

setupDefaults();
subscribeOnConsentEvents();
}

function subscribeOnEcommerceEvents() {
subscribeOnCheckoutEvents();
subscribeOnCartEvents();
subscribeOnProductEvents();
subscribeOnPromotionEvents();
}

setupConsent();
subscribeOnEcommerceEvents();
}
1 change: 1 addition & 0 deletions core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@next/bundle-analyzer": "^14.2.14",
"@playwright/test": "^1.47.2",
"@tailwindcss/container-queries": "^0.1.1",
"@types/gtag.js": "^0.0.20",
"@types/lodash.debounce": "^4.0.9",
"@types/node": "^20.16.10",
"@types/react": "^18.3.11",
Expand Down
22 changes: 15 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 49a7ce3

Please sign in to comment.