'use client'; import { useState, useEffect } from 'react'; import { db, Item } from '@/lib/db'; import { inventoryApi } from '@/lib/api'; import PageShell from '@/components/PageShell'; import { History, X, Search, Filter, Activity, ArrowDownCircle, ArrowUpCircle, User, RefreshCw } from 'lucide-react'; import { cn } from '@/lib/utils'; import { fetchAndCacheItems } from '@/lib/sync'; export default function LogsPage() { const [auditLogs, setAuditLogs] = useState([]); const [inventory, setInventory] = useState([]); const [loading, setLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [filterAction, setFilterAction] = useState('ALL'); const [selectedLog, setSelectedLog] = useState(null); useEffect(() => { loadData(); }, []); const loadData = async () => { setLoading(true); try { // 1. First, try to get fresh items to resolve names let freshItems: Item[] = []; try { freshItems = await fetchAndCacheItems(); } catch (itemErr) { console.warn("Item sync failed, using local cache for names", itemErr); freshItems = await db.items.toArray(); } setInventory(freshItems); // 2. Then, fetch fresh logs const logs = await inventoryApi.getAuditLogs(100); // 3. Pre-resolve names to avoid UI flickering/mismatches const enrichedLogs = (logs || []).map((log: any) => { // [AUDIT HARDENING] Prioritize the historical snapshot from the backend if (log.target_item_name) { return { ...log, resolved_name: log.target_item_name }; } // Fallback for legacy logs or system operations const hasTarget = log.target_item_id && String(log.target_item_id) !== 'null'; const item = hasTarget ? freshItems.find(i => String(i.id) === String(log.target_item_id)) : null; return { ...log, resolved_name: item ? item.name : (hasTarget ? `Item #${log.target_item_id}` : "System Operation") }; }); setAuditLogs(enrichedLogs); } catch (err: any) { console.error("Critical log load failure:", err); } finally { setLoading(false); } }; const filteredLogs = auditLogs.filter(log => { const matchesSearch = (log.resolved_name || '').toLowerCase().includes(searchQuery.toLowerCase()) || log.action.toLowerCase().includes(searchQuery.toLowerCase()) || (log.username || '').toLowerCase().includes(searchQuery.toLowerCase()); const matchesAction = filterAction === 'ALL' || log.action.includes(filterAction); return matchesSearch && matchesAction; }); // Calculate stats const totalCount = auditLogs.length; const inCount = auditLogs.filter(l => l.action.includes('IN')).length; const outCount = auditLogs.filter(l => l.action.includes('OUT') || l.action.includes('TRASH')).length; const mostActiveUser = auditLogs.length > 0 ? Object.entries(auditLogs.reduce((acc: any, curr) => { const user = curr.username || 'System'; acc[user] = (acc[user] || 0) + 1; return acc; }, {})).sort((a: any, b: any) => b[1] - a[1])[0]?.[0] : 'N/A'; return (

Audit Dashboard

Real-time Intervention Tracking

{/* Stats Grid */}

Total Events

{totalCount}

Check in

{inCount}

Check out

{outCount}

Top Operator

{mostActiveUser}

setSearchQuery(e.target.value)} className="w-full bg-slate-950/50 border border-slate-900 focus:border-primary/50 rounded-3xl py-5 pl-14 pr-6 text-sm text-white placeholder:text-slate-700 outline-none transition-all shadow-2xl" />
{[ { label: 'All', value: 'ALL' }, { label: 'Check in', value: 'CHECK_IN' }, { label: 'Check out', value: 'CHECK_OUT' }, { label: 'Trash', value: 'TRASH' }, { label: 'Create', value: 'CREATE' }, { label: 'System', value: 'DB' } ].map(action => ( ))}
{loading ? (

Securing Audit Stream...

) : filteredLogs.length === 0 ? (

No interventions found

Try adjusting your filters or search query

) : (
{filteredLogs.map((log) => ( ))}
)}
{/* Selected Log Modal */} {selectedLog && (
{selectedLog.action}

{selectedLog.resolved_name}

Operator

{selectedLog.username || 'System Profile'}

Delta

0 ? "text-green-500" : "text-rose-500" )}> {selectedLog.quantity_change ? `${selectedLog.quantity_change > 0 ? '+' : ''}${selectedLog.quantity_change} Units` : (selectedLog.action.includes('DB') ? 'System' : 'No Delta')}

Timestamp

{new Date(selectedLog.timestamp).toLocaleString(undefined, { dateStyle: 'full', timeStyle: 'medium' })}

{selectedLog.target_snapshot && (() => { try { const snap = JSON.parse(selectedLog.target_snapshot) as Record; return (

Full Historical Context

{Object.entries(snap).map(([key, val]) => ( (val && key !== 'image_url') ? (

{key.replace('_', ' ')}

{String(val)}

) : null ))}
); } catch (e) { return null; } })()} {selectedLog.details && (

Intervention Details

"{selectedLog.details}"
)} {selectedLog.target_item_pn && (

Historical Part Number

{selectedLog.target_item_pn}
)}
)}
); }