import { getTranslations } from "next-intl/server"; import { type CfhRow, CfhTable } from "@/app/admin/moderation/cfh/cfh-table"; import type { Prisma } from "@/generated/prisma/client"; import { requireModPermission } from "@/lib/admin/guard"; import { calcPagination, parseListParams } from "@/lib/admin-helpers"; import { PERMS } from "@/lib/permissions"; import { prisma } from "@/lib/prisma"; export default async function ModCfhListPage({ searchParams, }: { searchParams: Promise>; }) { await requireModPermission([PERMS.MOD_CFH_VIEW, PERMS.MODERATION_VIEW]); const t = await getTranslations("pages.admin.cfh"); const raw = await searchParams; const parsed = parseListParams(new URLSearchParams(raw)); const stateRaw = raw.filter_state ?? raw.state; const stateFilter = stateRaw !== undefined && stateRaw !== "" ? Number(stateRaw) : -1; const conditions: Prisma.SupportTicketsWhereInput[] = []; if (stateFilter >= 0) { conditions.push({ state: stateFilter }); } if (parsed.search.trim()) { const q = parsed.search.trim(); const asId = Number(q); let userIds: number[] = []; try { const users = await prisma.user.findMany({ where: { username: { contains: q } }, select: { id: true }, take: 50, }); userIds = users.map((u) => u.id); } catch { userIds = []; } conditions.push({ OR: [ { issue: { contains: q } }, ...(Number.isFinite(asId) && asId > 0 ? [{ id: asId }] : []), ...(userIds.length ? [ { senderId: { in: userIds } }, { reportedId: { in: userIds } }, { modId: { in: userIds } }, ] : []), ], }); } const where: Prisma.SupportTicketsWhereInput = conditions.length === 0 ? {} : conditions.length === 1 ? conditions[0] : { AND: conditions }; const SORT_MAP: Record< string, Prisma.SupportTicketsOrderByWithRelationInput > = { id: { id: "desc" }, issue: { issue: "asc" }, sender: { senderId: "asc" }, reported: { reportedId: "asc" }, mod: { modId: "asc" }, state: { state: "asc" }, }; const baseOrder = SORT_MAP[parsed.sort ?? "id"] ?? { id: "desc" }; const orderField = Object.keys(baseOrder)[0] as keyof typeof baseOrder; const orderBy = { [orderField]: parsed.order, } as Prisma.SupportTicketsOrderByWithRelationInput; const total = await prisma.supportTickets.count({ where }).catch(() => 0); const pagination = calcPagination(total, parsed.page, parsed.perPage); const tickets = await prisma.supportTickets .findMany({ where, orderBy, skip: pagination.offset, take: pagination.perPage, }) .catch(() => []); const userIds = [ ...new Set([ ...tickets.map((x) => x.senderId), ...tickets.map((x) => x.reportedId), ...tickets.map((x) => x.modId), ]), ].filter(Boolean); let userMap = new Map(); if (userIds.length > 0) { try { const users = await prisma.user.findMany({ where: { id: { in: userIds } }, select: { id: true, username: true }, }); userMap = new Map(users.map((u) => [u.id, u.username])); } catch { userMap = new Map(); } } const stateLabels: Record = { 0: t("stateOpen"), 1: t("statePicked"), 2: t("stateClosed"), }; const rows: CfhRow[] = tickets.map((ticket) => ({ id: ticket.id, issue: ticket.issue, roomId: ticket.roomId, when: ticket.timestamp ? new Date(ticket.timestamp * 1000) .toISOString() .slice(0, 16) .replace("T", " ") : "—", sender: userMap.get(ticket.senderId) ?? "—", senderId: ticket.senderId, reported: userMap.get(ticket.reportedId) ?? "—", reportedId: ticket.reportedId, mod: userMap.get(ticket.modId) ?? "—", state: ticket.state, stateLabel: stateLabels[ticket.state] ?? String(ticket.state), })); return (
{total === 0 && !parsed.search && stateFilter < 0 ? (
{t("noTickets")}
) : ( )}
); }