/** * Investigation Operations Panel * Case management, assignment, escalation, and timeline tracking */ import { useState } from 'react'; import { useQuery, useMutation } from '@tanstack/react-query'; // DB import commented out for build import { FolderOpen, Search, UserCheck, UserPlus, ArrowUpCircle, ArrowDownCircle, Clock, CheckCircle, AlertTriangle, Shield, Eye, RefreshCw, } from 'lucide-react'; const STATUSES = ['PENDING', 'IN_PROGRESS', 'UNDER_REVIEW', 'ESCALATED', 'COMPLETED', 'ARCHIVED']; const TIERS = ['FREE', 'BASIC', 'PRO', 'ELITE', 'ENTERPRISE']; const PRIORITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']; export default function InvestigationOperations() { const [searchQuery, setSearchQuery] = useState(''); const [statusFilter, setStatusFilter] = useState('all'); const [tierFilter, setTierFilter] = useState('all'); const [priorityFilter, setPriorityFilter] = useState('all'); const [selectedCase, setSelectedCase] = useState(null); const [_showDetailModal, setShowDetailModal] = useState(false); const [showAssignModal, setShowAssignModal] = useState(false); const [showTimeline, setShowTimeline] = useState(false); const [activeTab, setActiveTab] = useState<'active' | 'completed' | 'archived'>('active'); // Fetch investigations const { data: investigations, refetch } = useQuery({ queryKey: ['admin-investigations-ops'], queryFn: async () => { return []; }, }); // Fetch users for assignment const { data: analysts } = useQuery({ queryKey: ['admin-analysts'], queryFn: async () => { return []; }, }); // Update investigation mutation const updateInvestigation = useMutation({ mutationFn: async ({ id, updates }: { id: string; updates: any }) => { console.log('Update investigation', id, updates); return { success: true }; }, onSuccess: () => { refetch(); setShowAssignModal(false); }, }); // Add timeline event mutation const addTimelineEvent = useMutation({ mutationFn: async ({ id, event }: { id: string; event: any }) => { console.log('Add timeline event', id, event); return { success: true }; }, onSuccess: () => refetch(), }); const filteredCases = investigations?.filter((inv: any) => { const matchesSearch = inv.title?.toLowerCase().includes(searchQuery.toLowerCase()) || inv.id?.toLowerCase().includes(searchQuery.toLowerCase()) || inv.wallet_addresses?.some((w: string) => w.toLowerCase().includes(searchQuery.toLowerCase())); const matchesStatus = statusFilter === 'all' || inv.status === statusFilter; const matchesTier = tierFilter === 'all' || inv.tier === tierFilter; const matchesPriority = priorityFilter === 'all' || inv.priority === priorityFilter; // Tab filtering const matchesTab = activeTab === 'active' ? ['PENDING', 'IN_PROGRESS', 'UNDER_REVIEW', 'ESCALATED'].includes(inv.status) : activeTab === 'completed' ? inv.status === 'COMPLETED' : inv.status === 'ARCHIVED'; return matchesSearch && matchesStatus && matchesTier && matchesPriority && matchesTab; }); const stats = { total: investigations?.length || 0, pending: investigations?.filter((i: any) => i.status === 'PENDING').length || 0, inProgress: investigations?.filter((i: any) => i.status === 'IN_PROGRESS').length || 0, escalated: investigations?.filter((i: any) => i.status === 'ESCALATED').length || 0, completed: investigations?.filter((i: any) => i.status === 'COMPLETED').length || 0, critical: investigations?.filter((i: any) => i.priority === 'CRITICAL').length || 0, }; const getStatusColor = (status: string) => { switch (status) { case 'COMPLETED': return 'bg-green-500/20 text-green-400'; case 'IN_PROGRESS': return 'bg-blue-500/20 text-blue-400'; case 'ESCALATED': return 'bg-red-500/20 text-red-400'; case 'UNDER_REVIEW': return 'bg-purple-500/20 text-purple-400'; case 'ARCHIVED': return 'bg-gray-500/20 text-gray-400'; default: return 'bg-yellow-500/20 text-yellow-400'; } }; const getPriorityIcon = (priority: string) => { switch (priority) { case 'CRITICAL': return ; case 'HIGH': return ; case 'MEDIUM': return ; default: return ; } }; return (
{/* Stats */}
{/* Tab Navigation */}
{['active', 'completed', 'archived'].map((tab) => ( ))}
{/* 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" />
{/* Cases Table */}
{filteredCases?.map((inv: any) => ( ))}
Case Status Priority Tier Assigned Wallets Created Actions

{inv.title}

{inv.id?.slice(0, 8)}...

{inv.status?.replace('_', ' ')}
{getPriorityIcon(inv.priority)} {inv.priority}
{inv.tier} {inv.assigned_to ? (
{inv.assigned_to.slice(0, 8)}...
) : ( Unassigned )}
{inv.wallet_addresses?.length || 0} wallets {new Date(inv.created_at).toLocaleDateString()}
{/* Assignment Modal */} {showAssignModal && selectedCase && (

Assign Case

{selectedCase.title}

ID: {selectedCase.id}

{analysts?.map((analyst: any) => ( ))}
)} {/* Timeline Modal */} {showTimeline && selectedCase && (

Case Timeline

{selectedCase.title}

ID: {selectedCase.id}

{(selectedCase.timeline || []).map((event: any, idx: number) => (
{idx < (selectedCase.timeline || []).length - 1 && (
)}

{event.action}

{event.description}

{new Date(event.timestamp).toLocaleString()} • {event.user_id?.slice(0, 8)}...

))} {/* Add Event */}

Add Timeline Event

{ e.preventDefault(); const formData = new FormData(e.currentTarget); addTimelineEvent.mutate({ id: selectedCase.id, event: { action: formData.get('action'), description: formData.get('description'), timestamp: new Date().toISOString(), user_id: 'admin', // Current admin ID }, }); (e.target as HTMLFormElement).reset(); }} className="space-y-2" >