/** * Evidence Management Panel * Review, verify, and manage all investigation evidence */ import { useState } from 'react'; import { useQuery, useMutation } from '@tanstack/react-query'; // DB import commented out for build import { FileText, Search, CheckCircle, XCircle, Clock, Shield, Link, Image, FileCode, AlertTriangle, Trash2, RefreshCw, Award, } from 'lucide-react'; const EVIDENCE_TYPES = [ { id: 'TRANSACTION', label: 'Transaction', icon: FileCode, color: 'blue' }, { id: 'CONTRACT', label: 'Contract', icon: FileText, color: 'purple' }, { id: 'SOCIAL', label: 'Social/OSINT', icon: Link, color: 'green' }, { id: 'SCREENSHOT', label: 'Screenshot', icon: Image, color: 'yellow' }, { id: 'AI_ANALYSIS', label: 'AI Analysis', icon: Award, color: 'cyan' }, { id: 'USER_SUBMITTED', label: 'User Submitted', icon: Shield, color: 'orange' }, ]; const VERIFICATION_STATUS = ['UNVERIFIED', 'PENDING', 'VERIFIED', 'REJECTED']; const MOCK_EVIDENCE = [ { id: 'ev_1', type: 'TRANSACTION', title: 'Suspicious Transfer', description: 'Large ETH transfer to mixer', investigationId: 'inv_1', status: 'VERIFIED', createdAt: '2024-01-15', submittedBy: 'analyst_1', priority: 'HIGH' }, { id: 'ev_2', type: 'CONTRACT', title: 'Honeypot Contract', description: 'Contract has hidden transfer restrictions', investigationId: 'inv_2', status: 'PENDING', createdAt: '2024-01-14', submittedBy: 'system', priority: 'CRITICAL' }, { id: 'ev_3', type: 'SOCIAL', title: 'Twitter Intel', description: 'Developer deleted account after launch', investigationId: 'inv_3', status: 'VERIFIED', createdAt: '2024-01-13', submittedBy: 'user_123', priority: 'MEDIUM' }, ]; export default function EvidenceManagement() { const [searchQuery, setSearchQuery] = useState(''); const [typeFilter, setTypeFilter] = useState('all'); const [statusFilter, setStatusFilter] = useState('all'); const [selectedEvidence, setSelectedEvidence] = useState(null); const [showDetailModal, setShowDetailModal] = useState(false); // Fetch all evidence const { data: evidence, isLoading: evidenceLoading, refetch } = useQuery({ queryKey: ['admin-evidence'], queryFn: async () => { return MOCK_EVIDENCE || []; }, }); // Fetch investigations for assignment const { data: investigations } = useQuery({ queryKey: ['admin-investigations'], queryFn: async () => { return [] as any[]; }, }); // Update evidence mutation const updateEvidence = useMutation({ mutationFn: async ({ id, updates }: { id: string; updates: any }) => { console.log('Update evidence', id, updates); return { success: true }; }, onSuccess: () => refetch(), }); // Delete evidence mutation const deleteEvidence = useMutation({ mutationFn: async (id: string) => { console.log('Delete evidence', id); return { success: true }; }, onSuccess: () => refetch(), }); const filteredEvidence = evidence?.filter((e: any) => { const matchesSearch = e.title?.toLowerCase().includes(searchQuery.toLowerCase()) || e.source?.toLowerCase().includes(searchQuery.toLowerCase()) || e.wallet_address?.toLowerCase().includes(searchQuery.toLowerCase()); const matchesType = typeFilter === 'all' || e.evidence_type === typeFilter; const matchesStatus = statusFilter === 'all' || e.verification_status === statusFilter; return matchesSearch && matchesType && matchesStatus; }); const stats = { total: evidence?.length || 0, verified: evidence?.filter((e: any) => e.verification_status === 'VERIFIED').length || 0, pending: evidence?.filter((e: any) => e.verification_status === 'PENDING').length || 0, rejected: evidence?.filter((e: any) => e.verification_status === 'REJECTED').length || 0, unverified: evidence?.filter((e: any) => e.verification_status === 'UNVERIFIED').length || 0, }; const getTypeInfo = (type: string) => { return EVIDENCE_TYPES.find((t) => t.id === type) || EVIDENCE_TYPES[0]; }; const getStatusColor = (status: string) => { switch (status) { case 'VERIFIED': return 'bg-green-500/20 text-green-400'; case 'PENDING': return 'bg-yellow-500/20 text-yellow-400'; case 'REJECTED': return 'bg-red-500/20 text-red-400'; default: return 'bg-gray-500/20 text-gray-400'; } }; return (
{/* Stats */}
{/* Filters */}
setSearchQuery(e.target.value)} className="w-full bg-crypto-dark border border-crypto-border rounded-lg pl-10 pr-4 py-2 text-white" />
{/* Evidence Grid */}
{evidenceLoading ? (
Loading evidence...
) : ( filteredEvidence?.map((item: any) => { const typeInfo = getTypeInfo(item.evidence_type); const TypeIcon = typeInfo.icon; return (
{ setSelectedEvidence(item); setShowDetailModal(true); }} >
{item.verification_status}

{item.title || 'Untitled'}

{item.description || 'No description'}

{item.wallet_address?.slice(0, 8)}... {item.source && ( <> {item.source} )}
{item.confidence || 0}% confidence
{new Date(item.collected_at || item.created_at).toLocaleDateString()}
); }) )}
{/* Detail Modal */} {showDetailModal && selectedEvidence && (

Evidence Details

{/* Header Info */}

{selectedEvidence.evidence_type}

{selectedEvidence.verification_status}

{selectedEvidence.confidence || 0}%

{new Date(selectedEvidence.collected_at).toLocaleDateString()}

{/* Content */}
                  {JSON.stringify(selectedEvidence.content, null, 2)}
                
{/* Chain of Custody */} {selectedEvidence.chain_of_custody && (
{selectedEvidence.chain_of_custody.map((entry: any, idx: number) => (
{entry.action} by {entry.user_id?.slice(0, 8)}... {new Date(entry.timestamp).toLocaleDateString()}
))}
)} {/* Actions */}
)}
); } function StatCard({ title, value, icon: Icon, color }: any) { const colors: any = { blue: 'text-blue-400 bg-blue-500/20', green: 'text-green-400 bg-green-500/20', yellow: 'text-yellow-400 bg-yellow-500/20', red: 'text-red-400 bg-red-500/20', gray: 'text-gray-400 bg-gray-500/20', }; return (
{title}

{value}

); }