Harsha1845's picture
Update src/components/ResultView.tsx
809dc87 verified
import React, { useEffect, useState } from 'react';
import { Product } from '../types';
import { RefreshCw, AlertCircle, Sparkles, ScanFace, Timer, Play, ChevronDown, ChevronUp, Bug } from 'lucide-react';
interface ResultViewProps {
originalImage: string;
generatedImage: string | null;
product: Product;
loading: boolean;
error: string | null;
retryAfter: number | null;
onRetake: () => void;
onRetry: () => void;
}
const ResultView: React.FC<ResultViewProps> = ({
originalImage,
generatedImage,
product,
loading,
error,
retryAfter,
onRetake,
onRetry
}) => {
const [progressStep, setProgressStep] = useState(0);
const [timeLeft, setTimeLeft] = useState<number | null>(null);
const [showDetails, setShowDetails] = useState(false);
useEffect(() => {
if (loading) {
setProgressStep(0);
const interval = setInterval(() => {
setProgressStep(prev => (prev < 3 ? prev + 1 : prev));
}, 2000);
return () => clearInterval(interval);
}
}, [loading]);
useEffect(() => {
if (retryAfter !== null) {
setTimeLeft(retryAfter);
const timer = setInterval(() => {
setTimeLeft(prev => (prev !== null && prev > 0 ? prev - 1 : 0));
}, 1000);
return () => clearInterval(timer);
} else {
setTimeLeft(null);
}
}, [retryAfter]);
const loadingTexts = [
"Encoding micro-pixels...",
"Analyzing garment...",
"Synthesizing fit...",
"Almost there..."
];
return (
<div className="min-h-screen bg-gray-50 flex flex-col">
<div className="flex-1 max-w-4xl mx-auto w-full p-4 flex flex-col md:flex-row gap-6 items-start justify-center pt-8">
{/* Sidebar Preview */}
<div className="w-full md:w-1/3 bg-white p-3 rounded-2xl shadow-sm border border-gray-100 flex flex-col gap-2">
<h3 className="text-xs font-bold text-gray-400 uppercase tracking-widest px-1">Source</h3>
<div className="aspect-[3/4] rounded-xl overflow-hidden bg-gray-100 relative">
<img src={originalImage} alt="Original" className="w-full h-full object-cover" />
<div className="absolute bottom-2 right-2 bg-white/90 backdrop-blur rounded-lg p-1 shadow-sm w-12 h-12 border border-gray-200">
<img src={product.imageUrl} className="w-full h-full object-contain mix-blend-multiply" alt="item" />
</div>
</div>
</div>
{/* Result Area */}
<div className="w-full md:w-2/3 bg-white p-3 rounded-2xl shadow-lg border border-gray-100 flex flex-col gap-2 relative min-h-[400px]">
<h3 className="text-sm font-semibold text-brand-600 uppercase tracking-wide px-1 flex items-center gap-2">
<Sparkles className="w-4 h-4 text-brand-500" />
AI Studio
</h3>
<div className="aspect-[3/4] md:aspect-square rounded-xl overflow-hidden bg-slate-900 relative flex items-center justify-center">
{loading && (
<div className="absolute inset-0 flex flex-col items-center justify-center bg-slate-900/90 backdrop-blur-md z-10 text-white p-6 text-center">
<div className="relative mb-6">
<div className="w-16 h-16 border-4 border-brand-500/20 rounded-full animate-pulse"></div>
<div className="absolute inset-0 w-16 h-16 border-4 border-brand-500 border-t-transparent rounded-full animate-spin"></div>
<ScanFace className="absolute inset-0 w-8 h-8 m-auto text-brand-500 animate-pulse" />
</div>
<h4 className="text-xl font-bold mb-2">Generating...</h4>
<p className="text-brand-300 font-medium animate-pulse">{loadingTexts[progressStep]}</p>
</div>
)}
{timeLeft !== null && (
<div className="absolute inset-0 flex flex-col items-center justify-center p-8 text-center bg-slate-900 text-white z-20">
<div className="bg-amber-500/20 p-5 rounded-full mb-6">
<Timer className="w-12 h-12 text-amber-400 animate-pulse" />
</div>
<h4 className="text-2xl font-bold mb-3 text-amber-400">AI Cooling Down</h4>
<p className="text-slate-400 text-sm mb-8 max-w-xs">
To prevent errors, please wait 2 minutes between attempts on the free tier.
</p>
<div className="text-6xl font-mono font-bold text-white mb-10">
{timeLeft}s
</div>
<div className="flex gap-4">
<button onClick={onRetake} className="px-6 py-3 bg-white/10 hover:bg-white/20 rounded-xl font-bold transition-all">Back</button>
<button
onClick={onRetry}
disabled={timeLeft > 0}
className={`px-8 py-3 rounded-xl font-bold flex items-center gap-2 transition-all ${timeLeft === 0 ? 'bg-brand-500 text-white' : 'bg-slate-700 text-slate-500 cursor-not-allowed'}`}
>
<Play className="w-4 h-4" />
Try Now
</button>
</div>
</div>
)}
{error && timeLeft === null && (
<div className="absolute inset-0 flex flex-col items-center justify-center p-8 text-center bg-slate-800">
<AlertCircle className="w-10 h-10 text-red-500 mb-4" />
<h4 className="text-white font-bold text-lg mb-2">Service Delay</h4>
<p className="text-gray-400 text-sm mb-6 px-4">The AI encountered a limit. Wait a moment then retry.</p>
<button
onClick={() => setShowDetails(!showDetails)}
className="flex items-center gap-2 text-[10px] text-gray-500 uppercase tracking-widest mb-4 hover:text-gray-300 transition-colors"
>
<Bug className="w-3 h-3" />
Diagnostics
{showDetails ? <ChevronUp className="w-3 h-3" /> : <ChevronDown className="w-3 h-3" />}
</button>
{showDetails && (
<div className="bg-black/50 p-3 rounded-lg border border-white/10 text-left mb-6 max-h-32 overflow-y-auto w-full">
<code className="text-[10px] text-red-400 break-all">{error}</code>
</div>
)}
<button onClick={onRetake} className="px-8 py-3 bg-white text-black rounded-xl font-bold hover:bg-gray-100 transition-colors">Go Back</button>
</div>
)}
{!loading && !error && !timeLeft && generatedImage && (
<img src={generatedImage} alt="Result" className="w-full h-full object-contain animate-in fade-in zoom-in-95 duration-700" />
)}
</div>
{!loading && !error && !timeLeft && generatedImage && (
<div className="grid grid-cols-2 gap-3 mt-2">
<button onClick={onRetake} className="flex items-center justify-center gap-2 py-4 bg-slate-100 hover:bg-slate-200 text-slate-700 rounded-xl font-bold transition-all">
<RefreshCw className="w-4 h-4" />
Retake
</button>
<button className="flex items-center justify-center gap-2 py-4 bg-brand-600 hover:bg-brand-700 text-white rounded-xl font-bold transition-all shadow-lg shadow-brand-200">
Save
</button>
</div>
)}
</div>
</div>
</div>
);
};
export default ResultView;