Files
EpicNext-Cms/src/app/admin/polls/[id]/page.tsx
T

128 lines
3.8 KiB
TypeScript

import { notFound, redirect } from "next/navigation";
import { AdminBreadcrumb } from "@/components/admin/admin-breadcrumb";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
import { PollForm } from "../poll-form";
import { PollQuestionsManager } from "./poll-questions";
import { PollResultsView } from "./poll-results";
export default async function PollDetailPage({
params,
}: {
params: Promise<{ locale: string; id: string }>;
}) {
const { id } = await params;
const { session, permissions } = await getAdminContext();
if (!canAccess(permissions, PERMS.POLLS_EDIT, session.user.rank)) {
redirect("/admin/polls");
}
const pollId = parseInt(id, 10);
if (Number.isNaN(pollId)) notFound();
const poll = await prisma.websitePoll.findUnique({
where: { id: pollId },
include: {
questions: {
orderBy: { sortOrder: "asc" },
include: {
votes: true,
},
},
},
});
if (!poll) notFound();
const totalVoters = new Set(poll.questions.flatMap((q) => q.votes.map((v) => v.userId))).size;
return (
<div className="space-y-6">
<div>
<AdminBreadcrumb items={[{ label: "Polls", href: "/admin/polls" }, { label: poll.title }]} />
<div className="flex items-center gap-3">
<h1 className="text-3xl font-bold tracking-tight">{poll.title}</h1>
<Badge
variant={
poll.status === "active" ? "default" : poll.status === "closed" ? "outline" : "secondary"
}
>
{poll.status}
</Badge>
</div>
{poll.description && <p className="text-muted-foreground">{poll.description}</p>}
</div>
{/* Stats */}
<div className="grid gap-4 md:grid-cols-3">
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Total Voters</CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{totalVoters}</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Questions</CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{poll.questions.length}</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Total Votes</CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{poll.questions.reduce((sum, q) => sum + q.votes.length, 0)}
</div>
</CardContent>
</Card>
</div>
{/* Edit form */}
<PollForm
defaultValues={{
id: poll.id,
title: poll.title,
description: poll.description,
status: poll.status as "draft" | "active" | "closed",
showResults: poll.showResults,
multipleChoice: poll.multipleChoice,
startsAt: poll.startsAt,
endsAt: poll.endsAt,
}}
/>
{/* Questions */}
<PollQuestionsManager
pollId={poll.id}
questions={poll.questions.map((q) => ({
id: q.id,
question: q.question,
type: q.type,
sortOrder: q.sortOrder,
options: q.options,
}))}
/>
{/* Results */}
{poll.questions.length > 0 && (
<PollResultsView
questions={poll.questions.map((q) => ({
id: q.id,
question: q.question,
options: q.options,
votes: q.votes.map((v) => v.answer),
}))}
/>
)}
</div>
);
}