feat: add sub-sidebar result page

This commit is contained in:
2026-08-01 00:59:58 +07:00 Unverified
parent 255b895112
commit a41baf1435
7 changed files with 141 additions and 23 deletions
+13
View File
@@ -6,6 +6,8 @@ import { authOptions } from "@/lib/auth-options";
import { getSessionDiscordId } from "@/lib/auth";
import { getDiscordMemberProfile } from "@/lib/discord";
import { db } from "@/db";
import { submissions } from "@/db/schema";
import { desc, eq } from "drizzle-orm";
import { notFound } from "next/navigation";
import { isFormAcceptingSubmissions } from "@/lib/form-availability";
@@ -33,6 +35,16 @@ export default async function AdminFormLayout(
if (!form) {
notFound();
}
const responseItems = await db
.select({
id: submissions.id,
userName: submissions.userName,
userDiscordId: submissions.userDiscordId,
})
.from(submissions)
.where(eq(submissions.formId, params.id))
.orderBy(desc(submissions.submittedAt), desc(submissions.id));
let profile = null;
const discordId = getSessionDiscordId(session);
@@ -46,6 +58,7 @@ export default async function AdminFormLayout(
<FormAdminSidebar
formId={params.id}
formTitle={form.title}
responseItems={responseItems}
isOpen={isFormAcceptingSubmissions(form)}
userName={session?.user?.name || ""}
userImage={session?.user?.image || ""}
@@ -8,7 +8,6 @@ import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
} from "@/components/ui/field";
import {
ContextMenu,
@@ -25,7 +24,9 @@ import {
Check,
Clock,
Copy,
ExternalLink,
Loader2,
Maximize2,
Users,
} from "lucide-react";
import { ScrollArea } from "@/components/ui/scroll-area";
@@ -33,6 +34,7 @@ import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
@@ -414,34 +416,45 @@ function AnswerImagePreview({ src, label }: { src: string; label: string }) {
<Button
type="button"
variant="outline"
className="h-auto w-fit p-2"
className="group/image relative h-auto w-fit p-2"
aria-label={`Open image answer for ${label}`}
>
<Image
src={src}
alt=""
alt={`${label} image answer`}
width={224}
height={160}
unoptimized
className="max-h-40 max-w-56 rounded object-contain"
onError={() => setUnavailable(true)}
/>
<span className="absolute right-3 bottom-3 rounded-md bg-background/90 p-1.5 opacity-0 shadow-sm transition-opacity group-hover/image:opacity-100 group-focus-visible/image:opacity-100">
<Maximize2 />
</span>
</Button>
</DialogTrigger>
<DialogContent className="max-w-4xl">
<DialogContent className="max-h-[calc(100vh-2rem)] max-w-[calc(100vw-2rem)] sm:max-w-[calc(100vw-4rem)]">
<DialogHeader>
<DialogTitle>Image answer</DialogTitle>
<DialogDescription>{label}</DialogDescription>
</DialogHeader>
<Image
src={src}
alt=""
width={1200}
height={800}
alt={`${label} image answer`}
width={1920}
height={1080}
unoptimized
className="max-h-[70vh] w-full rounded-md object-contain"
className="max-h-[calc(100vh-10rem)] w-full rounded-md object-contain"
onError={() => setUnavailable(true)}
/>
<DialogFooter>
<Button asChild variant="outline">
<a href={src} target="_blank" rel="noopener noreferrer">
<ExternalLink data-icon="inline-start" />
Open original
</a>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
-9
View File
@@ -141,7 +141,6 @@ export default async function ResultsListPage({
<TableRow>
<TableHead>Respondent</TableHead>
<TableHead>Submitted</TableHead>
<TableHead>Status</TableHead>
<TableHead>Note</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
@@ -149,9 +148,6 @@ export default async function ResultsListPage({
<TableBody>
{rows.map((submission) => {
const detailHref = `/admin/form/${id}/result/${submission.id}${listQuery ? `?return=${encodeURIComponent(listQuery)}` : ""}`;
const edited =
Array.isArray(submission.editHistory) &&
submission.editHistory.length > 0;
return (
<TableRow key={submission.id} className="relative cursor-pointer">
<TableCell>
@@ -177,11 +173,6 @@ export default async function ResultsListPage({
)}
</TableCell>
<TableCell>{formatDate(submission.submittedAt)}</TableCell>
<TableCell>
<Badge variant={edited ? "secondary" : "outline"}>
{edited ? "Edited" : "Original"}
</Badge>
</TableCell>
<TableCell className="max-w-80">
{submission.adminNote ? (
<p className="line-clamp-2 whitespace-pre-wrap text-sm">