From dfa1785c84244fd2a2d3135276629cbfdd2f0a48 Mon Sep 17 00:00:00 2001 From: trafficlunar Date: Thu, 2 Apr 2026 19:07:01 +0100 Subject: [PATCH] feat: better reports --- src/app/admin/page.tsx | 2 +- src/components/admin/report-tabs.tsx | 32 +++++++++++++++++ src/components/admin/reports.tsx | 54 ++++++++++++++++++++++++++-- src/lib/auth.ts | 8 +++++ 4 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 src/components/admin/report-tabs.tsx diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 1719253..679ec87 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -70,7 +70,7 @@ export default async function AdminPage({ searchParams }: Props) {
- + {/* Queue */}
diff --git a/src/components/admin/report-tabs.tsx b/src/components/admin/report-tabs.tsx new file mode 100644 index 0000000..d29339e --- /dev/null +++ b/src/components/admin/report-tabs.tsx @@ -0,0 +1,32 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useTransition } from "react"; +import { ReportStatus } from "@prisma/client"; + +export default function ReportTabs({ status }: { status?: ReportStatus }) { + const router = useRouter(); + const [isPending, startTransition] = useTransition(); + + return ( +
+ {["ALL", "OPEN", "RESOLVED", "DISMISSED"].map((s) => ( + + ))} +
+ ); +} diff --git a/src/components/admin/reports.tsx b/src/components/admin/reports.tsx index c920eb1..8a7b12b 100644 --- a/src/components/admin/reports.tsx +++ b/src/components/admin/reports.tsx @@ -5,10 +5,27 @@ import { Icon } from "@iconify/react"; import { ReportStatus } from "@prisma/client"; import { prisma } from "@/lib/prisma"; +import ReportTabs from "./report-tabs"; -export default async function Reports() { - const reports = await prisma.report.findMany({ orderBy: { createdAt: "desc" } }); - // TODO: add pagination +const PAGE_SIZE = 20; + +export default async function Reports({ searchParams }: { searchParams: { status?: string; page?: string } }) { + const status = searchParams.status as ReportStatus | undefined; + const page = Number(searchParams.page ?? 1); + + const [reports, total] = await Promise.all([ + prisma.report.findMany({ + where: status ? { status } : undefined, + orderBy: { createdAt: "desc" }, + skip: (page - 1) * PAGE_SIZE, + take: PAGE_SIZE, + }), + prisma.report.count({ + where: status ? { status } : undefined, + }), + ]); + + const totalPages = Math.ceil(total / PAGE_SIZE); const updateStatus = async (formData: FormData) => { "use server"; @@ -25,6 +42,9 @@ export default async function Reports() { return (
+ + + {/* Grid */}
{reports.map((report) => (
@@ -150,6 +170,34 @@ export default async function Reports() {

Reports will appear here when users submit them

)} + + {/* Pagination */} + {totalPages > 1 && ( +
+ {total} total +
+ {page > 1 && ( + + Previous + + )} + + Page {page} of {totalPages} + + {page < totalPages && ( + + Next + + )} +
+
+ )}
); } diff --git a/src/lib/auth.ts b/src/lib/auth.ts index dbefdb9..b0edd81 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -13,6 +13,14 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ signIn: "/login", }, callbacks: { + async signIn({ user }) { + const blacklist = process.env.BLACKLISTED_EMAILS ? process.env.BLACKLISTED_EMAILS.split(",").map((item) => item.trim().toLowerCase()) : []; + const email = user?.email?.toLowerCase(); + if (!email) return false; + if (blacklist?.some((blocked) => email.endsWith(blocked))) return false; + return true; + }, + async session({ session, user }) { if (user) { session.user.id = user.id;