55 */
66
77class ConsentManager {
8- constructor ( ) {
8+ constructor ( options = { } ) {
99 this . COOKIE_NAME = 'essential-csharp-consent' ;
1010 this . COOKIE_DURATION = 365 ; // days
11+ this . GOOGLE_ANALYTICS_ID = options . googleAnalyticsId || 'G-761B4BMK2R' ;
1112 this . consentState = {
1213 analytics_storage : 'denied' ,
1314 ad_storage : 'denied' ,
@@ -35,6 +36,21 @@ class ConsentManager {
3536 if ( this . shouldShowConsentBanner ( ) ) {
3637 this . showConsentBanner ( ) ;
3738 }
39+
40+ // Dispatch initialization event for other scripts to listen to
41+ this . dispatchInitializationEvent ( ) ;
42+ }
43+
44+ dispatchInitializationEvent ( ) {
45+ // Create and dispatch custom event to signal consent manager is ready
46+ const event = new CustomEvent ( 'consentManagerReady' , {
47+ detail : {
48+ hasAnalyticsConsent : this . hasAnalyticsConsent ( ) ,
49+ hasAdvertisingConsent : this . hasAdvertisingConsent ( ) ,
50+ requiresConsent : this . requiresConsent
51+ }
52+ } ) ;
53+ document . dispatchEvent ( event ) ;
3854 }
3955
4056 initGoogleConsentMode ( ) {
@@ -54,7 +70,8 @@ class ConsentManager {
5470 return true ;
5571 }
5672
57- // Simple region detection - in production, you might want to use a more reliable service
73+ // Timezone-based region detection for GDPR compliance
74+ // Users can change timezones, but this provides reasonable detection for most cases
5875 const timezone = Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ;
5976
6077 // EEA countries, UK, and Switzerland timezones
@@ -90,7 +107,23 @@ class ConsentManager {
90107 if ( saved ) {
91108 try {
92109 const preferences = JSON . parse ( saved ) ;
93- this . consentState = { ...this . consentState , ...preferences } ;
110+
111+ // Validate and only apply known consent properties for security
112+ const validConsentKeys = [
113+ 'analytics_storage' , 'ad_storage' , 'ad_user_data' ,
114+ 'ad_personalization' , 'functionality_storage' ,
115+ 'security_storage' , 'personalization_storage'
116+ ] ;
117+
118+ const validatedPreferences = { } ;
119+ validConsentKeys . forEach ( key => {
120+ if ( preferences . hasOwnProperty ( key ) &&
121+ ( preferences [ key ] === 'granted' || preferences [ key ] === 'denied' ) ) {
122+ validatedPreferences [ key ] = preferences [ key ] ;
123+ }
124+ } ) ;
125+
126+ this . consentState = { ...this . consentState , ...validatedPreferences } ;
94127 this . updateConsentMode ( ) ;
95128 } catch ( e ) {
96129 console . warn ( 'Failed to parse consent preferences' , e ) ;
@@ -261,20 +294,30 @@ class ConsentManager {
261294
262295 updateConsentMode ( ) {
263296 if ( window . gtag ) {
264- gtag ( 'consent' , 'update' , this . consentState ) ;
265-
266- // Configure Google Analytics if analytics consent is granted
267- if ( this . consentState . analytics_storage === 'granted' ) {
268- gtag ( 'config' , 'G-761B4BMK2R' ) ;
297+ try {
298+ gtag ( 'consent' , 'update' , this . consentState ) ;
299+
300+ // Configure Google Analytics if analytics consent is granted
301+ if ( this . consentState . analytics_storage === 'granted' ) {
302+ gtag ( 'config' , 'G-761B4BMK2R' ) ;
303+ }
304+ } catch ( error ) {
305+ console . warn ( 'Failed to update Google Consent Mode:' , error ) ;
269306 }
270307 }
271308 }
272309
273310 updateClarityConsent ( ) {
274- // Send consent signal to Microsoft Clarity
311+ // Send consent signal to Microsoft Clarity using Consent API v2
275312 if ( window . clarity ) {
276- const analyticsConsent = this . consentState . analytics_storage === 'granted' ;
277- clarity ( 'consent' , analyticsConsent ) ;
313+ try {
314+ clarity ( 'consentv2' , {
315+ ad_Storage : this . consentState . ad_storage ,
316+ analytics_Storage : this . consentState . analytics_storage
317+ } ) ;
318+ } catch ( error ) {
319+ console . warn ( 'Failed to update Clarity consent:' , error ) ;
320+ }
278321 }
279322 }
280323
@@ -435,11 +478,15 @@ class ConsentManager {
435478 this . rejectAllConsent ( ) ;
436479 // Also clear any existing tracking cookies
437480 this . clearTrackingCookies ( ) ;
481+ // Erase Clarity cookies according to documentation
482+ if ( window . clarity ) {
483+ clarity ( 'consent' , false ) ;
484+ }
438485 }
439486
440487 clearTrackingCookies ( ) {
441- // Clear common tracking cookies
442- const trackingCookies = [ '_ga' , '_gid' , '_gat' , '_clck' , '_clsk' ] ;
488+ // Clear common tracking cookies (Google Analytics and Microsoft Clarity)
489+ const trackingCookies = [ '_ga' , '_gid' , '_gat' , '_clck' , '_clsk' , 'CLID' , 'ANONCHK' , 'MR' , 'MUID' , 'SM' ] ;
443490 trackingCookies . forEach ( cookieName => {
444491 document . cookie = `${ cookieName } =;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/` ;
445492 } ) ;
@@ -448,7 +495,11 @@ class ConsentManager {
448495
449496// Initialize consent manager when DOM is ready
450497document . addEventListener ( 'DOMContentLoaded' , function ( ) {
451- window . consentManager = new ConsentManager ( ) ;
498+ // Check for configuration from script tag data attributes
499+ const configScript = document . querySelector ( 'script[data-consent-config]' ) ;
500+ const config = configScript ? JSON . parse ( configScript . dataset . consentConfig ) : { } ;
501+
502+ window . consentManager = new ConsentManager ( config ) ;
452503} ) ;
453504
454505// Global function for opening consent preferences
0 commit comments