'use client' import React, { useState } from 'react' import { ChecklistView } from './ChecklistView' interface CheckItem { id: string label: string passed: boolean severity: string matched_text: string level?: number parent?: string | null skipped?: boolean hint?: string } interface BannerResult { banner_detected: boolean banner_provider: string banner_checks?: { violations: { code: string; text: string; severity: string }[] has_impressum_link?: boolean has_dse_link?: boolean } structured_checks?: CheckItem[] completeness_pct?: number correctness_pct?: number phases?: { before_consent: { cookies: string[]; scripts: string[]; tracking_services: string[]; violations: any[] } after_reject: { cookies: string[]; scripts: string[]; new_tracking: string[]; violations: any[] } after_accept: { cookies: string[]; scripts: string[]; new_tracking: string[]; undocumented: 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) { 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 structuredChecks = result?.structured_checks || [] const hasStructured = structuredChecks.length > 0 const compPct = result?.completeness_pct ?? 0 const corrPct = result?.correctness_pct ?? 0 // Build ChecklistView-compatible result for structured checks const checklistResults = hasStructured ? [{ label: `Cookie-Banner: ${result?.banner_provider || 'Unbekannt'}`, url: url, doc_type: 'banner', word_count: 0, completeness_pct: compPct, correctness_pct: corrPct, checks: structuredChecks, findings_count: structuredChecks.filter(c => !c.passed && !c.skipped).length, error: '', }] : [] 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 36 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 && (
{/* 3-Phase Summary Card */} {result.phases && (
{result.banner_detected ? '\u{1F6E1}\u{FE0F}' : '\u26A0\u{FE0F}'}

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

3-Phasen-Analyse: Cookies und Scripts vor/nach Interaktion

)} {/* Structured L1/L2 Checklist */} {hasStructured && (
)} {!result.banner_detected && !hasStructured && (

Kein Cookie-Banner auf dieser Seite gefunden. Falls Cookies gesetzt werden, ist ein Banner nach ss25 TDDDG Pflicht.

)}
)}
) } function PhaseBox({ label, icon, cookies, scripts, violations }: { label: string; icon: string; cookies: number; scripts: number; violations: number }) { return (
{icon}
{label}
{cookies} Cookies, {scripts} Scripts
{violations > 0 && (
{violations} Verstoesse
)}
) }