feat: Cookie-Banner Verarbeiter-Tabelle + Multi-Site UI (F9 + F3)

F9: Verarbeiter-Tabelle
- VendorTable.tsx: 82+ vendors grouped by category with expandable cookie details
- EmbeddableVendorHTML.tsx: Copy-pasteable HTML table for privacy policy
- Tab system: Konfiguration | Verarbeiter | Einbettung

F3: Multi-Site UI
- SiteSelector.tsx: Domain dropdown with "Neue Seite anlegen" dialog
- useCookieBanner hook extended with sites management
- Config/vendors reload per selected site

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-03 20:40:18 +02:00
parent 4c92b17617
commit 36d9f929c6
5 changed files with 395 additions and 2 deletions
@@ -1,18 +1,25 @@
'use client'
import React from 'react'
import React, { useState } from 'react'
import { useSDK } from '@/lib/sdk'
import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader'
import { useCookieBanner } from './_hooks/useCookieBanner'
import { BannerPreview } from './_components/BannerPreview'
import { CategoryCard } from './_components/CategoryCard'
import { VendorTable } from './_components/VendorTable'
import { EmbeddableVendorHTML } from './_components/EmbeddableVendorHTML'
import { SiteSelector } from './_components/SiteSelector'
type BannerTab = 'config' | 'vendors' | 'embed'
export default function CookieBannerPage() {
const { state } = useSDK()
const [activeTab, setActiveTab] = useState<BannerTab>('config')
const {
categories, config, bannerTexts, isSaving, exportToast,
setConfig, setBannerTexts,
handleCategoryToggle, handleExportCode, handleSaveConfig,
sites, activeSiteId, setActiveSiteId, createSite,
} = useCookieBanner()
const totalCookies = categories.reduce((sum, cat) => sum + cat.cookies.length, 0)
@@ -57,6 +64,35 @@ export default function CookieBannerPage() {
</div>
</StepHeader>
{/* Site Selector */}
{sites.length > 0 && (
<SiteSelector sites={sites} activeSiteId={activeSiteId} onSiteChange={setActiveSiteId} onCreateSite={createSite} />
)}
{/* Tabs */}
<div className="flex border-b border-gray-200">
{([
{ id: 'config' as const, label: 'Konfiguration' },
{ id: 'vendors' as const, label: 'Verarbeiter' },
{ id: 'embed' as const, label: 'Einbettung' },
]).map(tab => (
<button key={tab.id} onClick={() => setActiveTab(tab.id)}
className={`px-4 py-3 text-sm font-medium border-b-2 -mb-px transition-colors ${
activeTab === tab.id ? 'text-purple-600 border-purple-600' : 'text-gray-500 border-transparent hover:text-gray-700'
}`}>
{tab.label}
</button>
))}
</div>
{/* Tab: Verarbeiter */}
{activeTab === 'vendors' && <VendorTable siteId={activeSiteId || undefined} />}
{/* Tab: Einbettung */}
{activeTab === 'embed' && <EmbeddableVendorHTML siteId={activeSiteId || undefined} />}
{/* Tab: Konfiguration */}
{activeTab !== 'config' ? null : (<>
{/* Stats */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div className="bg-white rounded-xl border border-gray-200 p-6">
@@ -207,6 +243,7 @@ export default function CookieBannerPage() {
))}
</div>
</div>
</>)}
</div>
)
}