82 lines
3.1 KiB
TypeScript
82 lines
3.1 KiB
TypeScript
import { db } from "@/db";
|
|
import Link from "next/link";
|
|
import {
|
|
Card,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import { HtmlDisplay } from "@/components/html-display";
|
|
import { getServerSession } from "next-auth";
|
|
import { authOptions } from "@/lib/auth/auth-options";
|
|
import { canAccessForm, getSessionDiscordId } from "@/lib/auth/auth";
|
|
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { getFormSubmissionStats } from "@/lib/form/form-submission-stats";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export default async function FormsListingPage() {
|
|
const formsList = await db.query.forms.findMany({
|
|
where: (f, { and, eq, gt, isNull, or }) =>
|
|
and(
|
|
eq(f.isOpen, true),
|
|
or(isNull(f.closesAt), gt(f.closesAt, new Date()))
|
|
),
|
|
orderBy: (f, { desc }) => [desc(f.createdAt)],
|
|
});
|
|
|
|
const session = await getServerSession(authOptions);
|
|
const discordId = getSessionDiscordId(session);
|
|
const visibleForms = [];
|
|
for (const form of formsList) {
|
|
if (await canAccessForm(form, discordId)) {
|
|
visibleForms.push(form);
|
|
}
|
|
}
|
|
const submissionStats = await getFormSubmissionStats(
|
|
visibleForms.map((form) => form.id),
|
|
discordId
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<RealtimeRefresh topic="forms" />
|
|
<div className="mx-auto flex max-w-4xl flex-col gap-6 rounded-lg bg-background/90 p-4 text-foreground shadow-sm backdrop-blur md:p-6">
|
|
<h1 className="text-3xl font-bold tracking-tight text-foreground">Form ทั้งหมด</h1>
|
|
{visibleForms.length === 0 ? (
|
|
<p className="text-muted-foreground">ตอนนี้ยังไม่เปิดรับสัก Form</p>
|
|
) : (
|
|
<div className="flex flex-col gap-4">
|
|
{visibleForms.map((form) => (
|
|
<Link key={form.id} href={`/form/${form.id}`}>
|
|
<Card className="hover:bg-muted/50 transition-colors h-full flex flex-col">
|
|
<CardHeader>
|
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
<CardTitle>{form.title}</CardTitle>
|
|
<div className="flex flex-wrap gap-2">
|
|
<Badge variant="secondary">
|
|
{submissionStats.get(form.id)?.totalAnswers ?? 0} คำตอบ
|
|
</Badge>
|
|
{submissionStats.get(form.id)?.queueNumber != null && (
|
|
<Badge variant="outline">
|
|
ลำดับของคุณ #{submissionStats.get(form.id)?.queueNumber}
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
</div>
|
|
{form.description && (
|
|
<div className="line-clamp-3 text-sm text-muted-foreground mt-1.5">
|
|
<HtmlDisplay html={form.description} />
|
|
</div>
|
|
)}
|
|
</CardHeader>
|
|
</Card>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
}
|