Comprehensive admin + user dashboards (production-ready)
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
export default function EpisodeLoading() {
|
||||
return (
|
||||
<div className="animate-pulse space-y-6">
|
||||
<div className="space-y-2">
|
||||
<div className="h-9 w-72 rounded-xl bg-secondary" />
|
||||
<div className="h-4 w-48 rounded-lg bg-secondary/70" />
|
||||
</div>
|
||||
<div className="grid gap-6 lg:grid-cols-3">
|
||||
<div className="space-y-6 lg:col-span-1">
|
||||
<div className="aspect-square rounded-2xl border border-border bg-secondary" />
|
||||
<div className="h-32 rounded-2xl border border-border bg-card" />
|
||||
<div className="h-11 rounded-full bg-secondary" />
|
||||
</div>
|
||||
<div className="space-y-4 lg:col-span-2">
|
||||
<div className="h-14 rounded-2xl border border-border bg-card" />
|
||||
{Array.from({ length: 3 }).map((_, i) => (
|
||||
<div key={i} className="h-40 rounded-2xl border border-border bg-card" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import Link from "next/link";
|
||||
import { MicOff } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
export default function EpisodeNotFound() {
|
||||
return (
|
||||
<div className="flex min-h-[60vh] flex-col items-center justify-center gap-5 text-center">
|
||||
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-secondary text-muted-foreground">
|
||||
<MicOff className="h-7 w-7" />
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<h1 className="font-display text-2xl font-extrabold tracking-tight">Episode not found</h1>
|
||||
<p className="max-w-sm text-sm text-muted-foreground">
|
||||
This episode doesn't exist, or you don't have access to it.
|
||||
</p>
|
||||
</div>
|
||||
<Button asChild>
|
||||
<Link href="/episodes">Back to episodes</Link>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -32,7 +32,11 @@ export default async function EpisodePage({ params }: { params: Promise<{ id: st
|
||||
<PageHeader
|
||||
title={episode.title}
|
||||
description={`${episode.format.replace("_", "-").toLowerCase()} · ${episode.language.toUpperCase()} · ${episode.targetLengthMin} min`}
|
||||
action={!inProgress ? <EpisodeActions episodeId={episode.id} /> : undefined}
|
||||
action={
|
||||
!inProgress ? (
|
||||
<EpisodeActions episodeId={episode.id} initialShareId={episode.shareId} />
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
{episode.status === "FAILED" || inProgress ? (
|
||||
@@ -68,6 +72,7 @@ export default async function EpisodePage({ params }: { params: Promise<{ id: st
|
||||
<AudioPlayer
|
||||
storageKey={episode.audioAsset.storageKey}
|
||||
durationSec={episode.audioAsset.durationSec}
|
||||
episodeId={episode.id}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user