react-audit-log-trail
v2.1.1
Published
Headless React hooks and components for laravel-audit-trail
Maintainers
Readme
react-audit-log-trail
Headless React hooks and components for laravel-audit-trail.
Handles fetching, pagination, filtering, and diff parsing. You bring the styles.
Installation
npm install react-audit-log-trail
# or
yarn add react-audit-log-trailQuick start
import { useAuditTrail, AuditTimeline } from 'react-audit-log-trail';
function UserAuditLog({ userId }: { userId: string }) {
const { logs, loading, error, nextPage, prevPage, hasNextPage, hasPrevPage } =
useAuditTrail({
endpoint: '/api/audit-logs',
modelType: 'App\\Models\\User',
modelId: userId,
perPage: 20,
headers: { Authorization: `Bearer ${token}` },
});
return (
<>
<AuditTimeline
logs={logs}
loading={loading}
error={error}
renderEntry={(entry) => (
<div className="border-b py-3">
<span className="font-medium">{entry.event}</span>
<span className="text-gray-500 text-sm ml-2">{entry.created_at}</span>
</div>
)}
/>
<div className="flex gap-2 mt-4">
<button onClick={prevPage} disabled={!hasPrevPage}>Previous</button>
<button onClick={nextPage} disabled={!hasNextPage}>Next</button>
</div>
</>
);
}Hooks
useAuditTrail(options)
Fetches and paginates audit logs from your Laravel API.
const {
logs, // AuditLogEntry[]
meta, // PaginationMeta | null
loading, // boolean
error, // string | null
page, // number
setPage, // (page: number) => void
refresh, // () => void
hasNextPage, // boolean
hasPrevPage, // boolean
nextPage, // () => void
prevPage, // () => void
} = useAuditTrail({
endpoint: '/api/audit-logs', // required
modelType: 'App\\Models\\User', // optional filter
modelId: '42', // optional filter
event: 'updated', // optional filter
actorId: '1', // optional filter
from: '2024-01-01', // optional filter
to: '2024-12-31', // optional filter
perPage: 20,
headers: { Authorization: 'Bearer ...' },
});useAuditDiff(options)
Parses a single log entry into a structured diff.
const {
lines, // DiffLine[]
hasChanges, // boolean
addedCount, // number
removedCount, // number
changedFields, // string[]
} = useAuditDiff({ entry });Components
<AuditTimeline />
Headless timeline list. Fully controlled via render props.
<AuditTimeline
logs={logs}
loading={loading}
error={error}
renderEntry={(entry) => <MyCard entry={entry} />}
renderLoading={() => <Spinner />}
renderEmpty={() => <p>No logs yet.</p>}
renderError={(err) => <Alert message={err} />}
className="space-y-2"
/><AuditDiffViewer />
Headless diff renderer. Shows field-level before/after changes.
<AuditDiffViewer
entry={entry}
showUnchanged={false}
renderLine={(line, i) => (
<div
key={i}
className={
line.type === 'added' ? 'bg-green-50 text-green-800' :
line.type === 'removed' ? 'bg-red-50 text-red-800' :
'bg-gray-50'
}
>
<span className="font-mono font-bold">{line.field}</span>
<span>{line.type === 'added' ? String(line.newValue) : String(line.oldValue)}</span>
</div>
)}
/>Utilities
import {
formatAuditDate, // '2d ago' | 'Jan 12, 2024'
formatAuditEvent, // 'created' → 'Created'
auditEventIntent, // 'created' → 'success' (for badge colouring)
formatModelType, // 'App\\Models\\User' → 'User'
formatFieldValue, // any value → readable string
actorInitials, // 'Alice Smith' → 'AS'
expandDiff, // entry → DiffLine[] (GitHub-style two-line diffs)
} from 'react-audit-log-trail';TypeScript
All types are exported:
import type {
AuditLogEntry,
AuditEvent,
DiffLine,
PaginationMeta,
UseAuditTrailOptions,
} from '@devvboy/react-audit-log-trail';Expected API response shape
Your Laravel endpoint should return Laravel's standard pagination format:
{
"data": [
{
"id": "01HX...",
"event": "updated",
"auditable_type": "App\\Models\\User",
"auditable_id": "42",
"actor": { "type": "App\\Models\\User", "id": "1", "name": "Admin" },
"actor_ip": "127.0.0.1",
"before": { "name": "Alice" },
"after": { "name": "Bob" },
"url": "https://app.example.com/users/42",
"metadata": {},
"created_at": "2024-06-01T12:00:00Z"
}
],
"meta": {
"current_page": 1,
"last_page": 5,
"per_page": 20,
"total": 98,
"from": 1,
"to": 20
}
}License
MIT
