import Link from "next/link"; import { notFound } from "next/navigation"; import { ContentCard, EmptyState } from "@/components/public/ui"; import { prisma } from "@/lib/prisma"; export const dynamic = "force-dynamic"; type ThreadRow = { id: number; openerId: number | null; subject: string | null; postsCount: number | null; createdAt: number | null; updatedAt: number | null; pinned: number | null; locked: number | null; }; function formatTimestamp(ts: number | null | undefined): string { if (!ts) return ""; return new Date(ts * 1000).toISOString().slice(0, 10); } export default async function GuildForumPage({ params, }: { params: Promise<{ id: string }>; }) { const { id } = await params; const guildId = Number(id); if (!Number.isInteger(guildId) || guildId <= 0) notFound(); // Guild header (read-only). A DB hiccup degrades to notFound rather than 500. let guild: { id: number; name: string; badge: string } | null = null; try { guild = await prisma.guilds.findUnique({ where: { id: guildId }, select: { id: true, name: true, badge: true }, }); } catch { guild = null; } if (!guild) notFound(); // Threads for this guild. Pinned first, then most-recently active. let threads: ThreadRow[] = []; try { threads = await prisma.guildsForumsThreads.findMany({ where: { guildId: guild.id, state: 0 }, orderBy: [{ pinned: "desc" }, { updatedAt: "desc" }, { id: "desc" }], take: 100, select: { id: true, openerId: true, subject: true, postsCount: true, createdAt: true, updatedAt: true, pinned: true, locked: true, }, }); } catch { threads = []; } // Resolve opener usernames in one query (no relation exists in the schema, so // join the users table manually by id). Falls back to the raw author id. const openerIds = Array.from( new Set( threads .map((t) => t.openerId ?? 0) .filter((v) => v > 0), ), ); let users: { id: number; username: string }[] = []; try { users = openerIds.length ? await prisma.user.findMany({ where: { id: { in: openerIds } }, select: { id: true, username: true }, }) : []; } catch { users = []; } const usernameById = new Map(users.map((u) => [u.id, u.username])); return (

← Back to guild

+ New thread } /> {threads.length === 0 ? ( No threads in this forum yet. ) : ( {threads.map((t) => { const opener = t.openerId ?? 0; const username = opener > 0 ? usernameById.get(opener) : undefined; return ( ); })}
Subject Author Posts Date
{t.subject?.trim() || "(no subject)"} {t.pinned ? ( 📌 Pinned ) : null} {t.locked ? ( 🔒 Locked ) : null} {username ? ( {username} ) : ( {opener > 0 ? `User #${opener}` : "Unknown"} )} {t.postsCount ?? 0} {formatTimestamp(t.createdAt)}
)}
); }