57 lines
2.2 KiB
TypeScript
57 lines
2.2 KiB
TypeScript
import { notFound } from "next/navigation";
|
|
import Link from "next/link";
|
|
import { ArrowLeft } from "lucide-react";
|
|
import { requireAuth } from "@/lib/auth/guards";
|
|
import { prisma } from "@/lib/db";
|
|
import { PageHeader } from "@/components/app/page-header";
|
|
import { SeriesDetailClient } from "@/components/app/series-detail-client";
|
|
import { EpisodeStatusBadge } from "@/components/app/episode-status-badge";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
|
|
export default async function SeriesDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
|
const { id } = await params;
|
|
const session = await requireAuth();
|
|
|
|
const series = await prisma.series.findUnique({
|
|
where: { id },
|
|
include: { episodes: { orderBy: { createdAt: "desc" } } },
|
|
});
|
|
if (!series) notFound();
|
|
if (series.userId !== session.user.id && session.user.role !== "admin") notFound();
|
|
|
|
const planned = (series.plan as unknown as { title: string; topic: string; summary: string }[]) ?? [];
|
|
|
|
return (
|
|
<>
|
|
<Button asChild variant="ghost" size="sm" className="mb-2">
|
|
<Link href="/series">
|
|
<ArrowLeft className="h-4 w-4" /> Back to series
|
|
</Link>
|
|
</Button>
|
|
<PageHeader title={series.title} description={series.description ?? undefined} />
|
|
|
|
<h2 className="mb-3 text-sm font-semibold text-muted-foreground">Planned episodes</h2>
|
|
<SeriesDetailClient seriesId={series.id} episodes={planned} />
|
|
|
|
{series.episodes.length > 0 && (
|
|
<div className="mt-8">
|
|
<h2 className="mb-3 text-sm font-semibold text-muted-foreground">Generated</h2>
|
|
<div className="space-y-2">
|
|
{series.episodes.map((ep) => (
|
|
<Link key={ep.id} href={`/episodes/${ep.id}`}>
|
|
<Card className="transition-shadow hover:shadow-md">
|
|
<CardContent className="flex items-center justify-between py-3">
|
|
<span className="truncate font-medium">{ep.title}</span>
|
|
<EpisodeStatusBadge status={ep.status} />
|
|
</CardContent>
|
|
</Card>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|