'use client' import React, { useState } from 'react' interface BannerResult { banner_detected: boolean banner_provider: string banner_text: string banner_checks?: { violations: { code: string; text: string; severity: string }[] passes: { code: string; text: string }[] } phases?: { before_consent: { cookies: number; scripts: number; violations: string[] } after_reject: { cookies: number; scripts: number; violations: string[] } after_accept: { cookies: number; scripts: number; violations: string[] } } } export function BannerCheckTab() { const [url, setUrl] = useState('') const [loading, setLoading] = useState(false) const [progress, setProgress] = useState('') const [error, setError] = useState(null) const [result, setResult] = useState(null) const handleScan = async (e: React.FormEvent) => { e.preventDefault() if (!url.trim()) return setLoading(true) setError(null) setResult(null) setProgress('Cookie-Banner wird analysiert...') try { const res = await fetch('/api/sdk/v1/agent/banner-check', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: url.trim() }), }) if (!res.ok) throw new Error(`Fehler: ${res.status}`) const data = await res.json() if (data.scan_id) { // Async polling let attempts = 0 while (attempts < 60) { await new Promise(r => setTimeout(r, 3000)) const poll = await fetch(`/api/sdk/v1/agent/banner-check?scan_id=${data.scan_id}`) if (!poll.ok) { attempts++; continue } const pollData = await poll.json() if (pollData.progress) setProgress(pollData.progress) if (pollData.status === 'completed' && pollData.result) { setResult(pollData.result) break } if (pollData.status === 'failed') throw new Error(pollData.error || 'Scan fehlgeschlagen') attempts++ } } else { setResult(data) } } catch (e) { setError(e instanceof Error ? e.message : 'Unbekannter Fehler') } finally { setLoading(false) setProgress('') } } const violations = result?.banner_checks?.violations || [] const passes = result?.banner_checks?.passes || [] const total = violations.length + passes.length return (

Cookie-Banner Compliance Check

Playwright-basierter 3-Phasen-Test: Vor Interaktion, nach Ablehnen, nach Akzeptieren. Prueft Dark Patterns, Pre-Consent-Cookies, Farbkontrast, Klick-Paritaet und 20+ weitere Kriterien.

setUrl(e.target.value)} placeholder="https://www.example.com/" className="flex-1 px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent text-sm" disabled={loading} required />
{progress && (
{progress}
)} {error && (
{error}
)} {result && (
{/* Header */}
{result.banner_detected ? '๐Ÿ›ก๏ธ' : 'โš ๏ธ'}

{result.banner_detected ? `Banner erkannt: ${result.banner_provider || 'Unbekannter Anbieter'}` : 'Kein Cookie-Banner erkannt'}

{total > 0 && (

{passes.length}/{total} Pruefungen bestanden

)}
{total > 0 && (
{Math.round(passes.length / total * 100)}%
)}
{/* 3-Phase Summary */} {result.phases && (
{[ { label: 'Vor Consent', data: result.phases.before_consent, icon: '๐Ÿ”’' }, { label: 'Nach Ablehnen', data: result.phases.after_reject, icon: '๐Ÿšซ' }, { label: 'Nach Akzeptieren', data: result.phases.after_accept, icon: 'โœ…' }, ].map(phase => (
{phase.icon}
{phase.label}
{phase.data.cookies} Cookies, {phase.data.scripts} Scripts
{phase.data.violations.length > 0 && (
{phase.data.violations.length} Verstoesse
)}
))}
)} {/* Violations */} {violations.length > 0 && (

Verstoesse ({violations.length})

{violations.map((v, i) => (
{v.text}
{v.code} | {v.severity}
))}
)} {/* Passes */} {passes.length > 0 && (

Bestanden ({passes.length})

{passes.map((p, i) => (
{p.text}
))}
)} {!result.banner_detected && violations.length === 0 && passes.length === 0 && (
Kein Cookie-Banner auf dieser Seite gefunden. Falls Cookies gesetzt werden, ist ein Banner nach ยง25 TDDDG Pflicht.
)}
)}
) }