From 016e8ebe84260005040ec38015fa967a7ffe5f68 Mon Sep 17 00:00:00 2001 From: Remi <73385395+itsrubberduck@users.noreply.github.com> Date: Sat, 18 Oct 2025 14:48:13 +0200 Subject: [PATCH] Handle Hotjar consent via local storage --- app/app.vue | 97 ++++++++++++++++++++++++++++- app/composables/useCookieConsent.ts | 19 ++++++ plugins/hotjar.client.ts | 55 ---------------- 3 files changed, 114 insertions(+), 57 deletions(-) delete mode 100644 plugins/hotjar.client.ts diff --git a/app/app.vue b/app/app.vue index f9cc8e1..49c748e 100644 --- a/app/app.vue +++ b/app/app.vue @@ -5,12 +5,27 @@ diff --git a/app/composables/useCookieConsent.ts b/app/composables/useCookieConsent.ts index 726652a..a094313 100644 --- a/app/composables/useCookieConsent.ts +++ b/app/composables/useCookieConsent.ts @@ -14,6 +14,7 @@ type CookieConsentValue = { const CONSENT_COOKIE_NAME = 'osq-cookie-consent'; const CONSENT_VERSION = 1; const SIX_MONTHS_IN_SECONDS = 60 * 60 * 24 * 180; +export const HOTJAR_LOCAL_STORAGE_KEY = 'osq-hotjar-consent'; export const useCookieConsent = () => { const consentCookie = useCookie(CONSENT_COOKIE_NAME, { @@ -37,6 +38,24 @@ export const useCookieConsent = () => { { deep: true } ); + if (process.client) { + watch( + consentState, + (value) => { + if (!value) { + window.localStorage.removeItem(HOTJAR_LOCAL_STORAGE_KEY); + return; + } + + window.localStorage.setItem( + HOTJAR_LOCAL_STORAGE_KEY, + value.preferences.analytics ? 'granted' : 'denied' + ); + }, + { deep: true } + ); + } + const hasConsent = computed(() => consentState.value !== null); const analyticsEnabled = computed(() => { diff --git a/plugins/hotjar.client.ts b/plugins/hotjar.client.ts deleted file mode 100644 index 0eae42c..0000000 --- a/plugins/hotjar.client.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { defineNuxtPlugin } from '#app'; -import { watch } from 'vue'; -import { useCookieConsent } from '~/composables/useCookieConsent'; -import { useHotjar } from '#imports'; - -declare global { - interface Window { - hj?: ((...args: unknown[]) => void) & { q?: unknown[][] }; - _hjOptOut?: boolean; - } -} - -const setHotjarOptOut = (optOut: boolean) => { - if (typeof window === 'undefined') { - return; - } - - window._hjOptOut = optOut; - - if (optOut && typeof window.hj === 'function') { - try { - window.hj('event', 'cookie_consent_opt_out'); - } catch { - // ignore errors from Hotjar when shutting down - } - } -}; - -export default defineNuxtPlugin(() => { - if (!import.meta.client) { - return; - } - - const { initialize } = useHotjar(); - const hasInitialized = useState('hotjar-initialized', () => false); - const { analyticsEnabled } = useCookieConsent(); - - watch( - () => analyticsEnabled.value, - (enabled) => { - if (enabled) { - setHotjarOptOut(false); - - if (!hasInitialized.value) { - initialize(); - hasInitialized.value = true; - } - } else { - setHotjarOptOut(true); - hasInitialized.value = false; - } - }, - { immediate: true } - ); -});