import React, { useState, useEffect } from 'react'; import { Database, RefreshCw, ShieldCheck, AlertTriangle, Eye } from 'lucide-react'; interface Snapshot { id: string; program: string; call_name: string; source_url: string; fetched_at: string; version_hash: string; regulation_link_quality?: string; key_rules_count: number; exclusions_count: number; trust_score?: number; } export const SnapshotDashboard: React.FC<{ onTriggerSnapshot?: () => void }> = ({ onTriggerSnapshot }) => { const [snapshots, setSnapshots] = useState([]); const [loading, setLoading] = useState(false); const [health, setHealth] = useState(null); const [searchTerm, setSearchTerm] = useState(""); const [lawHistory, setLawHistory] = useState([]); const loadData = async () => { setLoading(true); try { const [snapsRes, healthRes] = await Promise.all([ fetch('/api/admin/regulation-snapshots'), fetch('/api/admin/credibility-health') ]); const snapsData = await snapsRes.json(); const healthData = await healthRes.json(); setSnapshots(snapsData.snapshots || []); setHealth(healthData); } catch (e) { console.error(e); } setLoading(false); }; useEffect(() => { loadData(); // Load law change history for notifications fetch('/api/admin/law-monitoring/history') .then(r => r.json()) .then(data => setLawHistory(data.history || [])) .catch(() => {}); }, []); const filteredSnapshots = snapshots.filter(s => s.program.toLowerCase().includes(searchTerm.toLowerCase()) || (s.call_name || "").toLowerCase().includes(searchTerm.toLowerCase()) ); const triggerNewSnapshot = async () => { if (onTriggerSnapshot) onTriggerSnapshot(); const url = prompt("Podaj URL regulaminu do snapshotu (np. https://.../regulamin.pdf):"); const program = prompt("Podaj kod programu (np. FENG, PARP_SMART):", "FENG"); if (!url || !program) return; try { const res = await fetch('/api/admin/regulation-engine/trigger-snapshot', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url, program }) }); const data = await res.json(); if (data.status === 'success') { alert(`Snapshot utworzony! ID: ${data.snapshot_id}`); } else { alert("Błąd: " + (data.error || JSON.stringify(data))); } } catch (e) { alert("Błąd wywołania API: " + e); } setTimeout(loadData, 1500); }; return (

Regulation Snapshots Dashboard

{snapshots.length} snapshots
{health && health.components?.acquisition_regulation_link_quality && (
Link Quality: {health.components.acquisition_regulation_link_quality.high_quality_links_pct}% high precision
)} setSearchTerm(e.target.value)} style={{ width: '100%', marginBottom: 8, padding: 6, fontSize: 12 }} /> {/* Law Change Alerts (Cycle 18) */} {lawHistory.length > 0 && (
Recent Law Changes
{lawHistory.slice(0, 4).map((change, i) => (
{new Date(change.timestamp).toLocaleDateString()} — {change.program} → new snapshot created
))}
These changes automatically improved Trust Scores of affected programs.
)}
{filteredSnapshots.length === 0 &&
Brak snapshotów pasujących do filtra.
} {filteredSnapshots.slice(0, 15).map((s, idx) => (
{s.program} — {s.call_name?.slice(0, 50)}
{s.regulation_link_quality || 'medium'}
Hash: {s.version_hash} | Fetched: {new Date(s.fetched_at).toLocaleDateString()} | Rules: {s.key_rules_count} | Exclusions: {s.exclusions_count} {s.trust_score !== undefined && ( 75 ? '#dcfce7' : s.trust_score > 60 ? '#fef3c7' : '#fee2e2', padding: '1px 5px', borderRadius: 3 }}> Trust: {s.trust_score} )}
{s.source_url && ( Otwórz źródło )}
))}
Snapshots są automatycznie wzbogacane o live EUR-Lex + ISAP przy ingestowaniu. Wysoka jakość linków = wyższa wiarygodność certificate'ów.
); }; export default SnapshotDashboard;