npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-audit-log-trail

v2.1.1

Published

Headless React hooks and components for laravel-audit-trail

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-trail

Quick 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