70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
|
|
import type { Metadata } from "next";
|
||
|
|
import Link from "next/link";
|
||
|
|
import { Mic2, Plus } from "lucide-react";
|
||
|
|
import { requireAuth } from "@/lib/auth/guards";
|
||
|
|
import { prisma } from "@/lib/db";
|
||
|
|
import { PageHeader } from "@/components/app/page-header";
|
||
|
|
import { EpisodeCard } from "@/components/app/episode-card";
|
||
|
|
import { Button } from "@/components/ui/button";
|
||
|
|
|
||
|
|
export const metadata: Metadata = { title: "Episodes" };
|
||
|
|
|
||
|
|
export default async function EpisodesPage() {
|
||
|
|
const session = await requireAuth();
|
||
|
|
const episodes = await prisma.episode.findMany({
|
||
|
|
where: { userId: session.user.id },
|
||
|
|
orderBy: { createdAt: "desc" },
|
||
|
|
include: { coverArt: { select: { storageKey: true } } },
|
||
|
|
});
|
||
|
|
|
||
|
|
return (
|
||
|
|
<>
|
||
|
|
<PageHeader
|
||
|
|
title="Episodes"
|
||
|
|
description="Your AI-produced podcast library."
|
||
|
|
action={
|
||
|
|
<Button asChild>
|
||
|
|
<Link href="/episodes/new">
|
||
|
|
<Plus className="h-4 w-4" /> New episode
|
||
|
|
</Link>
|
||
|
|
</Button>
|
||
|
|
}
|
||
|
|
/>
|
||
|
|
|
||
|
|
{episodes.length === 0 ? (
|
||
|
|
<div className="flex flex-col items-center gap-3 rounded-2xl border border-dashed border-border py-16 text-center">
|
||
|
|
<span className="flex h-14 w-14 items-center justify-center rounded-2xl bg-brand/10 text-brand">
|
||
|
|
<Mic2 className="h-6 w-6" />
|
||
|
|
</span>
|
||
|
|
<div>
|
||
|
|
<p className="font-medium">No episodes yet</p>
|
||
|
|
<p className="text-sm text-muted-foreground">Create your first AI-produced episode.</p>
|
||
|
|
</div>
|
||
|
|
<Button asChild>
|
||
|
|
<Link href="/episodes/new">
|
||
|
|
<Plus className="h-4 w-4" /> New episode
|
||
|
|
</Link>
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
) : (
|
||
|
|
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
|
||
|
|
{episodes.map((ep) => (
|
||
|
|
<EpisodeCard
|
||
|
|
key={ep.id}
|
||
|
|
episode={{
|
||
|
|
id: ep.id,
|
||
|
|
title: ep.title,
|
||
|
|
status: ep.status,
|
||
|
|
format: ep.format,
|
||
|
|
language: ep.language,
|
||
|
|
createdAt: ep.createdAt,
|
||
|
|
coverArtKey: ep.coverArt?.storageKey,
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</>
|
||
|
|
);
|
||
|
|
}
|