'use client' /** * CookieResultView — strukturierte Cookie-/Vendor-Auswertung aus einem * gespeicherten Snapshot (cmp_vendors), OHNE Re-Crawl. * * KPIs + Empfänger-Gruppen (Eigene / Auftragsverarbeiter / Joint Controller — * wie im Audit-Mail-VVT) + aufklappbare Vendor→Cookie-Tabelle. Verarbeitet * Mengen (780 Cookies bei BMW): Vendors gruppiert, Cookies on-demand. */ import React, { useMemo, useState } from 'react' export interface SnapshotCookie { name: string expiry?: string purpose?: string is_third_party?: boolean functional_role?: string } export interface SnapshotVendor { name: string cookies?: SnapshotCookie[] category?: string country?: string recipient_type?: string compliance_score?: number compliance_flags?: string[] opt_out_ok?: boolean } interface Snapshot { id: string site_domain?: string created_at?: string cmp_vendors?: SnapshotVendor[] } const ROLE_LABEL: Record = { unknown: 'Unbekannt', ad_pixel: 'Werbe-Pixel', auth_token: 'Auth-Token', preference: 'Präferenz', visitor_id: 'Besucher-ID', consent_state: 'Consent', tracking: 'Tracking', } const CAT_COLOR: Record = { necessary: 'bg-green-100 text-green-700', functional: 'bg-blue-100 text-blue-700', statistics: 'bg-amber-100 text-amber-700', marketing: 'bg-red-100 text-red-700', } const EEA = new Set([ 'DE','FR','IE','NL','AT','BE','BG','HR','CY','CZ','DK','EE','FI','GR','HU', 'IT','LV','LT','LU','MT','PL','PT','RO','SK','SI','ES','SE','IS','LI','NO', ]) const GROUPS = [ { key: 'own', label: 'Eigene Verarbeitungen (VVT, Art. 30)', test: (r: string) => !r || r === 'INTERNAL' || r === 'GROUP' }, { key: 'proc', label: 'Auftragsverarbeiter (AVV, Art. 28)', test: (r: string) => r === 'PROCESSOR' }, { key: 'joint', label: 'Eigenverantwortliche Dritte / Joint Controller (Art. 26)', test: (r: string) => r === 'JOINT_CONTROLLER' || r === 'CONTROLLER' }, { key: 'other', label: 'Sonstige Empfänger', test: () => true }, ] function scoreColor(s?: number): string { if (s == null) return 'text-gray-400' return s >= 80 ? 'text-green-700' : s >= 50 ? 'text-amber-700' : 'text-red-700' } function Tile({ label, value, tone }: { label: string; value: React.ReactNode; tone: string }) { return (
{value}
{label}
) } function VendorRow({ v }: { v: SnapshotVendor }) { const [open, setOpen] = useState(false) const cookies = v.cookies || [] const cat = (v.category || '').toLowerCase() const drittland = !!v.country && !EEA.has((v.country || '').toUpperCase()) return (
{open && cookies.length > 0 && (
{cookies.map((c, i) => ( ))}
Cookie Rolle Zweck Laufzeit
{c.name} {ROLE_LABEL[c.functional_role || 'unknown'] || c.functional_role} {c.purpose ? c.purpose.slice(0, 60) : kein Zweck} {c.expiry || '—'}
)}
) } export function CookieResultView({ snapshot }: { snapshot: Snapshot }) { const vendors = snapshot.cmp_vendors || [] const stats = useMemo(() => { const cookies = vendors.reduce((n, v) => n + (v.cookies?.length || 0), 0) const marketing = vendors.filter(v => (v.category || '').toLowerCase() === 'marketing').length const drittland = vendors.filter(v => v.country && !EEA.has(v.country.toUpperCase())).length return { cookies, marketing, drittland } }, [vendors]) const grouped = useMemo(() => GROUPS.map(g => ({ ...g, vendors: vendors .filter(v => GROUPS.find(gg => gg.test((v.recipient_type || '').toUpperCase()))?.key === g.key) .sort((a, b) => (a.compliance_score ?? 100) - (b.compliance_score ?? 100)), })).filter(g => g.vendors.length > 0), [vendors]) return (

Cookie-Auswertung — {snapshot.site_domain || 'Snapshot'}

aus gespeichertem Snapshot (kein Re-Crawl) ·{' '} {snapshot.created_at ? snapshot.created_at.slice(0, 19).replace('T', ' ') : ''}

0 ? 'text-red-700' : 'text-gray-800'} /> 0 ? 'text-amber-700' : 'text-gray-800'} />
{grouped.map(g => (
{g.label} ({g.vendors.length})
{g.vendors.map((v, i) => )}
))}
) }