import { useState, useEffect, useCallback } from 'react' import { Download, ChevronDown, ChevronRight, FileText } from 'lucide-react' import { DataTable, Pagination, PageHeader, EmptyState } from '@/components/admin' import type { Column } from '@/components/admin' import { adminApi } from '@/api/admin' import { toast } from '@/lib/toast' import { cn } from '@/lib/utils' import type { AuditLogEntry } from '@/types/admin' export function AuditLogsPage() { const [logs, setLogs] = useState([]) const [loading, setLoading] = useState(true) const [page, setPage] = useState(1) const [total, setTotal] = useState(0) const [expandedId, setExpandedId] = useState(null) const [actionFilter, setActionFilter] = useState('') const [resourceFilter, setResourceFilter] = useState('') const pageSize = 25 const fetchLogs = useCallback(async () => { setLoading(true) try { const data = await adminApi.listAuditLogs({ page, per_page: pageSize, action: actionFilter || undefined, resource_type: resourceFilter || undefined, }) setLogs(data.items || []) setTotal(data.total || 0) } catch { toast.error('Failed to load audit logs') } finally { setLoading(false) } }, [page, actionFilter, resourceFilter]) useEffect(() => { fetchLogs() }, [fetchLogs]) const handleExport = async () => { try { const response = await adminApi.exportAuditLogs({ action: actionFilter || undefined, resource_type: resourceFilter || undefined, } as Record) const blob = new Blob([response.data], { type: 'text/csv' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `audit-logs-${new Date().toISOString().split('T')[0]}.csv` a.click() URL.revokeObjectURL(url) toast.success('Export downloaded') } catch { toast.error('Failed to export audit logs') } } const columns: Column[] = [ { key: 'expand', header: '', className: 'w-8', render: (log) => ( ), }, { key: 'action', header: 'Action', render: (log) => ( {log.action} ), }, { key: 'resource', header: 'Resource', render: (log) => ( {log.resource_type}{log.resource_id ? ` (${log.resource_id.slice(0, 8)}...)` : ''} ), }, { key: 'user', header: 'User', render: (log) => ( {log.user_email || 'System'} ), }, { key: 'created_at', header: 'Time', render: (log) => ( {new Date(log.created_at).toLocaleString()} ), }, ] return (
Export CSV } />
{ setActionFilter(e.target.value); setPage(1) }} placeholder="Filter by action..." className={cn( 'h-9 rounded-md border border-border bg-card px-3 text-sm text-foreground', 'placeholder:text-muted-foreground focus:outline-none focus:border-primary focus:ring-2 focus:ring-primary/20' )} /> { setResourceFilter(e.target.value); setPage(1) }} placeholder="Filter by resource type..." className={cn( 'h-9 rounded-md border border-border bg-card px-3 text-sm text-foreground', 'placeholder:text-muted-foreground focus:outline-none focus:border-primary focus:ring-2 focus:ring-primary/20' )} />
log.id} isLoading={loading} emptyState={ } title="No audit logs" description="Activity will appear here as actions are taken on the platform." /> } /> {/* Expanded details row */} {expandedId && logs.find(l => l.id === expandedId)?.details && (

Details

            {JSON.stringify(logs.find(l => l.id === expandedId)?.details, null, 2)}
          
)}
) } export default AuditLogsPage