feat: add sub-sidebar result page
This commit is contained in:
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user