feat: Scan state persists across navigation — resume polling on return

- URL, mode, tab, scan result persisted in localStorage
- Active scan_id stored — polling resumes when returning to page
- Scan results survive navigation to other SDK modules
- 'Scan laeuft noch...' shown when returning to in-progress scan
- Cleans up localStorage when scan completes or fails

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-05 10:47:39 +02:00
parent b5cf25f6ab
commit 8e40155459
+65 -4
View File
@@ -21,15 +21,71 @@ const TABS: { id: AnalysisTab; label: string; desc: string }[] = [
]
export default function AgentPage() {
const [url, setUrl] = useState('')
const [mode, setMode] = useState<AnalysisMode>('post_launch')
const [tab, setTab] = useState<AnalysisTab>('quick')
// Restore state from localStorage on mount
const [url, setUrl] = useState(() => typeof window !== 'undefined' ? localStorage.getItem('agent-scan-url') || '' : '')
const [mode, setMode] = useState<AnalysisMode>(() => (typeof window !== 'undefined' ? localStorage.getItem('agent-scan-mode') as AnalysisMode : null) || 'post_launch')
const [tab, setTab] = useState<AnalysisTab>(() => (typeof window !== 'undefined' ? localStorage.getItem('agent-scan-tab') as AnalysisTab : null) || 'quick')
const [scanLoading, setScanLoading] = useState(false)
const [scanError, setScanError] = useState<string | null>(null)
const [scanData, setScanData] = useState<any>(null)
const [scanData, setScanData] = useState<any>(() => {
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<string>('')
const [activeScanId, setActiveScanId] = useState<string>(() => typeof window !== 'undefined' ? localStorage.getItem('agent-scan-id') || '' : '')
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('')
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 handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (!url.trim()) return
@@ -51,6 +107,8 @@ export default function AgentPage() {
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
@@ -68,6 +126,9 @@ export default function AgentPage() {
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('')
break
}
if (pollData.status === 'failed') {