"use client"; import React, { useState, useEffect } from "react"; import { Card, CardContent } from "@/components/ui/Card"; import { ProgressBar } from "@/components/ui/ProgressBar"; import { LoadingSpinner } from "@/components/ui/LoadingSpinner"; import { Sparkles, Image as ImageIcon, Database, CheckCircle2, AlertCircle, Wand2, Zap, X } from "lucide-react"; import type { GenerationProgress } from "@/types"; import { useGenerationStore } from "@/store/generationStore"; interface GenerationProgressProps { progress: GenerationProgress; generationStartTime?: number | null; } const STEPS = [ { key: "copy", label: "Crafting Copy", icon: Sparkles, color: "from-blue-500 to-cyan-500", messages: [ "Brainstorming compelling headlines...", "Writing persuasive ad copy...", "Polishing the perfect message...", "Adding psychological triggers...", ] }, { key: "image", label: "Generating Images", icon: ImageIcon, color: "from-cyan-500 to-pink-500", messages: [ "Creating stunning visuals...", "Bringing your vision to life...", "Rendering high-quality images...", "Adding creative flair...", "Generation may take a while...", "Almost there!", "Working on the perfect image...", "This is worth the wait...", "Crafting something amazing...", "Just a few more moments...", ] }, { key: "saving", label: "Saving", icon: Database, color: "from-pink-500 to-purple-500", messages: [ "Storing your creative...", "Securing your masterpiece...", "Almost done...", "Finalizing everything...", ] }, ] as const; // Engaging messages for when stuck at high progress const ENGAGING_MESSAGES = [ "Generation may take a while, but great things are worth waiting for!", "Almost there! We're putting the finishing touches on your ad.", "Hang tight! We're creating something amazing for you.", "This is taking a bit longer, but we're ensuring top quality!", "Just a few more moments... Your ad is almost ready!", "We're working hard to make this perfect for you!", "Great things take time - we're crafting your masterpiece!", "Almost done! We're making sure everything is just right.", ] as const; export const GenerationProgressComponent: React.FC = ({ progress, generationStartTime, }) => { const [currentMessageIndex, setCurrentMessageIndex] = useState(0); const [elapsedTime, setElapsedTime] = useState(0); const reset = useGenerationStore((state) => state.reset); const stepProgress = { idle: 0, copy: 33, image: 66, saving: 90, complete: 100, error: 0, }; // Use nullish coalescing (??) instead of || to properly handle 0 as a valid progress value const currentProgress = progress.progress ?? stepProgress[progress.step]; const currentStepIndex = STEPS.findIndex(s => s.key === progress.step); const isComplete = progress.step === "complete"; const isError = progress.step === "error"; const isStuckAtHighProgress = currentProgress >= 85 && !isComplete && !isError; // Calculate elapsed time useEffect(() => { if (generationStartTime && !isComplete && !isError) { const interval = setInterval(() => { setElapsedTime(Math.floor((Date.now() - generationStartTime) / 1000)); }, 1000); return () => clearInterval(interval); } }, [generationStartTime, isComplete, isError]); // Rotate messages when stuck at high progress useEffect(() => { if (isStuckAtHighProgress) { const interval = setInterval(() => { setCurrentMessageIndex((prev) => (prev + 1) % ENGAGING_MESSAGES.length); }, 5000); // Change message every 5 seconds return () => clearInterval(interval); } }, [isStuckAtHighProgress]); // Rotate step messages periodically useEffect(() => { if (!isComplete && !isError && !isStuckAtHighProgress) { const step = STEPS.find(s => s.key === progress.step); if (step && step.messages.length > 1) { const interval = setInterval(() => { setCurrentMessageIndex((prev) => (prev + 1) % step.messages.length); }, 4000); // Change message every 4 seconds return () => clearInterval(interval); } } }, [progress.step, isComplete, isError, isStuckAtHighProgress]); // Get message for current step const getStepMessage = () => { if (progress.message) return progress.message; // If stuck at high progress, show engaging messages if (isStuckAtHighProgress) { return ENGAGING_MESSAGES[currentMessageIndex]; } const step = STEPS.find(s => s.key === progress.step); if (step && step.messages.length > 0) { return step.messages[currentMessageIndex % step.messages.length]; } return "Processing..."; }; return (
{/* Header with animated icon */}
{isComplete ? (
) : isError ? ( ) : (
)}

{isComplete ? "Generation Complete!" : isError ? "Generation Failed" : "Creating Your Ad"}

{isComplete ? "Your ad is ready!" : isError ? "Something went wrong" : getStepMessage()}

{elapsedTime > 30 && !isComplete && !isError && (

{Math.floor(elapsedTime / 60)}m {elapsedTime % 60}s elapsed

)}
{progress.estimatedTimeRemaining && !isComplete && !isError && (
~{Math.ceil(progress.estimatedTimeRemaining)}s

remaining

)} {!isComplete && !isError && ( )}
{/* Step Indicators */} {!isComplete && !isError && (
{/* Progress line */}
{STEPS.map((step, index) => { const StepIcon = step.icon; const isActive = progress.step === step.key; const isCompleted = currentStepIndex > index; const isUpcoming = currentStepIndex < index; return (
{isActive ? (
) : isCompleted ? ( ) : ( )} {isActive && (
)}

{step.label}

); })}
)} {/* Progress Bar */}
Overall Progress {Math.round(currentProgress)}%
{/* Success State */} {isComplete && (

Ad generated successfully!

Your creative is ready to use

)} {/* Error State */} {isError && (

Generation failed

{progress.message || "An error occurred. Please try again."}

)}
); };