Initial commit: PodcastYes — AI podcast platform
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
import Link from "next/link";
|
||||
import { Mic2, Plus, Sparkles, ArrowRight } from "lucide-react";
|
||||
import { requireAuth } from "@/lib/auth/guards";
|
||||
import { getEffectivePlan } from "@/lib/billing/subscription";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { PageHeader } from "@/components/app/page-header";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { EpisodeStatusBadge } from "@/components/app/episode-status-badge";
|
||||
|
||||
export default async function DashboardPage() {
|
||||
const session = await requireAuth();
|
||||
const { plan, key } = await getEffectivePlan(
|
||||
session.user.id,
|
||||
session.session.activeOrganizationId
|
||||
);
|
||||
|
||||
const [episodeCount, recent] = await Promise.all([
|
||||
prisma.episode.count({ where: { userId: session.user.id } }),
|
||||
prisma.episode.findMany({
|
||||
where: { userId: session.user.id },
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 5,
|
||||
select: { id: true, title: true, status: true, format: true, createdAt: true },
|
||||
}),
|
||||
]);
|
||||
|
||||
const firstName = session.user.name.split(" ")[0];
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHeader
|
||||
title={`Welcome back, ${firstName}`}
|
||||
description="Spin up a fully produced episode in a couple of minutes."
|
||||
action={
|
||||
<Button asChild>
|
||||
<Link href="/episodes/new">
|
||||
<Plus className="h-4 w-4" /> New episode
|
||||
</Link>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="grid gap-4 sm:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">Episodes created</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="font-display text-4xl font-extrabold tracking-tight">{episodeCount}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">Current plan</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex items-center justify-between">
|
||||
<p className="font-display text-4xl font-extrabold capitalize tracking-tight">{plan.name}</p>
|
||||
{key === "free" && (
|
||||
<Button asChild size="sm" variant="outline">
|
||||
<Link href="/billing">Upgrade</Link>
|
||||
</Button>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">Usage this month</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button asChild size="sm" variant="outline">
|
||||
<Link href="/usage">
|
||||
View usage <ArrowRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card className="mt-6">
|
||||
<CardHeader className="flex flex-row items-center justify-between">
|
||||
<CardTitle>Recent episodes</CardTitle>
|
||||
<Button asChild variant="ghost" size="sm">
|
||||
<Link href="/episodes">View all</Link>
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{recent.length === 0 ? (
|
||||
<div className="flex flex-col items-center gap-3 py-12 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 to get started.
|
||||
</p>
|
||||
</div>
|
||||
<Button asChild>
|
||||
<Link href="/episodes/new">
|
||||
<Sparkles className="h-4 w-4" /> Create your first episode
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<ul className="divide-y">
|
||||
{recent.map((ep) => (
|
||||
<li key={ep.id}>
|
||||
<Link
|
||||
href={`/episodes/${ep.id}`}
|
||||
className="flex items-center justify-between gap-3 py-3 hover:opacity-80"
|
||||
>
|
||||
<div className="min-w-0">
|
||||
<p className="truncate font-medium">{ep.title}</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{ep.format.replace("_", "-").toLowerCase()} ·{" "}
|
||||
{ep.createdAt.toLocaleDateString()}
|
||||
</p>
|
||||
</div>
|
||||
<EpisodeStatusBadge status={ep.status} />
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user