'use client' /** * Snapshot-Detail — öffnet einen gespeicherten Check aus der Historie und * zeigt die Ergebnis-Views aus den Rohdaten (kein Re-Crawl), als Modul-Tabs: * Cookies & Tracking + Impressum (DSE/AGB folgen). Impressum wird beim Öffnen * des Tabs nachgeladen (ImpressumAgent auf dem gespeicherten Text). */ import React, { use as useUnwrap, useEffect, useMemo, useState } from 'react' import Link from 'next/link' import { CookieLibraryPanel } from '../../_components/CookieLibraryPanel' import { CookieResultView } from '../../_components/CookieResultView' import { AgentResultTab } from '../../_components/AgentResultTab' export default function SnapshotDetail( { params }: { params: Promise<{ snapshotId: string }> }, ) { const { snapshotId } = useUnwrap(params) const [snap, setSnap] = useState(null) const [check, setCheck] = useState(null) // cookie-check const [impressum, setImpressum] = useState(null) // impressum-check (lazy) const [impLoading, setImpLoading] = useState(false) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [tab, setTab] = useState('') useEffect(() => { let cancelled = false fetch(`/api/sdk/v1/agent/snapshots/${snapshotId}`) .then(r => r.json()) .then(d => { if (cancelled) return if (d?.error) setError(d.error); else setSnap(d) }) .catch(e => { if (!cancelled) setError(String(e)) }) .finally(() => { if (!cancelled) setLoading(false) }) return () => { cancelled = true } }, [snapshotId]) // Cookie-Abgleich einmal laden (Findings + cookie_categories für beide Views). useEffect(() => { let cancelled = false fetch(`/api/sdk/v1/agent/snapshots/${snapshotId}/cookie-check`) .then(r => r.json()) .then(d => { if (!cancelled) setCheck(d) }) .catch(() => { if (!cancelled) setCheck(null) }) return () => { cancelled = true } }, [snapshotId]) const docs = snap?.doc_entries || [] const hasCookies = (snap?.cmp_vendors?.length ?? 0) > 0 const hasImpressum = docs.some( (e: any) => e.doc_type === 'impressum' && (e.text || e.content || '').length > 100) const modules = useMemo(() => [ ...(hasCookies ? [{ key: 'cookie', label: 'Cookies & Tracking' }] : []), ...(hasImpressum ? [{ key: 'impressum', label: 'Impressum' }] : []), ], [hasCookies, hasImpressum]) useEffect(() => { if (!tab && modules.length) setTab(modules[0].key) }, [modules, tab]) // Impressum erst beim Öffnen des Tabs analysieren (ImpressumAgent, ggf. LLM). useEffect(() => { if (tab !== 'impressum' || impressum || impLoading) return setImpLoading(true) fetch(`/api/sdk/v1/agent/snapshots/${snapshotId}/impressum-check`) .then(r => r.json()) .then(setImpressum) .catch(() => setImpressum({ error: 'Impressum-Analyse fehlgeschlagen', findings: [] })) .finally(() => setImpLoading(false)) }, [tab, snapshotId, impressum, impLoading]) const tabBtn = (key: string, label: string) => ( ) return (
‹ Zurück zur Historie {loading ? (
Lade Snapshot…
) : error || !snap ? (
Snapshot nicht gefunden.
) : modules.length === 0 ? (
Dieser Snapshot enthält keine auswertbaren Daten.
) : ( <>
{modules.map(m => tabBtn(m.key, m.label))}
{tab === 'cookie' && hasCookies && (
)} {tab === 'impressum' && ( impLoading ? (
Impressum-Analyse läuft…
) : impressum?.error ? (
{impressum.error}
) : impressum && (impressum.findings?.length || impressum.mc_coverage?.length) ? ( ) : impressum ? (
{impressum.notes || 'Keine Impressum-Auswertung verfügbar.'}
) : null )} )}
) }