'use client' import React, { useState } from 'react' import { useSDK } from '@/lib/sdk' import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader' // ============================================================================= // TYPES // ============================================================================= interface CookieCategory { id: string name: string description: string required: boolean enabled: boolean cookies: Cookie[] } interface Cookie { name: string provider: string purpose: string expiry: string type: 'first-party' | 'third-party' } interface BannerConfig { position: 'bottom' | 'top' | 'center' style: 'bar' | 'popup' | 'modal' primaryColor: string showDeclineAll: boolean showSettings: boolean blockScripts: boolean } // ============================================================================= // DEFAULT DATA (Fallback wenn DB leer oder nicht erreichbar) // ============================================================================= const DEFAULT_COOKIE_CATEGORIES: CookieCategory[] = [ { id: 'necessary', name: 'Notwendig', description: 'Diese Cookies sind fuer die Grundfunktionen der Website erforderlich.', required: true, enabled: true, cookies: [ { name: 'session_id', provider: 'Eigene', purpose: 'Session-Verwaltung', expiry: 'Session', type: 'first-party' }, { name: 'csrf_token', provider: 'Eigene', purpose: 'Sicherheit', expiry: 'Session', type: 'first-party' }, ], }, { id: 'analytics', name: 'Analyse', description: 'Diese Cookies helfen uns, die Nutzung der Website zu verstehen.', required: false, enabled: true, cookies: [ { name: '_ga', provider: 'Google Analytics', purpose: 'Nutzeranalyse', expiry: '2 Jahre', type: 'third-party' }, { name: '_gid', provider: 'Google Analytics', purpose: 'Nutzeranalyse', expiry: '24 Stunden', type: 'third-party' }, ], }, { id: 'marketing', name: 'Marketing', description: 'Diese Cookies werden fuer personalisierte Werbung verwendet.', required: false, enabled: false, cookies: [ { name: '_fbp', provider: 'Meta (Facebook)', purpose: 'Werbung', expiry: '3 Monate', type: 'third-party' }, { name: 'IDE', provider: 'Google Ads', purpose: 'Werbung', expiry: '1 Jahr', type: 'third-party' }, ], }, { id: 'preferences', name: 'Praeferenzen', description: 'Diese Cookies speichern Ihre Einstellungen und Praeferenzen.', required: false, enabled: true, cookies: [ { name: 'language', provider: 'Eigene', purpose: 'Spracheinstellung', expiry: '1 Jahr', type: 'first-party' }, { name: 'theme', provider: 'Eigene', purpose: 'Design-Einstellung', expiry: '1 Jahr', type: 'first-party' }, ], }, ] const defaultConfig: BannerConfig = { position: 'bottom', style: 'bar', primaryColor: '#6366f1', showDeclineAll: true, showSettings: true, blockScripts: true, } // ============================================================================= // COMPONENTS // ============================================================================= interface BannerTexts { title: string description: string privacyLink: string } function BannerPreview({ config, categories, bannerTexts }: { config: BannerConfig; categories: CookieCategory[]; bannerTexts: BannerTexts }) { return (
Website-Vorschau

{bannerTexts.title}

{bannerTexts.description}

{config.showDeclineAll && ( )} {config.showSettings && ( )}
) } function CategoryCard({ category, onToggle, }: { category: CookieCategory onToggle: (enabled: boolean) => void }) { const [expanded, setExpanded] = useState(false) return (

{category.name}

{category.required && ( Erforderlich )} {category.cookies.length} Cookies

{category.description}

{expanded && (
{category.cookies.map(cookie => ( ))}
Cookie Anbieter Zweck Ablauf
{cookie.name} {cookie.provider} {cookie.purpose} {cookie.expiry}
)}
) } // ============================================================================= // MAIN PAGE // ============================================================================= const defaultBannerTexts: BannerTexts = { title: 'Wir verwenden Cookies', description: 'Wir nutzen Cookies, um Ihnen die bestmoegliche Nutzung unserer Website zu ermoeglichen.', privacyLink: '/datenschutz', } export default function CookieBannerPage() { const { state } = useSDK() const [categories, setCategories] = useState([]) const [config, setConfig] = useState(defaultConfig) const [bannerTexts, setBannerTexts] = useState(defaultBannerTexts) const [isSaving, setIsSaving] = useState(false) const [exportToast, setExportToast] = useState(null) React.useEffect(() => { const loadConfig = async () => { try { const response = await fetch('/api/sdk/v1/einwilligungen/cookie-banner/config') if (response.ok) { const data = await response.json() // DB-Kategorien haben immer Vorrang — Defaults nur wenn DB wirklich leer setCategories(data.categories?.length > 0 ? data.categories : DEFAULT_COOKIE_CATEGORIES) if (data.config && Object.keys(data.config).length > 0) { setConfig(prev => ({ ...prev, ...data.config })) const savedTexts = data.config.banner_texts || data.config.texts if (savedTexts) { setBannerTexts(prev => ({ ...prev, ...savedTexts })) } } } else { setCategories(DEFAULT_COOKIE_CATEGORIES) } } catch { setCategories(DEFAULT_COOKIE_CATEGORIES) } } loadConfig() }, []) const handleCategoryToggle = async (categoryId: string, enabled: boolean) => { setCategories(prev => prev.map(cat => cat.id === categoryId ? { ...cat, enabled } : cat) ) try { await fetch('/api/sdk/v1/einwilligungen/cookie-banner/config', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ categoryId, enabled }), }) } catch { // Silently ignore — local state already updated } } const handleExportCode = async () => { try { const res = await fetch('/api/sdk/v1/einwilligungen/cookie-banner/embed-code') if (res.ok) { const data = await res.json() const code = data.embed_code || data.script || '' await navigator.clipboard.writeText(code) setExportToast('Embed-Code in Zwischenablage kopiert!') setTimeout(() => setExportToast(null), 3000) } else { setExportToast('Fehler beim Laden des Embed-Codes') setTimeout(() => setExportToast(null), 3000) } } catch { setExportToast('Fehler beim Kopieren in die Zwischenablage') setTimeout(() => setExportToast(null), 3000) } } const handleSaveConfig = async () => { setIsSaving(true) try { await fetch('/api/sdk/v1/einwilligungen/cookie-banner/config', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ categories, config: { ...config, banner_texts: bannerTexts } }), }) } catch { // Silently ignore } finally { setIsSaving(false) } } const totalCookies = categories.reduce((sum, cat) => sum + cat.cookies.length, 0) const thirdPartyCookies = categories.reduce( (sum, cat) => sum + cat.cookies.filter(c => c.type === 'third-party').length, 0 ) const stepInfo = STEP_EXPLANATIONS['cookie-banner'] return (
{/* Toast notification */} {exportToast && (
{exportToast}
)} {/* Step Header */}
{/* Stats */}
Kategorien
{categories.length}
Cookies gesamt
{totalCookies}
Third-Party
{thirdPartyCookies}
Aktive Kategorien
{categories.filter(c => c.enabled).length}
{/* Preview */}

Banner-Vorschau

{/* Configuration */}

Banner-Einstellungen

setConfig({ ...config, primaryColor: e.target.value })} className="w-full h-10 rounded-lg cursor-pointer" />

Texte anpassen

setBannerTexts({ ...bannerTexts, title: e.target.value })} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500" />