import React, { useCallback, useEffect, useState } from 'react' import { adminApi } from '../../api/client' import { useTranslation } from '../../i18n' import { RefreshCw, ClipboardList } from 'lucide-react' interface AuditEntry { id: number created_at: string user_id: number | null username: string | null user_email: string | null action: string resource: string | null details: Record | null ip: string | null } interface AuditLogPanelProps { serverTimezone?: string } export default function AuditLogPanel({ serverTimezone }: AuditLogPanelProps): React.ReactElement { const { t, locale } = useTranslation() const [entries, setEntries] = useState([]) const [total, setTotal] = useState(0) const [offset, setOffset] = useState(0) const [loading, setLoading] = useState(true) const limit = 100 const loadFirstPage = useCallback(async () => { setLoading(true) try { const data = await adminApi.auditLog({ limit, offset: 0 }) as { entries: AuditEntry[] total: number } setEntries(data.entries || []) setTotal(data.total ?? 0) setOffset(0) } catch { setEntries([]) setTotal(0) setOffset(0) } finally { setLoading(false) } }, []) const loadMore = useCallback(async () => { const nextOffset = offset + limit setLoading(true) try { const data = await adminApi.auditLog({ limit, offset: nextOffset }) as { entries: AuditEntry[] total: number } setEntries((prev) => [...prev, ...(data.entries || [])]) setTotal(data.total ?? 0) setOffset(nextOffset) } catch { /* keep existing */ } finally { setLoading(false) } }, [offset]) useEffect(() => { loadFirstPage() }, [loadFirstPage]) const fmtTime = (iso: string) => { try { return new Date(iso.endsWith('Z') ? iso : iso + 'Z').toLocaleString(locale, { dateStyle: 'short', timeStyle: 'medium', timeZone: serverTimezone || undefined, }) } catch { return iso } } const fmtDetails = (d: Record | null) => { if (!d || Object.keys(d).length === 0) return '—' try { return JSON.stringify(d) } catch { return '—' } } const userLabel = (e: AuditEntry) => { if (e.username) return e.username if (e.user_email) return e.user_email if (e.user_id != null) return `#${e.user_id}` return '—' } return (

{t('admin.tabs.audit')}

{t('admin.audit.subtitle')}

{t('admin.audit.showing', { count: entries.length, total })}

{loading && entries.length === 0 ? (
{t('common.loading')}
) : entries.length === 0 ? (
{t('admin.audit.empty')}
) : (
{entries.map((e) => ( ))}
{t('admin.audit.col.time')} {t('admin.audit.col.user')} {t('admin.audit.col.action')} {t('admin.audit.col.resource')} {t('admin.audit.col.ip')} {t('admin.audit.col.details')}
{fmtTime(e.created_at)} {userLabel(e)} {e.action} {e.resource || '—'} {e.ip || '—'} {fmtDetails(e.details)}
)} {entries.length < total && ( )}
) }