Files
erika/app/admin/form/page.tsx
T

153 lines
6.0 KiB
TypeScript

import { db } from "@/db";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Badge } from "@/components/ui/badge";
import { Plus } from "lucide-react";
import { DeleteFormButton } from "@/components/delete-buttons";
import { AdminShellServer } from "@/components/admin-shell-server";
import { createDefaultForm } from "./actions";
import { RealtimeRefresh } from "@/components/realtime-refresh";
import { getFormSubmissionStats } from "@/lib/form-submission-stats";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
export const dynamic = "force-dynamic";
export default async function AdminFormsPage() {
const formsList = await db.query.forms.findMany({
orderBy: (f, { desc }) => [desc(f.createdAt)],
});
const submissionStats = await getFormSubmissionStats(
formsList.map((form) => form.id),
null
);
return (
<AdminShellServer>
<RealtimeRefresh topic="forms" />
<div className="flex w-full flex-col gap-6 p-4 pb-12 md:p-6">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight">Forms</h1>
<p className="text-muted-foreground mt-1">
Manage your custom forms and view submissions.
</p>
</div>
<form action={createDefaultForm}>
<Button type="submit">
<Plus data-icon="inline-start" />
Create form
</Button>
</form>
</div>
<div className="hidden rounded-md border md:block">
<Table>
<TableHeader>
<TableRow>
<TableHead>Title</TableHead>
<TableHead>Status</TableHead>
<TableHead>Responses</TableHead>
<TableHead>Created</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{formsList.length === 0 ? (
<TableRow>
<TableCell colSpan={5} className="h-24 text-center text-muted-foreground">
No forms found. Create one to get started.
</TableCell>
</TableRow>
) : (
formsList.map((form) => (
<TableRow key={form.id} className="group hover:bg-muted/50 transition-colors">
<TableCell className="p-0 align-middle">
<Link href={`/admin/form/${form.id}`} className="flex items-center p-3 font-medium h-full w-full">
{form.title}
</Link>
</TableCell>
<TableCell className="p-0 align-middle">
<Link href={`/admin/form/${form.id}`} className="flex items-center p-3 h-full w-full">
{form.isOpen ? (
<Badge variant="default">Open</Badge>
) : (
<Badge variant="secondary">Closed</Badge>
)}
</Link>
</TableCell>
<TableCell className="p-0 align-middle">
<Link href={`/admin/form/${form.id}/result`} className="flex items-center p-3 h-full w-full">
{submissionStats.get(form.id)?.totalAnswers ?? 0}
</Link>
</TableCell>
<TableCell className="p-0 align-middle">
<Link href={`/admin/form/${form.id}`} className="flex items-center p-3 h-full w-full">
{form.createdAt
? new Date(form.createdAt).toLocaleDateString("en-GB", {
timeZone: "Asia/Bangkok",
})
: "N/A"}
</Link>
</TableCell>
<TableCell className="p-3 text-right">
<div className="flex justify-end gap-2">
<Button variant="outline" asChild size="sm">
<Link href={`/admin/form/${form.id}/result`}>Responses</Link>
</Button>
<DeleteFormButton formId={form.id} />
</div>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
<div className="flex flex-col gap-3 md:hidden">
{formsList.map((form) => (
<Card key={form.id}>
<CardHeader>
<div className="flex items-start justify-between gap-3">
<CardTitle className="text-base">
<Link href={`/admin/form/${form.id}`}>{form.title}</Link>
</CardTitle>
<Badge variant={form.isOpen ? "default" : "secondary"}>
{form.isOpen ? "Open" : "Closed"}
</Badge>
</div>
</CardHeader>
<CardContent className="flex items-center justify-between gap-3">
<Link
href={`/admin/form/${form.id}/result`}
className="text-sm text-muted-foreground"
>
{submissionStats.get(form.id)?.totalAnswers ?? 0} responses
</Link>
<DeleteFormButton formId={form.id} />
</CardContent>
</Card>
))}
{formsList.length === 0 && (
<Card>
<CardHeader>
<CardTitle className="text-base">No forms yet</CardTitle>
</CardHeader>
<CardContent className="text-sm text-muted-foreground">
Create a form to start collecting responses.
</CardContent>
</Card>
)}
</div>
</div>
</AdminShellServer>
);
}