import { useState } from 'react'; import { useAuthStore } from '../../auth/auth-store'; import { useAuditLog, type AuditLogParams } from '../../api/queries/admin/audit'; import layout from '../../styles/AdminLayout.module.css'; import styles from './AuditLogPage.module.css'; function defaultFrom(): string { const d = new Date(); d.setDate(d.getDate() - 7); return d.toISOString().slice(0, 10); } function defaultTo(): string { return new Date().toISOString().slice(0, 10); } export function AuditLogPage() { const roles = useAuthStore((s) => s.roles); if (!roles.includes('ADMIN')) { return (
Access Denied -- this page requires the ADMIN role.
); } return ; } function AuditLogContent() { const [from, setFrom] = useState(defaultFrom); const [to, setTo] = useState(defaultTo); const [username, setUsername] = useState(''); const [category, setCategory] = useState(''); const [search, setSearch] = useState(''); const [page, setPage] = useState(0); const [selectedEventId, setSelectedEventId] = useState(null); const [filtersVisible, setFiltersVisible] = useState(true); const pageSize = 25; const params: AuditLogParams = { from: from || undefined, to: to || undefined, username: username || undefined, category: category || undefined, search: search || undefined, page, size: pageSize, }; const audit = useAuditLog(params); const data = audit.data; const totalPages = data?.totalPages ?? 0; const showingFrom = data && data.totalCount > 0 ? page * pageSize + 1 : 0; const showingTo = data ? Math.min((page + 1) * pageSize, data.totalCount) : 0; const selectedEvent = data?.items.find((e) => e.id === selectedEventId) ?? null; return (
Audit Log
{data && (
{data.totalCount.toLocaleString()} events
)}
{/* Left pane — event list */}
{/* Collapsible filter bar */}
{ setFrom(e.target.value); setPage(0); }} />
{ setTo(e.target.value); setPage(0); }} />
{ setUsername(e.target.value); setPage(0); }} />
{ setSearch(e.target.value); setPage(0); }} />
{/* Event list */}
{audit.isLoading ? (
Loading...
) : !data || data.items.length === 0 ? (
No events found.
) : ( data.items.map((event) => (
setSelectedEventId(event.id)} >
{formatTimestamp(event.timestamp)}
{event.username} {event.action}
{event.result}
)) )}
{/* Pagination */} {data && data.totalCount > 0 && (
{showingFrom}-{showingTo} of {data.totalCount.toLocaleString()}
)}
{/* Right pane — detail view */}
{!selectedEvent ? (
Select an event to view details
) : ( <>
Event Info
Timestamp {formatTimestamp(selectedEvent.timestamp)}
User {selectedEvent.username}
Category {selectedEvent.category}
Action {selectedEvent.action}
Target {selectedEvent.target}
Result {selectedEvent.result}
IP Address {selectedEvent.ipAddress}
User Agent {selectedEvent.userAgent}
Detail Payload
                  {JSON.stringify(selectedEvent.detail, null, 2)}
                
)}
); } function formatTimestamp(iso: string): string { try { const d = new Date(iso); return d.toLocaleString(undefined, { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', }); } catch { return iso; } }