import Link from "next/link"; import { redirect } from "next/navigation"; import { getServerSession } from "next-auth"; import { authOptions } from "@/lib/auth"; import { isAdminEmail, listAdminEmails } from "@/lib/admin"; import { prisma } from "@/lib/prisma"; import type { Prisma } from "@/app/generated/prisma/client"; import { AdminFilterBar } from "@/features/admin/components/admin-filter-bar"; const ENTITY_TYPES = [ "Refund", "Payout", "Trip", "User", "OrganizerVerification", "Payment", ] as const; interface PageProps { searchParams: Promise<{ entityType?: string; action?: string; reviewer?: string; dateFrom?: string; dateTo?: string; }>; } function parseDate(value: string | undefined): Date | undefined { if (!value) return undefined; const d = new Date(value); return Number.isNaN(d.getTime()) ? undefined : d; } export default async function AdminAuditLogPage({ searchParams }: PageProps) { const session = await getServerSession(authOptions); if (!session?.user) redirect("/login?callbackUrl=/admin/audit-log"); if (!isAdminEmail(session.user.email)) { return (

Halaman ini hanya untuk admin SeTrip.

); } const params = await searchParams; const dateFrom = parseDate(params.dateFrom); const dateTo = parseDate(params.dateTo); const where: Prisma.AdminActionLogWhereInput = {}; if (params.entityType && ENTITY_TYPES.includes(params.entityType as never)) { where.entityType = params.entityType; } if (params.action) { where.action = { contains: params.action, mode: "insensitive" }; } if (params.reviewer) { where.adminEmail = params.reviewer; } if (dateFrom || dateTo) { where.createdAt = { ...(dateFrom && { gte: dateFrom }), ...(dateTo && { lte: dateTo }), }; } const logs = await prisma.adminActionLog.findMany({ where, orderBy: { createdAt: "desc" }, take: 200, }); return (

Audit Log

Catatan semua aksi admin lintas entity (refund, payout, trip cancel, user suspend, dst). Append-only. Maksimal 200 baris terbaru per query — pakai filter untuk drill-down.

{logs.length === 0 ? (

Tidak ada audit log yang cocok dengan filter ini.

) : (
{logs.map((row) => ( ))}
Waktu Admin Action Entity Entity ID Payload
{row.createdAt.toLocaleString("id-ID", { day: "2-digit", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit", })} {row.adminEmail} {!row.adminId && ( (deleted) )} {row.action} {row.entityType} {row.payload ? ( {JSON.stringify(row.payload)} ) : ( "—" )}
)}
); } function EntityIdLink({ entityType, entityId, }: { entityType: string; entityId: string; }) { const short = `${entityId.slice(0, 8)}…`; let href: string | null = null; if (entityType === "Trip") href = `/admin/trips/${entityId}`; if (entityType === "User") href = `/admin/users/${entityId}`; if (href) { return ( {short} ); } return {short}; }