From e2144076e901aed552a809703956ec76f935a4a7 Mon Sep 17 00:00:00 2001 From: ipeke94 <26484292+ipeke94@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:51:44 +0200 Subject: [PATCH] feat: add cookie consent v3 --- package.json | 1 + src/@types/cookieconsent.d.ts | 54 +++++++++++++ src/components/CookieConsent.tsx | 92 +++++++++++++++++++++++ src/components/layout/leadinfo-script.tsx | 34 ++++++--- src/pages/index.tsx | 4 +- yarn.lock | 5 ++ 6 files changed, 176 insertions(+), 14 deletions(-) create mode 100644 src/@types/cookieconsent.d.ts create mode 100644 src/components/CookieConsent.tsx diff --git a/package.json b/package.json index 596ff1424..f16d61d70 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "stylis": "^4.3.1", "unified": "^10.1.1", "util": "^0.12.5", + "vanilla-cookieconsent": "3.0.1", "webpack": "^5.84.1", "what-input": "^5.2.12" }, diff --git a/src/@types/cookieconsent.d.ts b/src/@types/cookieconsent.d.ts new file mode 100644 index 000000000..12fd257a8 --- /dev/null +++ b/src/@types/cookieconsent.d.ts @@ -0,0 +1,54 @@ +declare module 'vanilla-cookieconsent' { + interface CookieValue { + categories: { + necessary: boolean; + analytics: boolean; + }; + } + + interface CookieConsentCallbackParam { + cookie: CookieValue; + } + + interface CookieConsentConfig { + categories: { + necessary: { + enabled: boolean; + readOnly: boolean; + }; + analytics: { + enabled: boolean; + }; + }; + language: { + default: string; + translations: { + [key: string]: { + consentModal: { + title: string; + description: string; + acceptAllBtn: string; + acceptNecessaryBtn: string; + showPreferencesBtn: string; + }; + preferencesModal: { + title: string; + acceptAllBtn: string; + acceptNecessaryBtn: string; + savePreferencesBtn: string; + closeIconLabel: string; + sections: Array<{ + title: string; + description: string; + linkedCategory?: string; + }>; + }; + }; + }; + }; + onFirstConsent?: (param: CookieConsentCallbackParam) => void; + onConsentChange?: (param: CookieConsentCallbackParam) => void; + } + + export function run(config: CookieConsentConfig): void; +} diff --git a/src/components/CookieConsent.tsx b/src/components/CookieConsent.tsx new file mode 100644 index 000000000..2b58312a3 --- /dev/null +++ b/src/components/CookieConsent.tsx @@ -0,0 +1,92 @@ +import React, { useEffect, useState } from 'react'; +import 'vanilla-cookieconsent/dist/cookieconsent.css'; +import * as CookieConsent from 'vanilla-cookieconsent'; +import LeadinfoScript from '../components/layout/leadinfo-script'; + +const CookieConsentComponentV3 = () => { + const [analyticsEnabled, setAnalyticsEnabled] = useState(false); + + useEffect(() => { + CookieConsent.run({ + categories: { + necessary: { + enabled: true, + readOnly: true, + }, + analytics: { + enabled: false, + }, + }, + language: { + default: 'en', + translations: { + en: { + consentModal: { + title: 'We use cookies', + description: + 'This website uses cookies to ensure the best user experience.', + acceptAllBtn: 'Accept all', + acceptNecessaryBtn: 'Reject all', + showPreferencesBtn: 'Manage preferences', + }, + preferencesModal: { + title: 'Manage Cookie Preferences', + acceptAllBtn: 'Accept all', + acceptNecessaryBtn: 'Accept necessary only', + savePreferencesBtn: 'Save preferences', + closeIconLabel: 'Close', + sections: [ + { + title: 'Strictly Necessary Cookies', + description: + 'These cookies are essential for website functionality and cannot be disabled.', + linkedCategory: 'necessary', + }, + { + title: 'Analytics Cookies', + description: + 'We use analytics cookies to analyze website usage and improve our services.', + linkedCategory: 'analytics', + }, + ], + }, + }, + }, + }, + onFirstConsent: (param) => { + handleConsent(param.cookie.categories); + }, + onConsentChange: (param) => { + handleConsent(param.cookie.categories); + }, + }); + }, []); + + const handleConsent = (categories) => { + const isAnalyticsAccepted = categories.includes('analytics'); + + if (isAnalyticsAccepted) { + setAnalyticsEnabled(true); + setLeadinfoCookies(); + } else { + setAnalyticsEnabled(false); + clearLeadinfoCookies(); + } + }; + + const setLeadinfoCookies = () => { + const twoYears = 63072000; + const sessionValue = new Date().toISOString(); + document.cookie = `_li_id=some_value; max-age=${twoYears}; path=/`; + document.cookie = `_li_ses=${sessionValue}; max-age=0; path=/`; + }; + + const clearLeadinfoCookies = () => { + document.cookie = '_li_id=; max-age=0; path=/'; + document.cookie = '_li_ses=; max-age=0; path=/'; + }; + + return ; +}; + +export default CookieConsentComponentV3; diff --git a/src/components/layout/leadinfo-script.tsx b/src/components/layout/leadinfo-script.tsx index 5e6ebc296..46df9d602 100644 --- a/src/components/layout/leadinfo-script.tsx +++ b/src/components/layout/leadinfo-script.tsx @@ -1,20 +1,30 @@ -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; + +let leadinfoInitialized = false; + +const LeadinfoScript = ({ enable }: { enable: boolean }) => { + const [script, setScript] = useState(null); -const LeadinfoScript = () => { useEffect(() => { - const script = document.createElement('script'); - script.innerHTML = ` - (function(l,e,a,d,i,n,f,o){if(!l[i]){l.GlobalLeadinfoNamespace=l.GlobalLeadinfoNamespace||[]; - l.GlobalLeadinfoNamespace.push(i);l[i]=function(){(l[i].q=l[i].q||[]).push(arguments)};l[i].t=l[i].t||n; - l[i].q=l[i].q||[];o=e.createElement(a);f=e.getElementsByTagName(a)[0];o.async=1;o.src=d;f.parentNode.insertBefore(o,f);} - }(window,document,'script','https://cdn.leadinfo.eu/ping.js','leadinfo','LI-66D184CC97CFD')); + if (enable && !leadinfoInitialized) { + const leadinfoScript = document.createElement('script'); + leadinfoScript.innerHTML = ` + (function(l,e,a,d,i,n,f,o){if(!l[i]){l.GlobalLeadinfoNamespace=l.GlobalLeadinfoNamespace||[]; + l.GlobalLeadinfoNamespace.push(i);l[i]=function(){(l[i].q=l[i].q||[]).push(arguments)};l[i].t=l[i].t||n; + l[i].q=l[i].q||[];o=e.createElement(a);f=e.getElementsByTagName(a)[0];o.async=1;o.src=d;f.parentNode.insertBefore(o,f);} + }(window,document,'script','https://cdn.leadinfo.eu/ping.js','leadinfo','LI-66D184CC97CFD')); `; - document.head.appendChild(script); + document.head.appendChild(leadinfoScript); + setScript(leadinfoScript); + leadinfoInitialized = true; + } - return () => { + if (!enable && leadinfoInitialized && script) { document.head.removeChild(script); - }; - }, []); + setScript(null); + leadinfoInitialized = false; + } + }, [enable, script]); return null; }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 2f97547c6..208e43283 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -11,7 +11,7 @@ import { } from '../types'; import { IGatsbyImageData } from 'gatsby-plugin-image'; import { StructuredOrganizationData } from '../components/pages/landingpage/structured-organization-data'; -import LeadinfoScript from '../components/layout/leadinfo-script'; // Import the new component +import CookieConsentComponentV3 from '../components/CookieConsent'; export interface OfficeImage { relativePath: string; @@ -72,8 +72,8 @@ export const Head = ({ data, location }: PageProps) => { rssLink locales={data.locales} /> + - ); }; diff --git a/yarn.lock b/yarn.lock index 38d0c5f18..08748363b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15148,6 +15148,11 @@ value-or-promise@^1.0.12: resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.12.tgz#0e5abfeec70148c78460a849f6b003ea7986f15c" integrity sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q== +vanilla-cookieconsent@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/vanilla-cookieconsent/-/vanilla-cookieconsent-3.0.1.tgz#059d1b2c712476ae4172d4ec7fa9d553a16be12d" + integrity sha512-gqc4x7O9t1I4xWr7x6/jtQWPr4PZK26SmeA0iyTv1WyoECfAGnu5JEOExmMEP+5Fz66AT9OiCBO3GII4wDQHLw== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"