import { useLoaderData } from "react-router"; import { requireAdmin } from "@/session.server"; import prisma from "@/lib/prisma"; const ACTION_LABELS: Record = { LOGIN: "Anmeldung", LOGIN_FAILED: "Anmeldung fehlgeschlagen", LOGOUT: "Abmeldung", CREATE_USER: "Benutzer erstellt", UPDATE_USER: "Benutzer bearbeitet", DELETE_USER: "Benutzer gelöscht", CREATE_COMPANY: "Firma erstellt", UPDATE_COMPANY: "Firma bearbeitet", DELETE_COMPANY: "Firma gelöscht", CREATE_INVOICE: "Rechnung erstellt", UPDATE_INVOICE: "Rechnung bearbeitet", DELETE_INVOICE: "Rechnung gelöscht", }; const ACTION_COLORS: Record = { LOGIN: "bg-green-100 text-green-700", LOGIN_FAILED: "bg-red-100 text-red-700", LOGOUT: "bg-slate-100 text-slate-600", CREATE_USER: "bg-blue-100 text-blue-700", UPDATE_USER: "bg-amber-100 text-amber-700", DELETE_USER: "bg-red-100 text-red-700", CREATE_COMPANY: "bg-blue-100 text-blue-700", UPDATE_COMPANY: "bg-amber-100 text-amber-700", DELETE_COMPANY: "bg-red-100 text-red-700", CREATE_INVOICE: "bg-blue-100 text-blue-700", UPDATE_INVOICE: "bg-amber-100 text-amber-700", DELETE_INVOICE: "bg-red-100 text-red-700", }; export async function loader({ request }: { request: Request }) { await requireAdmin(request); const url = new URL(request.url); const page = Math.max(1, parseInt(url.searchParams.get("page") ?? "1")); const pageSize = 50; const [logs, total] = await Promise.all([ prisma.auditLog.findMany({ orderBy: { createdAt: "desc" }, skip: (page - 1) * pageSize, take: pageSize, include: { user: { select: { name: true, username: true } } }, }), prisma.auditLog.count(), ]); return { logs: logs.map((l) => ({ id: l.id, action: l.action, entity: l.entity, entityId: l.entityId, metadata: l.metadata, ipAddress: l.ipAddress, createdAt: l.createdAt.toISOString(), userName: l.user?.name ?? null, userUsername: l.user?.username ?? null, })), total, page, pageSize, totalPages: Math.ceil(total / pageSize), }; } export default function AdminLogsPage() { const { logs, total, page, totalPages } = useLoaderData(); return (

Audit-Log

{total} Einträge insgesamt

{logs.length === 0 && ( )} {logs.map((log, i) => ( ))}
Zeitpunkt Aktion Benutzer Objekt IP
Noch keine Einträge vorhanden.
{new Date(log.createdAt).toLocaleString("de-DE")} {ACTION_LABELS[log.action] ?? log.action} {log.userName ? ( {log.userName}{" "} @{log.userUsername} ) : ( )} {log.entity ? ( {log.entity} {log.entityId && ( #{log.entityId.slice(0, 8)} )} ) : ( )} {log.ipAddress ?? "—"}
{/* Pagination */} {totalPages > 1 && (
{page > 1 && ( Zurück )} Seite {page} / {totalPages} {page < totalPages && ( Weiter )}
)}
); }