'use client' import { useState, useEffect, useCallback } from 'react' /** * CookieBannerOverlay — Live cookie consent banner for the Compliance SDK. * * - Opens automatically on first visit (localStorage check) * - Can be reopened via FAB button (right-[10rem]) * - Records consent choice to localStorage * - Fires custom event 'sdkCookieConsentUpdated' for other components */ const STORAGE_KEY = 'bp-sdk-cookie-consent' interface ConsentState { necessary: boolean statistics: boolean marketing: boolean functional: boolean timestamp: string } interface VendorInfo { name: string cookies: string provider: string retention: string country: string } // Demo vendors per category — mirrors service registry + cookie_table_generator.py const CATEGORY_VENDORS: Record = { necessary: { label: 'Notwendig', description: 'Fuer die Grundfunktionen der Website erforderlich.', vendors: [ { name: 'Session', cookies: 'session_id', provider: 'Eigener Server', retention: 'Session', country: 'DE' }, { name: 'Consent-Cookie', cookies: 'bp_consent', provider: 'Eigener Server', retention: '12 Monate', country: 'DE' }, { name: 'Cloudflare', cookies: '__cf_bm', provider: 'Cloudflare Inc.', retention: '30 Min.', country: 'USA (DPF)' }, { name: 'Stripe', cookies: '__stripe_mid', provider: 'Stripe Inc.', retention: 'Session', country: 'USA (DPF)' }, ], }, statistics: { label: 'Statistik', description: 'Helfen uns zu verstehen, wie Besucher mit der Website interagieren.', vendors: [ { name: 'Google Analytics', cookies: '_ga, _gid', provider: 'Google LLC', retention: '2 Jahre', country: 'USA (DPF)' }, { name: 'Hotjar', cookies: '_hj*', provider: 'Hotjar Ltd.', retention: '1 Jahr', country: 'EU (Malta)' }, { name: 'Google Tag Manager', cookies: '_gcl_au', provider: 'Google LLC', retention: '90 Tage', country: 'USA (DPF)' }, ], }, marketing: { label: 'Marketing', description: 'Werden verwendet, um Besuchern relevante Werbung zu zeigen.', vendors: [ { name: 'Facebook Pixel', cookies: '_fbp, _fbc', provider: 'Meta Platforms', retention: '90 Tage', country: 'USA (DPF)' }, { name: 'Google Ads', cookies: '_gcl_aw, IDE', provider: 'Google LLC', retention: '90 Tage', country: 'USA (DPF)' }, { name: 'LinkedIn Insight', cookies: 'bcookie, li_sugr', provider: 'LinkedIn Ireland', retention: '6 Monate', country: 'EU (Irland)' }, ], }, functional: { label: 'Funktional', description: 'Ermoeglichen erweiterte Funktionen und Personalisierung.', vendors: [ { name: 'Spracheinstellung', cookies: 'bp_lang', provider: 'Eigener Server', retention: '12 Monate', country: 'DE' }, { name: 'YouTube', cookies: 'YSC, VISITOR_INFO1_LIVE', provider: 'Google LLC', retention: '6 Monate', country: 'USA (DPF)' }, { name: 'HubSpot Chat', cookies: '__hstc, hubspotutk', provider: 'HubSpot Inc.', retention: '13 Monate', country: 'USA (DPF)' }, ], }, } function getStoredConsent(): ConsentState | null { if (typeof window === 'undefined') return null try { const raw = localStorage.getItem(STORAGE_KEY) if (!raw) return null return JSON.parse(raw) } catch { return null } } export function CookieBannerOverlay() { const [isOpen, setIsOpen] = useState(false) const [showSettings, setShowSettings] = useState(false) const [consent, setConsent] = useState({ necessary: true, statistics: false, marketing: false, functional: false, timestamp: '', }) // Check on mount if consent was already given useEffect(() => { const stored = getStoredConsent() if (!stored) { // First visit — show banner setIsOpen(true) } else { setConsent(stored) } }, []) // Listen for reopen event from FAB button useEffect(() => { const handler = () => { setIsOpen(true) setShowSettings(true) } window.addEventListener('openCookieBanner', handler) return () => window.removeEventListener('openCookieBanner', handler) }, []) const saveConsent = useCallback((state: ConsentState) => { const withTimestamp = { ...state, timestamp: new Date().toISOString() } localStorage.setItem(STORAGE_KEY, JSON.stringify(withTimestamp)) setConsent(withTimestamp) setIsOpen(false) setShowSettings(false) window.dispatchEvent(new CustomEvent('sdkCookieConsentUpdated', { detail: withTimestamp })) }, []) const handleAcceptAll = () => { saveConsent({ necessary: true, statistics: true, marketing: true, functional: true, timestamp: '' }) } const handleRejectAll = () => { saveConsent({ necessary: true, statistics: false, marketing: false, functional: false, timestamp: '' }) } const handleSaveSettings = () => { saveConsent(consent) } if (!isOpen) return null return ( <> {/* Overlay */}
{/* Don't close on overlay click — consent is required */}} /> {/* Banner */}
{/* Header */}

Cookie-Einstellungen

Wir verwenden Cookies und aehnliche Technologien, um Ihnen die bestmoegliche Erfahrung zu bieten. Sie koennen Ihre Praeferenzen jederzeit aendern.

{/* Category Settings (expandable) */} {showSettings && (
{Object.entries(CATEGORY_VENDORS).map(([key, cat]) => ( key !== 'necessary' && setConsent(prev => ({ ...prev, [key]: v }))} /> ))}
)} {/* Buttons */}
{!showSettings ? ( <> ) : ( <> )}
) } /** * FAB button to reopen the cookie banner settings. * Positioned next to ComplianceAdvisor and PipelineSidebar. */ export function CookieBannerFAB() { const [hasConsent, setHasConsent] = useState(false) useEffect(() => { setHasConsent(!!getStoredConsent()) const handler = () => setHasConsent(true) window.addEventListener('sdkCookieConsentUpdated', handler) return () => window.removeEventListener('sdkCookieConsentUpdated', handler) }, []) // Only show FAB after consent was given (banner is closed) if (!hasConsent) return null return ( ) } function CategorySection({ categoryKey, label, description, vendors, checked, disabled, onChange, }: { categoryKey: string label: string description: string vendors: VendorInfo[] checked: boolean disabled?: boolean onChange: (v: boolean) => void }) { const [expanded, setExpanded] = useState(false) return (
{/* Category Header with Toggle */}
{/* Vendor Table (expandable) */} {expanded && (
{vendors.map((v, i) => ( ))}
Verarbeiter Cookies Dauer Land
{v.name} {v.cookies} {v.retention} {v.country}
)}
) }