import { useState, useEffect } from 'react'; import { ChevronDown, ChevronRight, History, Eye, Lock, Unlock, CheckCircle, XCircle, AlertCircle } from 'lucide-react'; import { Badge } from '@/components/ui/badge'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { Skeleton } from '@/components/ui/skeleton'; import { format } from 'date-fns'; import { supabase } from '@/lib/supabaseClient'; import { handleError } from '@/lib/errorHandler'; interface AuditLogEntry { id: string; action: string; moderator_id: string; submission_id: string | null; previous_status: string | null; new_status: string | null; notes: string | null; created_at: string; is_test_data: boolean | null; } interface AuditTrailViewerProps { submissionId: string; } export function AuditTrailViewer({ submissionId }: AuditTrailViewerProps) { const [isOpen, setIsOpen] = useState(false); const [auditLogs, setAuditLogs] = useState([]); const [loading, setLoading] = useState(false); useEffect(() => { if (isOpen && auditLogs.length === 0) { fetchAuditLogs(); } }, [isOpen, submissionId]); const fetchAuditLogs = async () => { try { setLoading(true); const { data, error } = await supabase .from('moderation_audit_log') .select('*') .eq('submission_id', submissionId) .order('created_at', { ascending: false }); if (error) throw error; setAuditLogs(data || []); } catch (error) { handleError(error, { action: 'Fetch Audit Trail', metadata: { submissionId } }); } finally { setLoading(false); } }; const getActionIcon = (action: string) => { switch (action) { case 'viewed': return ; case 'claimed': case 'locked': return ; case 'released': case 'unlocked': return ; case 'approved': return ; case 'rejected': return ; case 'escalated': return ; default: return ; } }; const getActionColor = (action: string) => { switch (action) { case 'approved': return 'text-green-600 dark:text-green-400'; case 'rejected': return 'text-red-600 dark:text-red-400'; case 'escalated': return 'text-orange-600 dark:text-orange-400'; case 'claimed': case 'locked': return 'text-blue-600 dark:text-blue-400'; default: return 'text-muted-foreground'; } }; return ( {isOpen ? : } Audit Trail {auditLogs.length > 0 && ( {auditLogs.length} action{auditLogs.length !== 1 ? 's' : ''} )}
{loading ? (
) : auditLogs.length === 0 ? (
No audit trail entries found
) : (
{auditLogs.map((entry) => (
{getActionIcon(entry.action)}
{entry.action.replace('_', ' ')} {format(new Date(entry.created_at), 'MMM d, HH:mm:ss')}
{(entry.previous_status || entry.new_status) && (
{entry.previous_status && ( {entry.previous_status} )} {entry.previous_status && entry.new_status && ( )} {entry.new_status && ( {entry.new_status} )}
)} {entry.notes && (

{entry.notes}

)}
))}
)}
); }