import { desc, eq, gt, or } from "drizzle-orm"; import { Ban as BanIcon } from "lucide-react"; import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { createBan, liftBan } from "@/actions/admin-bans"; import { AdminPageShell } from "@/components/admin/admin-page-shell"; import { StatusCard } from "@/components/admin/dashboard"; import { Button } from "@/components/ui/button"; import { unixNow } from "@/lib/bans"; import { Ban, db } from "@/lib/db"; import { formatDate } from "@/lib/format-date"; import { canAccess, getAdminContext, PERMS } from "@/lib/permissions"; export default async function AdminBans() { const { session, permissions } = await getAdminContext(); if (!canAccess(permissions, PERMS.BANS_VIEW, session.user.rank)) { redirect("/admin"); } const t = await getTranslations("pages.admin.bans"); const now = unixNow(); let bans: (typeof Ban.$inferSelect)[] = []; try { bans = await db .select() .from(Ban) .where(or(eq(Ban.banExpire, 0), gt(Ban.banExpire, now))) .orderBy(desc(Ban.timestamp)) .limit(100); } catch { bans = []; } const permanent = bans.filter((b) => b.banExpire === 0).length; const accountBans = bans.filter((b) => b.type === "account").length; return (
0 ? "warn" : "ok"} icon="🔨" /> 0 ? "danger" : "neutral"} icon="⛔" />

{t("newBan")}

{t("activeBans")} ({bans.length})

{bans.length === 0 ? (
{t("noBans")}
) : (
{bans.map((b) => ( ))}
{t("colUserId")} {t("colType")} {t("colReason")} {t("colExpires")}
{b.userId} {b.type} {b.banReason || "—"} {b.banExpire === 0 ? ( {t("permanent")} ) : ( {formatDate(new Date(b.banExpire * 1000))} )}
)}
); }