import { asc, count, eq, inArray } from "drizzle-orm"; import Link from "next/link"; import { notFound, redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { disbandGuild } from "@/actions/admin-guilds"; import { Button } from "@/components/ui/button"; import { db, Guilds, GuildsForumsThreads, GuildsMembers, User } from "@/lib/db"; import { formatDate } from "@/lib/format-date"; import { canAccess, getAdminContext, PERMS } from "@/lib/permissions"; // TODO: Cache Components adoption. Refactor this route so this opt-out can be removed. // See: https://nextjs.org/docs/app/guides/migrating-to-cache-components export const instant = false; export default async function AdminGuildDetailPage({ params, }: { params: Promise<{ id: string }>; }) { const { session, permissions } = await getAdminContext(); if (!canAccess(permissions, PERMS.USERS_VIEW, session.user.rank)) { redirect("/admin"); } const canEdit = canAccess(permissions, PERMS.USERS_EDIT, session.user.rank); const t = await getTranslations("pages.admin.guilds"); const { id: rawId } = await params; const id = Number(rawId); if (!Number.isFinite(id) || id <= 0) notFound(); const [guild] = await db .select({ id: Guilds.id, name: Guilds.name, description: Guilds.description, userId: Guilds.userId, roomId: Guilds.roomId, badge: Guilds.badge, dateCreated: Guilds.dateCreated, state: Guilds.state, forum: Guilds.forum, }) .from(Guilds) .where(eq(Guilds.id, id)) .limit(1); if (!guild) notFound(); const [ownerRows, members, memberCountRows, threadCountRows] = await Promise.all([ db .select({ id: User.id, username: User.username }) .from(User) .where(eq(User.id, guild.userId)) .limit(1) .catch(() => []), db .select({ userId: GuildsMembers.userId, levelId: GuildsMembers.levelId, memberSince: GuildsMembers.memberSince, }) .from(GuildsMembers) .where(eq(GuildsMembers.guildId, id)) .orderBy(asc(GuildsMembers.levelId), asc(GuildsMembers.memberSince)) .limit(100) .catch(() => []), db .select({ total: count() }) .from(GuildsMembers) .where(eq(GuildsMembers.guildId, id)) .catch(() => [{ total: 0 }]), db .select({ total: count() }) .from(GuildsForumsThreads) .where(eq(GuildsForumsThreads.guildId, id)) .catch(() => [{ total: 0 }]), ]); const owner = ownerRows[0] ?? null; const memberCount = Number(memberCountRows[0]?.total ?? 0); const threadCount = Number(threadCountRows[0]?.total ?? 0); const memberUserIds = members.map((m) => m.userId).filter((uid) => uid > 0); const memberUsers = memberUserIds.length > 0 ? await db .select({ id: User.id, username: User.username }) .from(User) .where(inArray(User.id, memberUserIds)) .catch(() => []) : []; const usernameById = new Map(memberUsers.map((u) => [u.id, u.username])); return (
{guild.badge ? ( // eslint-disable-next-line @next/next/no-img-element ) : null}

{guild.name || `#${guild.id}`}

#{guild.id}

{canEdit ? (
) : null}
{guild.description ? (

{guild.description}

) : null}
{t("colOwner")}
{owner ? ( {owner.username} ) : ( `#${guild.userId}` )}
{t("colMembers")}
{memberCount}
{t("colThreads")}
{threadCount}
{t("colCreated")}
{formatDate(new Date(guild.dateCreated * 1000))}
{t("colRoom")}
{guild.roomId > 0 ? ( #{guild.roomId} ) : ( "—" )}

{t("members")} ({Math.min(members.length, memberCount)})

{members.length === 0 ? (
{t("noMembers")}
) : (
{members.map((m) => ( ))}
{t("colUser")} {t("colLevel")} {t("colJoined")}
{usernameById.get(m.userId) ?? `#${m.userId}`} {m.levelId} {formatDate(new Date(m.memberSince * 1000))}
)}
); }