"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { Loader2, CheckCircle2, AlertCircle, RefreshCw } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { cn } from "@/lib/utils"; import { regenerateAction } from "@/app/(app)/episodes/actions"; const STEPS = [ { key: "SCRIPTING", label: "Writing the script" }, { key: "SYNTHESIZING", label: "Recording the audio" }, { key: "STITCHING", label: "Mixing the audio" }, { key: "ART", label: "Designing the cover art" }, { key: "SAVING", label: "Finalizing" }, ]; const ORDER = ["QUEUED", "SCRIPTING", "SYNTHESIZING", "STITCHING", "ART", "SAVING", "READY"]; export function GenerationProgress({ episodeId, initialStatus, initialStage, initialError, }: { episodeId: string; initialStatus: string; initialStage?: string | null; initialError?: string | null; }) { const router = useRouter(); const [status, setStatus] = useState(initialStatus); const [stage, setStage] = useState(initialStage); const [error, setError] = useState(initialError); const [retrying, setRetrying] = useState(false); useEffect(() => { if (status === "READY" || status === "FAILED") return; const es = new EventSource(`/api/episodes/${episodeId}/stream`); es.onmessage = (e) => { const data = JSON.parse(e.data); if (data.type === "open") return; if (data.status) { setStatus(data.status); setStage(data.stage); if (data.error) setError(data.error); if (data.status === "READY") { es.close(); router.refresh(); } else if (data.status === "FAILED") { es.close(); } } }; es.onerror = () => es.close(); return () => es.close(); }, [episodeId, status, router]); async function retry() { setRetrying(true); setStatus("QUEUED"); setError(null); await regenerateAction(episodeId, "full"); router.refresh(); setRetrying(false); } if (status === "FAILED") { return (

Generation failed

{error || "Something went wrong while producing this episode."}

); } const currentIdx = ORDER.indexOf(status); return (

{stage || "Generating your episode…"}

This usually takes a minute or two.

    {STEPS.map((s) => { const idx = ORDER.indexOf(s.key); const done = currentIdx > idx; const active = status === s.key; return (
  1. {done ? ( ) : active ? ( ) : ( )} {s.label}
  2. ); })}
); }