@primarix/easy-consent
Version:
A lightweight consent management solution for Google Analytics and related services. This is a beta version and should be used with caution.
212 lines (164 loc) • 6.71 kB
text/typescript
import { type Mode,
type Options,
Config,
type ConsentEventKey,
type ConsentEventMode,
ConsentUpdateEventDetail,
ConsentUpdateEvent,
type PartialConfig } from "./types";
declare global {
interface Window {
dataLayer: any[];
gtag: (...args: any[]) => void;
}
}
declare global {
interface WindowEventMap {
'consent-updated': ConsentUpdateEvent;
}
}
export class EasyConsent {
public isNewUser:boolean
public state:Config;
private head:HTMLElement
private analytics_lib:HTMLElement
private init_consent:HTMLElement
private init_GA:HTMLElement
private consentConfigDuration = 180;
private getCookie(name: string) {
const cookies = document.cookie.split("; ");
for (let cookie of cookies) {
const [key, value] = cookie.split("=");
if (key === name) {
try {
return JSON.parse(decodeURIComponent(value));
} catch (error) {
console.error("Error al parsear el contenido de la cookie:", error);
return null;
}
}
}
return null;
}
private setCookie(name: string, value: Config, days: number) {
const jsonValue = JSON.stringify(value);
const encodedValue = encodeURIComponent(jsonValue);
const expires = days
? "; expires=" + new Date(Date.now() + days * 864e5).toUTCString()
: "";
document.cookie = `${name}=${encodedValue}${expires}; path=/; SameSite=Lax; Secure`;
}
constructor (private id:string){
const config = this.getCookie("consentConfig")
if(config){
this.state = config;
this.isNewUser = false;
}
else{
this.isNewUser = true;
this.state = {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'functionality_storage': 'denied',
'personalization_storage': 'denied',
'ad_user_data':'denied',
'ad_personalization': 'denied',
'security_storage': 'denied'
}
this.setCookie("consentConfig", this.state , this.consentConfigDuration)
}
this.head = document.head;
this.analytics_lib = document.createElement("script");
this.init_consent = document.createElement("script");
this.init_GA = document.createElement("script");
this.analytics_lib.setAttribute("src",`https://www.googletagmanager.com/gtag/js?id=${this.id}`);
this.analytics_lib.setAttribute("async", "true");
this.init_consent.setAttribute("data-cookieconsent", "ignore")
this.init_consent.textContent = `
window.dataLayer = window.dataLayer || [];
function gtag(){ dataLayer.push(arguments); }
gtag('consent', 'default', ${JSON.stringify(this.state)});
gtag('set', 'ads_data_redaction', true);
gtag('set', 'url_passthrough', true);
`
this.init_GA.textContent = `
gtag('js', new Date());
gtag('config', '${this.id}', { send_page_view: false });
`
this.head.appendChild(this.init_consent);
this.analytics_lib.onload = () => {
this.head.appendChild(this.init_GA);
};
this.head.appendChild(this.analytics_lib);
}
private pageView(){
if (this.state.analytics_storage === 'granted') {
window.gtag('event', 'page_view', {
page_path: window.location.pathname,
page_title: document.title,
});
}
}
private dispatchCustomEvent(key:ConsentEventKey,mode:ConsentEventMode){
const event = new CustomEvent<ConsentUpdateEventDetail>('consent-updated', {
detail: { key, mode, state: this.state, timestamp: Date.now().toString()} });
window.dispatchEvent(event);
}
update(key:Options, mode:Mode){
if(!window.dataLayer) throw new Error("The gtag function is not defined");
this.state = {...this.state, [key]: mode}
this.setCookie("consentConfig", this.state ,this.consentConfigDuration)
window.gtag("consent", "update", { [key]: mode });
this.pageView();
this.dispatchCustomEvent(key,mode);
}
acceptAll() {
try {
if (!window.dataLayer) throw new Error("The gtag function is not defined");
const v1 = Object.keys(this.state) as Options[];
const v2 = v1.map((key) => [key ,"granted"])
this.state = Object.fromEntries(v2) as Config;
window.gtag("consent", "update", this.state);
this.setCookie("consentConfig", this.state, this.consentConfigDuration)
this.pageView();
this.dispatchCustomEvent("all","accept-all");
}
catch (error) {
console.error("Error in acceptAll:", error);
}
}
rejectAll(){
try{
if(!window.dataLayer) throw new Error("The gtag function is not defined");
const v1 = Object.keys(this.state) as Options[];
const v2 = v1.map((key) => [key ,"denied"])
this.state = Object.fromEntries(v2) as Config;
window.gtag("consent", "update", this.state);
this.setCookie("consentConfig", this.state ,this.consentConfigDuration)
this.dispatchCustomEvent("all","reject-all");
}
catch(error){
console.error("Error in rejectAll:", error)
}
}
isAllConsented(): boolean {
return Object.values(this.state).every(value => value === 'granted');
}
isAllDenied(): boolean {
return Object.values(this.state).every(value => value === 'denied');
}
updateMultiple(new_state:PartialConfig){
try{
this.state = {...this.state,...new_state}
window.gtag("consent", "update", new_state);
this.setCookie("consentConfig", this.state ,this.consentConfigDuration)
Object.entries(new_state).forEach(([key, mode]) => {
this.dispatchCustomEvent(key as Options, mode as Mode);
});
this.pageView();
}
catch(error){
console.error("Error in updateMultiple:", error)
}
}
}