'use client' import React, { useState } from 'react' import { useAgentAnalysis } from './_hooks/useAgentAnalysis' import { AnalysisResult } from './_components/AnalysisResult' import { AnalysisHistory } from './_components/AnalysisHistory' import { FollowUpQuestions } from './_components/FollowUpQuestions' import { ScanResult } from './_components/ScanResult' import { DocCheckTab } from './_components/DocCheckTab' type AnalysisMode = 'pre_launch' | 'post_launch' type AnalysisTab = 'quick' | 'scan' | 'doc-check' const MODES: { id: AnalysisMode; label: string; desc: string; icon: string }[] = [ { id: 'pre_launch', label: 'Internes Dokument', desc: 'Vor Veroeffentlichung pruefen', icon: '📋' }, { id: 'post_launch', label: 'Live-Website', desc: 'Bereits online analysieren', icon: '🌐' }, ] const TABS: { id: AnalysisTab; label: string; desc: string }[] = [ { id: 'quick', label: 'Schnellanalyse', desc: 'Einzelne Seite klassifizieren + bewerten' }, { id: 'scan', label: 'Website-Scan', desc: 'Mehrere Seiten scannen + Dienstleister abgleichen' }, { id: 'doc-check', label: 'Dokumenten-Pruefung', desc: 'Einzelne Dokumente gezielt pruefen' }, ] export default function AgentPage() { // Restore state from localStorage on mount const [url, setUrl] = useState(() => typeof window !== 'undefined' ? localStorage.getItem('agent-scan-url') || '' : '') const [mode, setMode] = useState(() => (typeof window !== 'undefined' ? localStorage.getItem('agent-scan-mode') as AnalysisMode : null) || 'post_launch') const [tab, setTab] = useState(() => (typeof window !== 'undefined' ? localStorage.getItem('agent-scan-tab') as AnalysisTab : null) || 'quick') const [scanLoading, setScanLoading] = useState(false) const [scanError, setScanError] = useState(null) const [scanData, setScanData] = useState(() => { if (typeof window === 'undefined') return null try { const s = localStorage.getItem('agent-scan-result'); return s ? JSON.parse(s) : null } catch { return null } }) const [scanProgress, setScanProgress] = useState('') const [activeScanId, setActiveScanId] = useState(() => typeof window !== 'undefined' ? localStorage.getItem('agent-scan-id') || '' : '') const [scanHistory, setScanHistory] = useState<{ url: string; date: string; findings: number; docs: number }[]>(() => { if (typeof window === 'undefined') return [] try { return JSON.parse(localStorage.getItem('agent-scan-history') || '[]') } catch { return [] } }) const { analyze, answerFollowUp, loading, error, result, history } = useAgentAnalysis() // Persist state to localStorage React.useEffect(() => { localStorage.setItem('agent-scan-url', url) }, [url]) React.useEffect(() => { localStorage.setItem('agent-scan-mode', mode) }, [mode]) React.useEffect(() => { localStorage.setItem('agent-scan-tab', tab) }, [tab]) React.useEffect(() => { if (scanData?.services) localStorage.setItem('agent-scan-result', JSON.stringify(scanData)) }, [scanData]) // Resume polling if scan was in progress when page was left React.useEffect(() => { if (!activeScanId || scanData?.services) return let cancelled = false setScanLoading(true) setScanProgress('Scan laeuft noch...') const poll = async () => { while (!cancelled) { await new Promise(r => setTimeout(r, 5000)) try { const res = await fetch(`/api/sdk/v1/agent/scan?scan_id=${activeScanId}`) if (!res.ok) continue const data = await res.json() if (data.progress) setScanProgress(data.progress) if (data.status === 'completed' && data.result) { setScanData(data.result) setScanProgress('') setScanLoading(false) localStorage.setItem('agent-scan-result', JSON.stringify(data.result)) localStorage.removeItem('agent-scan-id') setActiveScanId('') _addToHistory(data.result) return } if (data.status === 'failed') { setScanError(data.error || 'Scan fehlgeschlagen') setScanProgress('') setScanLoading(false) localStorage.removeItem('agent-scan-id') setActiveScanId('') return } if (data.status === 'not_found') { setScanProgress('') setScanLoading(false) localStorage.removeItem('agent-scan-id') setActiveScanId('') return } } catch { /* retry */ } } } poll() return () => { cancelled = true } }, []) // eslint-disable-line react-hooks/exhaustive-deps const _addToHistory = (result: any) => { const entry = { url: url || result.url || '', date: new Date().toISOString(), findings: result.findings?.length || 0, docs: result.discovered_documents?.length || 0, } const updated = [entry, ...scanHistory].slice(0, 50) setScanHistory(updated) localStorage.setItem('agent-scan-history', JSON.stringify(updated)) } const _loadFromHistory = (entry: { url: string }) => { setUrl(entry.url) setTab('scan') // Load saved result if same URL try { const saved = localStorage.getItem('agent-scan-result') if (saved) { const parsed = JSON.parse(saved) if (parsed.url === entry.url) { setScanData(parsed) } } } catch {} } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!url.trim()) return if (tab === 'quick') { analyze(url.trim(), mode) } else { setScanLoading(true) setScanError(null) setScanData(null) setScanProgress('Scan wird gestartet...') try { // Step 1: Start async scan const startRes = await fetch('/api/sdk/v1/agent/scan', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: url.trim(), mode }), }) if (!startRes.ok) throw new Error(`Scan konnte nicht gestartet werden: ${startRes.status}`) const { scan_id } = await startRes.json() if (!scan_id) throw new Error('Keine Scan-ID erhalten') setActiveScanId(scan_id) localStorage.setItem('agent-scan-id', scan_id) // Step 2: Poll for results let attempts = 0 const maxAttempts = 120 // 10 min at 5s intervals while (attempts < maxAttempts) { await new Promise(r => setTimeout(r, 5000)) const pollRes = await fetch(`/api/sdk/v1/agent/scan?scan_id=${scan_id}`) if (!pollRes.ok) { attempts++; continue } const pollData = await pollRes.json() if (pollData.progress) { setScanProgress(pollData.progress) } if (pollData.status === 'completed' && pollData.result) { setScanData(pollData.result) setScanProgress('') localStorage.setItem('agent-scan-result', JSON.stringify(pollData.result)) localStorage.removeItem('agent-scan-id') setActiveScanId('') _addToHistory(pollData.result) break } if (pollData.status === 'failed') { throw new Error(pollData.error || 'Scan fehlgeschlagen') } attempts++ } if (attempts >= maxAttempts) throw new Error('Scan-Timeout (10 Minuten)') } catch (e) { setScanError(e instanceof Error ? e.message : 'Unbekannter Fehler') setScanProgress('') } finally { setScanLoading(false) } } } const isLoading = tab === 'quick' ? loading : scanLoading const currentError = tab === 'quick' ? error : scanError return (

Compliance Agent

Analysiere Dokumente und Webseiten auf DSGVO-Konformitaet.

{/* Mode Selection */}
{MODES.map(m => ( ))}
{/* Tab Selection */}
{TABS.map(t => ( ))}
{/* Doc Check Tab — own component */} {tab === 'doc-check' && } {/* URL Input (quick + scan only) */} {tab !== 'doc-check' &&
setUrl(e.target.value)} placeholder={tab === 'scan' ? 'https://www.example.com/' : 'https://example.com/datenschutz'} 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={isLoading} required />
} {/* Scan Progress */} {scanProgress && tab === 'scan' && (
{scanProgress}
)} {/* Error */} {currentError && (
{currentError}
)} {/* Quick Analysis Result */} {tab === 'quick' && result && (
{result.follow_up_questions.length > 0 && (
)}
)} {/* Scan Result — only render when we have a complete response with services */} {tab === 'scan' && scanData && scanData.services && (
)} {/* History (quick only) */} {tab === 'quick' && ( { setUrl(r.url); analyze(r.url, mode) }} /> )} {/* Scan History */} {tab === 'scan' && scanHistory.length > 0 && (

Letzte Scans

{scanHistory.map((h, i) => ( ))}
)}
) }