'use client' import { useState, useEffect, useCallback, useMemo } from 'react' import { CATEGORY_VENDORS, countNonEWRVendors, isEWR, isOutsideEWR, type VendorInfo, } from './cookie-banner-vendors' /** * CookieBannerOverlay — Cookie consent banner with Drittland-Schutz. * * Unique feature: Users can accept a category (e.g. Marketing) but block * all vendors that transfer data to non-EU countries. This means: * - Marketing = ON, Drittland-Schutz = ON → LinkedIn (EU) loads, Facebook (USA) does NOT * - The consent state records both category consent AND blocked vendors * * No other CMP offers per-vendor country-based blocking within accepted categories. */ const STORAGE_KEY = 'bp-sdk-cookie-consent' interface ConsentState { necessary: boolean statistics: boolean marketing: boolean functional: boolean ewrOnly: boolean blockedVendors: string[] timestamp: string } 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, ewrOnly: false, blockedVendors: [], timestamp: '', }) const nonEWRCount = useMemo(() => countNonEWRVendors(), []) // Compute which vendors are actually blocked const blockedVendors = useMemo(() => { if (!consent.ewrOnly) return [] const blocked: string[] = [] for (const [key, cat] of Object.entries(CATEGORY_VENDORS)) { const catEnabled = key === 'necessary' || consent[key as keyof ConsentState] if (!catEnabled) continue for (const v of cat.vendors) { if (isOutsideEWR(v.country)) { blocked.push(v.name) } } } return blocked }, [consent]) useEffect(() => { const stored = getStoredConsent() if (!stored) { setIsOpen(true) } else { setConsent(stored) } }, []) useEffect(() => { const handler = () => { setIsOpen(true) setShowSettings(true) } window.addEventListener('openCookieBanner', handler) return () => window.removeEventListener('openCookieBanner', handler) }, []) const saveConsent = useCallback((state: ConsentState) => { // Compute blocked vendors before saving const blocked: string[] = [] if (state.ewrOnly) { for (const [key, cat] of Object.entries(CATEGORY_VENDORS)) { const catEnabled = key === 'necessary' || state[key as keyof ConsentState] if (!catEnabled) continue for (const v of cat.vendors) { if (isOutsideEWR(v.country)) blocked.push(v.name) } } } const withMeta = { ...state, blockedVendors: blocked, timestamp: new Date().toISOString() } localStorage.setItem(STORAGE_KEY, JSON.stringify(withMeta)) setConsent(withMeta) setIsOpen(false) setShowSettings(false) window.dispatchEvent(new CustomEvent('sdkCookieConsentUpdated', { detail: withMeta })) }, []) const handleAcceptAll = () => { saveConsent({ ...consent, necessary: true, statistics: true, marketing: true, functional: true }) } const handleRejectAll = () => { saveConsent({ ...consent, necessary: true, statistics: false, marketing: false, functional: false }) } const handleSaveSettings = () => { saveConsent(consent) } if (!isOpen) return null return ( <>
{}} />
{/* Header */}

Cookie-Einstellungen

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

{/* Settings */} {showSettings && (
{/* === DRITTLAND-SCHUTZ === */}
Nur EU/EWR-Anbieter

Erlaubt nur Anbieter mit Sitz im Europaeischen Wirtschaftsraum (EWR) oder der Schweiz. Anbieter ausserhalb werden blockiert — auch wenn Sie einer Kategorie zustimmen. {nonEWRCount} Anbieter betroffen.

{consent.ewrOnly && blockedVendors.length > 0 && (
{blockedVendors.map(name => ( {name} ))}
)}
{/* Category Sections */}
{Object.entries(CATEGORY_VENDORS).map(([key, cat]) => ( key !== 'necessary' && setConsent(prev => ({ ...prev, [key]: v }))} /> ))}
)} {/* Buttons */}
{!showSettings ? ( <> ) : ( <> )}
) } export function CookieBannerFAB() { const [hasConsent, setHasConsent] = useState(false) useEffect(() => { setHasConsent(!!getStoredConsent()) const handler = () => setHasConsent(true) window.addEventListener('sdkCookieConsentUpdated', handler) return () => window.removeEventListener('sdkCookieConsentUpdated', handler) }, []) if (!hasConsent) return null return ( ) } function CategorySection({ categoryKey, label, description, vendors, checked, disabled, ewrOnly, onChange, }: { categoryKey: string label: string description: string vendors: VendorInfo[] checked: boolean disabled?: boolean ewrOnly: boolean onChange: (v: boolean) => void }) { const [expanded, setExpanded] = useState(false) const euVendors = vendors.filter(v => isEWR(v.country)) const nonEuVendors = vendors.filter(v => isOutsideEWR(v.country)) const blockedCount = ewrOnly && checked ? nonEuVendors.length : 0 const activeCount = checked ? vendors.length - blockedCount : 0 return (
{expanded && (
{vendors.map((v, i) => { const isBlocked = ewrOnly && checked && isOutsideEWR(v.country) const isActive = checked && !isBlocked return ( ) })}
Verarbeiter Cookies Dauer Land
{isBlocked ? ( ) : isActive ? ( ) : ( )} {v.name} {v.cookies} {v.retention} {isOutsideEWR(v.country) ? ( {v.country} ) : ( {v.country} )}
)}
) }