since3-website/modules/shared/ui/components/cookie-consent.tsx
2026-09-25 19:35:58 +02:00

70 lines
2.9 KiB
TypeScript

"use client";
import { Analytics } from "@vercel/analytics/next";
import type { BeforeSendEvent } from "@vercel/analytics";
import * as CookieConsent from 'vanilla-cookieconsent';
import 'vanilla-cookieconsent/dist/cookieconsent.css';
import { useEffect } from "react";
// Re-checked on every single event, so it stays correct for the rest of the
// session regardless of the <Analytics> component's own mount state.
// Module-level (not created inside the component) so its reference is
// stable across renders and Analytics doesn't re-register it needlessly.
function gateByConsent(event: BeforeSendEvent) {
return CookieConsent.acceptedCategory('analytics') ? event : null;
}
export default function CookieBanner() {
useEffect(() => {
document.documentElement.classList.add('cc--elegant-black');
CookieConsent.run({
guiOptions: {
consentModal: { layout: 'box', position: 'bottom right' },
preferencesModal: {layout: 'box'},
},
categories: {
analytics: {}
},
language: {
default: 'de',
translations: {
de: {
consentModal: {
title: 'Wir nutzen Cookies',
description:
'Diese Webseite nutzt optionale Cookies für Statistik und Marketing. Mehr dazu in unserer <a href="/datenschutz" target="_blank" rel="noopener">Datenschutzerklärung</a>.',
acceptAllBtn: 'Alle akzeptieren',
acceptNecessaryBtn: 'Nur notwendige',
showPreferencesBtn: 'Einstellungen verwalten',
},
preferencesModal: {
title: 'Cookie-Einstellungen',
acceptAllBtn: 'Alle akzeptieren',
acceptNecessaryBtn: 'Nur notwendige',
savePreferencesBtn: 'Auswahl speichern',
sections: [
{ title: "Statistik", linkedCategory: 'analytics' }
],
},
},
},
},
})
}, []);
return (
<>
{/*
* Always mounted, regardless of consent: @vercel/analytics injects
* its script into <head> on mount and never removes it on unmount
* (v2.0.1 has no cleanup), so a script that already loaded would
* keep tracking after consent is withdrawn if we unmounted this.
* Gating happens per-event in beforeSend instead, which is
* re-checked live on every event and therefore stays effective
* for the rest of the session, including after withdrawal.
*/}
<Analytics beforeSend={gateByConsent} />
</>
)
}