'use client'; import { useState, useEffect, useRef } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { ShieldAlert, Link, Image as ImageIcon, Search, AlertTriangle, CheckCircle, XCircle, Info, Hash, ExternalLink, Brain, Sparkles, Upload } from 'lucide-react'; import { apiClient, guardianClient } from '@/lib/api'; import type { ScamGuardianResponse } from '@/lib/types'; import LiveEvidencePanel from './guardian/LiveEvidencePanel'; import { useGuardianFeed } from '@/hooks/useGuardianFeed'; export default function ScamGuardian() { const [activeTab, setActiveTab] = useState<'text' | 'url' | 'image'>('text'); const [inputValue, setInputValue] = useState(''); const [isAnalyzing, setIsAnalyzing] = useState(false); const [result, setResult] = useState(null); const [history, setHistory] = useState([]); const [guardianStatus, setGuardianStatus] = useState(null); const [isSubmittingFeedback, setIsSubmittingFeedback] = useState(false); const [feedbackSubmitted, setFeedbackSubmitted] = useState(null); const [selectedFile, setSelectedFile] = useState(null); const [previewUrl, setPreviewUrl] = useState(null); const fileInputRef = useRef(null); const liveEvents = useGuardianFeed(); // Load history and status on mount useEffect(() => { fetchHistory(); guardianClient.getGuardianStatus().then(setGuardianStatus).catch(() => null); }, []); const fetchHistory = async () => { try { const res = await guardianClient.getHistory(); setHistory(res); } catch (err) { console.error('History fetch failed', err); } }; const handleAnalyze = async () => { if (!inputValue.trim() && !selectedFile) return; setIsAnalyzing(true); setFeedbackSubmitted(null); try { const payload: any = { source: 'guardian-ui' }; if (activeTab === 'text') payload.text = inputValue; if (activeTab === 'url') payload.url = inputValue; if (activeTab === 'image' && selectedFile) { const base64 = await fileToBase64(selectedFile); payload.image_base64 = base64; } const res = await guardianClient.analyze(payload); setResult(res as unknown as ScamGuardianResponse); fetchHistory(); // Refresh history } catch (err) { console.error(err); } finally { setIsAnalyzing(false); } }; const fileToBase64 = (file: File): Promise => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result as string); reader.onerror = (error) => reject(error); }); }; const handleFileChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { setSelectedFile(file); setPreviewUrl(URL.createObjectURL(file)); } }; const handleFeedback = async (isScam: boolean) => { if (!result) return; setIsSubmittingFeedback(true); try { await guardianClient.submitFeedback({ analyze_id: result.id, is_scam: isScam, notes: "Submitted via Janus Guardian UI" }); setFeedbackSubmitted(isScam ? 'scam' : 'safe'); } catch (err) { console.error("Feedback failed", err); } finally { setIsSubmittingFeedback(false); } }; const getRiskColor = (score: number) => { if (score >= 70) return 'text-red-500 bg-red-500/10 border-red-500/20'; if (score >= 30) return 'text-amber-500 bg-amber-500/10 border-amber-500/20'; return 'text-emerald-500 bg-emerald-500/10 border-emerald-500/20'; }; const getDecisionIcon = (decision: string) => { switch (decision) { case 'BLOCK': return ; case 'WARN': return ; default: return ; } }; return (
{/* Main Analysis Area */}
{/* Header */}

Guardian Sensory

Deep forensic analysis across text, images, and domains. Janus ZeroTrust Mesh provides real-time threat neutralization.

{/* Intake Area */}
{[ { id: 'text', label: 'Detection', icon: }, { id: 'url', label: 'Link Intelligence', icon: }, { id: 'image', label: 'OCR Vision', icon: }, ].map((tab) => ( ))}
{guardianStatus && (
Memory Status: {guardianStatus.db_ready ? 'ACTIVE' : 'DEGRADED'} {guardianStatus.db_mode && ({guardianStatus.db_mode})}
)}
{activeTab === 'text' && (