Skip to main content

useAuditLog

Location: src/hooks/useAuditLog.js

Overview

Provides a full-featured interface for viewing admin audit logs. Supports filtering by admin, action type, action category, target, date range, and free-text search. Includes pagination and CSV export. This is an admin-only hook used in the admin panel.

The file also exports several constants and utilities:

  • ACTION_CATEGORIES -- groups of action types organized by category (user, content, report, admin, system)
  • ACTION_LABELS -- human-readable labels for each action type
  • getActionSeverity -- returns a severity level ("danger", "warning", "success", "default") for color-coding actions

Exported Constants

ACTION_CATEGORIES

const ACTION_CATEGORIES: Record<string, {
label: string,
actions: string[]
}>

Categories: user (User Management), content (Content Moderation), report (Reports), admin (Admin Management), system (System).

ACTION_LABELS

const ACTION_LABELS: Record<string, string>

Maps action type keys to display labels (e.g. user_ban -> "Banned User", report_resolve -> "Resolved Report").

getActionSeverity

function getActionSeverity(actionType: string): "danger" | "warning" | "success" | "default"

Returns a severity classification for styling purposes.

Signature

function useAuditLog(): {
logs: AuditLogRow[],
admins: AdminProfile[],
isLoading: boolean,
error: string | null,
hasMore: boolean,
totalCount: number,
fetchLogs: (filters?: FilterOptions) => Promise<void>,
fetchAdmins: () => Promise<void>,
loadMore: (filters: FilterOptions, currentOffset: number) => Promise<void>,
exportCSV: (filters: FilterOptions) => Promise<{ success: boolean, error?: string }>
}

Parameters

None.

Return Value

PropertyTypeDescription
logsAuditLogRow[]Array of audit log entries, each with joined admin profile data. Ordered newest first.
adminsAdminProfile[]List of all admin users for filter dropdowns. Populated by calling fetchAdmins.
isLoadingbooleantrue while a fetch is in progress.
errorstring | nullError message from the most recent failed operation.
hasMorebooleantrue if more pages of logs are available.
totalCountnumberTotal number of matching log entries (from Supabase count).
fetchLogs(filters?) => Promise<void>Fetch logs with optional filters (see below). Replaces the current list unless append: true is set.
fetchAdmins() => Promise<void>Fetch the list of admin users for the filter dropdown.
loadMore(filters, currentOffset) => Promise<void>Load the next page of logs, appending to the existing list.
exportCSV(filters) => PromiseExport matching logs as a CSV file (up to 1000 rows). Triggers a browser download. Returns { success } or { success: false, error }.

FilterOptions

interface FilterOptions {
adminId?: string | null,
actionType?: string | null,
actionCategory?: string | null,
targetType?: string | null,
targetId?: string | null,
dateRange?: "24h" | "7d" | "30d" | "all",
searchTerm?: string | null,
limit?: number, // default 50
offset?: number, // default 0
append?: boolean // default false
}

Usage

function AuditLogViewer() {
const { logs, isLoading, fetchLogs, fetchAdmins, hasMore, loadMore, exportCSV } = useAuditLog();
const [filters, setFilters] = useState({ dateRange: '7d' });

useEffect(() => {
fetchAdmins();
fetchLogs(filters);
}, []);

const handleFilterChange = (newFilters) => {
setFilters(newFilters);
fetchLogs(newFilters);
};

return (
<div>
<button onClick={() => exportCSV(filters)}>Export CSV</button>
{logs.map(log => (
<div key={log.id}>
<span>{ACTION_LABELS[log.action_type]}</span>
<span className={getActionSeverity(log.action_type)}>
{log.admin?.display_name}
</span>
<span>{new Date(log.created_at).toLocaleString()}</span>
</div>
))}
{hasMore && (
<button onClick={() => loadMore(filters, logs.length)}>
Load More
</button>
)}
</div>
);
}

Last updated: 2026-02-07