161 lines
9.0 KiB
JavaScript
161 lines
9.0 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { Head, router } from '@inertiajs/react';
|
|
import AdminLayout from '@/Layouts/AdminLayout';
|
|
import {
|
|
Search,
|
|
User,
|
|
Globe,
|
|
Terminal
|
|
} from 'lucide-react';
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from '@/components/ui/table';
|
|
import { Badge } from '@/components/ui/badge';
|
|
|
|
export default function AuditLogsHub({ logs = [], search = '', category = 'all' }) {
|
|
const [searchTerm, setSearchTerm] = useState(search || '');
|
|
const [selectedCategory, setSelectedCategory] = useState(category || 'all');
|
|
|
|
const handleSearchSubmit = (e) => {
|
|
e.preventDefault();
|
|
router.get('/admin/audit-logs', {
|
|
search: searchTerm,
|
|
category: selectedCategory
|
|
}, {
|
|
preserveState: true
|
|
});
|
|
};
|
|
|
|
const handleCategorySelect = (cat) => {
|
|
setSelectedCategory(cat);
|
|
router.get('/admin/audit-logs', {
|
|
search: searchTerm,
|
|
category: cat
|
|
});
|
|
};
|
|
|
|
return (
|
|
<AdminLayout title="Logs">
|
|
<Head title="Logs" />
|
|
|
|
<div className="font-sans max-w-7xl mx-auto space-y-6 pb-12">
|
|
|
|
{/* Simplified Header */}
|
|
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 border-b border-slate-200 pb-5">
|
|
<div>
|
|
<h1 className="text-xl font-black text-slate-800 uppercase tracking-tight">System Logs</h1>
|
|
<p className="text-xs text-slate-500 mt-0.5 font-medium">Detailed history of system events.</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Filters Row */}
|
|
<div className="bg-white p-4 rounded-2xl border border-slate-200 shadow-sm flex flex-col md:flex-row gap-4 items-center justify-between">
|
|
<form onSubmit={handleSearchSubmit} className="flex flex-1 items-center space-x-3 w-full md:w-auto">
|
|
<div className="relative flex-1 max-w-md">
|
|
<Search className="absolute left-3.5 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
|
<input
|
|
type="text"
|
|
placeholder="Search logs..."
|
|
className="w-full pl-10 pr-4 py-2.5 bg-slate-50 border border-slate-100 rounded-xl text-xs font-semibold focus:bg-white focus:ring-2 focus:ring-[#0F6E56]/10 outline-none transition-all"
|
|
value={searchTerm}
|
|
onChange={e => setSearchTerm(e.target.value)}
|
|
/>
|
|
</div>
|
|
<button type="submit" className="px-4 py-2.5 bg-[#0F6E56] hover:bg-[#085041] text-white rounded-xl text-xs font-black uppercase tracking-wider transition-colors">
|
|
Search
|
|
</button>
|
|
</form>
|
|
|
|
{/* Category tabs */}
|
|
<div className="flex items-center gap-1 bg-slate-100 p-1 rounded-xl overflow-x-auto w-full md:w-auto">
|
|
{[
|
|
{ label: 'All Logs', val: 'all' },
|
|
{ label: 'Admin Actions', val: 'admin_action' },
|
|
{ label: 'Verifications', val: 'verification' },
|
|
{ label: 'Payments', val: 'payment' },
|
|
{ label: 'Disputes', val: 'dispute' },
|
|
{ label: 'Logins', val: 'user_activity' }
|
|
].map((cat) => (
|
|
<button
|
|
key={cat.val}
|
|
onClick={() => handleCategorySelect(cat.val)}
|
|
className={`px-3 py-1.5 rounded-lg text-[9px] font-black uppercase tracking-widest whitespace-nowrap transition-all ${
|
|
selectedCategory === cat.val
|
|
? 'bg-white text-[#0F6E56] shadow-sm'
|
|
: 'text-gray-500 hover:text-gray-900'
|
|
}`}
|
|
>
|
|
{cat.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Audit Grid table */}
|
|
<div className="bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow className="bg-slate-50/50 hover:bg-slate-50/50 border-b border-slate-150">
|
|
<TableHead className="font-bold text-slate-550 text-[10px] uppercase tracking-widest h-14 pl-8">Log ID & Category</TableHead>
|
|
<TableHead className="font-bold text-slate-550 text-[10px] uppercase tracking-widest h-14">User</TableHead>
|
|
<TableHead className="font-bold text-slate-550 text-[10px] uppercase tracking-widest h-14">Action</TableHead>
|
|
<TableHead className="font-bold text-slate-550 text-[10px] uppercase tracking-widest h-14">IP Address</TableHead>
|
|
<TableHead className="font-bold text-slate-550 text-[10px] uppercase tracking-widest h-14 text-right pr-8">Time</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{logs && logs.length > 0 ? (
|
|
logs.map((log) => (
|
|
<TableRow key={log.id} className="hover:bg-slate-50/50 transition-colors border-b border-slate-100">
|
|
<TableCell className="py-4 pl-8">
|
|
<div className="flex items-center space-x-2">
|
|
<Badge className={`border-none text-[8px] font-black uppercase tracking-wider ${
|
|
log.category === 'admin_action' ? 'bg-red-50 text-red-700' :
|
|
log.category === 'verification' ? 'bg-blue-50 text-blue-700' :
|
|
log.category === 'payment' ? 'bg-emerald-50 text-emerald-700' :
|
|
log.category === 'dispute' ? 'bg-amber-50 text-amber-700' : 'bg-slate-100 text-slate-600'
|
|
}`}>{log.category.replace('_', ' ')}</Badge>
|
|
<span className="font-mono text-[9px] text-slate-400 font-bold">{log.id}</span>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell className="text-xs font-bold text-slate-700">
|
|
<div className="flex items-center space-x-2">
|
|
<User className="w-3.5 h-3.5 text-slate-400" />
|
|
<span>{log.user}</span>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell className="text-xs font-semibold text-slate-600 leading-normal">
|
|
<div className="max-w-[420px] break-words whitespace-normal py-1">
|
|
{log.action}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell className="text-xs font-mono font-medium text-slate-400">
|
|
<div className="flex items-center space-x-1">
|
|
<Globe className="w-3.5 h-3.5 text-slate-300" />
|
|
<span>{log.ip_address}</span>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell className="text-xs text-slate-400 text-right pr-8 font-semibold">{log.timestamp}</TableCell>
|
|
</TableRow>
|
|
))
|
|
) : (
|
|
<TableRow>
|
|
<TableCell colSpan={5} className="py-20 text-center">
|
|
<Terminal className="w-12 h-12 text-slate-200 mx-auto mb-3" />
|
|
<div className="font-bold text-slate-400 uppercase text-xs">No logs found.</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</div>
|
|
</AdminLayout>
|
|
);
|
|
}
|