import Link from "next/link"; import { Mic2, Plus, Sparkles, ArrowRight, Mic, Gauge, Crown, Infinity as InfinityIcon } from "lucide-react"; import { requireAuth } from "@/lib/auth/guards"; import { getEffectivePlan } from "@/lib/billing/subscription"; import { getUsageSummary } from "@/lib/usage/meter"; import { prisma } from "@/lib/db"; import { UNLIMITED, type UsageMetric } from "@/lib/billing/plans"; import { PageHeader } from "@/components/app/page-header"; import { EpisodeStatusBadge } from "@/components/app/episode-status-badge"; import { StatCard } from "@/components/admin/ui/stat-card"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Progress } from "@/components/ui/progress"; import { EmptyState } from "@/components/ui/empty-state"; const METRIC_LABELS: Record = { script: "Scripts", audio: "Audio generations", art: "Cover art", repurpose: "Repurposed content", }; export default async function DashboardPage() { const session = await requireAuth(); const { plan, key, subjectId } = await getEffectivePlan( session.user.id, session.session.activeOrganizationId ); // Episodes from the last 8 weeks for the sparkline + a 30-day rolling count. const now = new Date(); const eightWeeksAgo = new Date(now); eightWeeksAgo.setDate(eightWeeksAgo.getDate() - 7 * 8); const [episodeCount, recent, recentForSpark, usage] = 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 }, }), prisma.episode.findMany({ where: { userId: session.user.id, createdAt: { gte: eightWeeksAgo } }, select: { createdAt: true }, }), getUsageSummary(subjectId), ]); // Bucket episodes into 8 weekly counts (oldest → newest) for the sparkline. const weeklySpark = Array.from({ length: 8 }, (_, i) => { const start = new Date(eightWeeksAgo); start.setDate(start.getDate() + i * 7); const end = new Date(start); end.setDate(end.getDate() + 7); return recentForSpark.filter((e) => e.createdAt >= start && e.createdAt < end).length; }); const thisWeek = weeklySpark[weeklySpark.length - 1]; // Tightest metered limit: the metric closest to its cap (excluding unlimited). const metrics = (Object.keys(METRIC_LABELS) as UsageMetric[]) .map((m) => { const limit = plan.limits[m]; const used = usage[m]; const unlimited = limit === UNLIMITED; const pct = unlimited ? 0 : Math.min(100, Math.round((used / Math.max(1, limit)) * 100)); return { metric: m, used, limit, unlimited, pct }; }); const tightest = metrics .filter((m) => !m.unlimited) .sort((a, b) => b.pct - a.pct)[0] ?? metrics[0]; const tightestAtLimit = !tightest.unlimited && tightest.used >= tightest.limit; const firstName = session.user.name.split(" ")[0]; return ( <> New episode } />
v > 0) ? weeklySpark : undefined} hint={`${thisWeek} this week`} /> {/* Live usage meter — tightest metered metric */}
{METRIC_LABELS[tightest.metric]} this month

{tightest.used}

{tightest.unlimited ? ( <> Unlimited ) : ( <>of {tightest.limit} )}
{!tightest.unlimited ? ( ) : (

No limits on this metric.

)}
{/* Plan card with inline upgrade */}
Current plan

{plan.name}

{key !== "free" && Active}

{plan.tagline}

{key !== "agency" && ( )}
Recent episodes {recent.length > 0 && ( )} {recent.length === 0 ? ( Create your first episode } /> ) : (
    {recent.map((ep) => (
  • {ep.title}

    {ep.format.replace("_", "-").toLowerCase()} ·{" "} {ep.createdAt.toLocaleDateString()}

  • ))}
)}
); }