Harsha1845 commited on
Commit
3fd02c0
·
verified ·
1 Parent(s): 06f9bb6

Update src/components/ResultView.tsx

Browse files
Files changed (1) hide show
  1. src/components/ResultView.tsx +72 -44
src/components/ResultView.tsx CHANGED
@@ -1,6 +1,6 @@
1
  import React, { useEffect, useState } from 'react';
2
  import { Product } from '../types';
3
- import { RefreshCw, Download, Share2, AlertCircle, ShoppingCart, Sparkles, ScanFace } from 'lucide-react';
4
 
5
  interface ResultViewProps {
6
  originalImage: string;
@@ -8,7 +8,9 @@ interface ResultViewProps {
8
  product: Product;
9
  loading: boolean;
10
  error: string | null;
 
11
  onRetake: () => void;
 
12
  }
13
 
14
  const ResultView: React.FC<ResultViewProps> = ({
@@ -17,99 +19,125 @@ const ResultView: React.FC<ResultViewProps> = ({
17
  product,
18
  loading,
19
  error,
20
- onRetake
 
 
21
  }) => {
22
- // Simulate progress steps for better UX during the wait
23
  const [progressStep, setProgressStep] = useState(0);
 
24
 
25
  useEffect(() => {
26
  if (loading) {
27
  setProgressStep(0);
28
  const interval = setInterval(() => {
29
  setProgressStep(prev => (prev < 3 ? prev + 1 : prev));
30
- }, 1500); // Change text every 1.5s
31
  return () => clearInterval(interval);
32
  }
33
  }, [loading]);
34
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  const loadingTexts = [
36
- "Analyzing body pose and lighting...",
37
- "Extracting product details...",
38
- "Warping fabric to fit your shape...",
39
- "Finalizing realistic shadows..."
40
  ];
41
 
42
  return (
43
  <div className="min-h-screen bg-gray-50 flex flex-col">
44
  <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">
45
 
46
- {/* Original Image (Small preview) */}
47
  <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">
48
- <h3 className="text-sm font-semibold text-gray-500 uppercase tracking-wide px-1">Original Capture</h3>
49
- <div className="aspect-[3/4] rounded-xl overflow-hidden bg-gray-100 relative group">
50
  <img src={originalImage} alt="Original" className="w-full h-full object-cover" />
51
- {/* Product Overlay Badge */}
52
  <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">
53
  <img src={product.imageUrl} className="w-full h-full object-contain mix-blend-multiply" alt="item" />
54
  </div>
55
  </div>
56
  </div>
57
 
58
- {/* Generated Result */}
59
  <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]">
60
  <h3 className="text-sm font-semibold text-brand-600 uppercase tracking-wide px-1 flex items-center gap-2">
61
  <Sparkles className="w-4 h-4 text-brand-500" />
62
- AI Generated Look
63
  </h3>
64
 
65
- <div className="aspect-[3/4] md:aspect-square rounded-xl overflow-hidden bg-gray-900 relative flex items-center justify-center">
66
  {loading && (
67
- <div className="absolute inset-0 flex flex-col items-center justify-center bg-gray-900/80 backdrop-blur-md z-10 text-white p-6 text-center">
68
  <div className="relative mb-6">
69
- <div className="w-16 h-16 border-4 border-brand-500/30 rounded-full animate-pulse"></div>
70
  <div className="absolute inset-0 w-16 h-16 border-4 border-brand-500 border-t-transparent rounded-full animate-spin"></div>
71
  <ScanFace className="absolute inset-0 w-8 h-8 m-auto text-brand-500 animate-pulse" />
72
  </div>
73
- <h4 className="text-xl font-bold mb-2">Creating Your Try-On</h4>
74
  <p className="text-brand-300 font-medium animate-pulse">{loadingTexts[progressStep]}</p>
75
- <p className="text-xs text-gray-500 mt-4">Powered by Gemini Nano Banana</p>
76
  </div>
77
  )}
78
 
79
- {error && (
80
- <div className="absolute inset-0 flex flex-col items-center justify-center p-8 text-center bg-gray-800">
81
- <div className="bg-red-500/10 p-4 rounded-full mb-4">
82
- <AlertCircle className="w-10 h-10 text-red-500" />
 
 
 
 
 
 
 
83
  </div>
84
- <h4 className="text-white font-bold text-lg mb-2">Generation Failed</h4>
85
- <p className="text-gray-400 text-sm mb-6 max-w-xs">{error}</p>
86
- <button
87
- onClick={onRetake}
88
- className="px-6 py-2.5 bg-white text-black rounded-full font-bold text-sm hover:bg-gray-100 transition-colors"
89
- >
90
- Try Again
91
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
92
  </div>
93
  )}
94
 
95
- {!loading && !error && generatedImage && (
96
- <img src={generatedImage} alt="Generated Try-On" className="w-full h-full object-contain animate-in fade-in duration-700" />
97
  )}
98
  </div>
99
 
100
- {/* Actions */}
101
- {!loading && !error && generatedImage && (
102
  <div className="grid grid-cols-2 gap-3 mt-2">
103
- <button
104
- onClick={onRetake}
105
- className="flex items-center justify-center gap-2 py-3 bg-gray-100 hover:bg-gray-200 text-gray-800 rounded-xl font-bold transition-colors"
106
- >
107
  <RefreshCw className="w-4 h-4" />
108
- Retake
109
  </button>
110
- <button className="flex items-center justify-center gap-2 py-3 bg-brand-600 hover:bg-brand-700 text-white rounded-xl font-bold transition-colors shadow-lg shadow-brand-200 hover:shadow-brand-300">
111
- <ShoppingCart className="w-4 h-4" />
112
- Add to Cart
113
  </button>
114
  </div>
115
  )}
@@ -119,4 +147,4 @@ const ResultView: React.FC<ResultViewProps> = ({
119
  );
120
  };
121
 
122
- export default ResultView;
 
1
  import React, { useEffect, useState } from 'react';
2
  import { Product } from '../types';
3
+ import { RefreshCw, AlertCircle, Sparkles, ScanFace, Timer, Play } from 'lucide-react';
4
 
5
  interface ResultViewProps {
6
  originalImage: string;
 
8
  product: Product;
9
  loading: boolean;
10
  error: string | null;
11
+ retryAfter: number | null;
12
  onRetake: () => void;
13
+ onRetry: () => void;
14
  }
15
 
16
  const ResultView: React.FC<ResultViewProps> = ({
 
19
  product,
20
  loading,
21
  error,
22
+ retryAfter,
23
+ onRetake,
24
+ onRetry
25
  }) => {
 
26
  const [progressStep, setProgressStep] = useState(0);
27
+ const [timeLeft, setTimeLeft] = useState<number | null>(null);
28
 
29
  useEffect(() => {
30
  if (loading) {
31
  setProgressStep(0);
32
  const interval = setInterval(() => {
33
  setProgressStep(prev => (prev < 3 ? prev + 1 : prev));
34
+ }, 1500);
35
  return () => clearInterval(interval);
36
  }
37
  }, [loading]);
38
 
39
+ useEffect(() => {
40
+ if (retryAfter !== null) {
41
+ setTimeLeft(retryAfter);
42
+ const timer = setInterval(() => {
43
+ setTimeLeft(prev => (prev !== null && prev > 0 ? prev - 1 : 0));
44
+ }, 1000);
45
+ return () => clearInterval(timer);
46
+ } else {
47
+ setTimeLeft(null);
48
+ }
49
+ }, [retryAfter]);
50
+
51
  const loadingTexts = [
52
+ "Analyzing pose...",
53
+ "Fitting garment...",
54
+ "Adjusting shadows...",
55
+ "Finalizing..."
56
  ];
57
 
58
  return (
59
  <div className="min-h-screen bg-gray-50 flex flex-col">
60
  <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">
61
 
62
+ {/* Sidebar Preview */}
63
  <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">
64
+ <h3 className="text-xs font-bold text-gray-400 uppercase tracking-widest px-1">Source Photo</h3>
65
+ <div className="aspect-[3/4] rounded-xl overflow-hidden bg-gray-100 relative">
66
  <img src={originalImage} alt="Original" className="w-full h-full object-cover" />
 
67
  <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">
68
  <img src={product.imageUrl} className="w-full h-full object-contain mix-blend-multiply" alt="item" />
69
  </div>
70
  </div>
71
  </div>
72
 
73
+ {/* Result Area */}
74
  <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]">
75
  <h3 className="text-sm font-semibold text-brand-600 uppercase tracking-wide px-1 flex items-center gap-2">
76
  <Sparkles className="w-4 h-4 text-brand-500" />
77
+ AI Generation
78
  </h3>
79
 
80
+ <div className="aspect-[3/4] md:aspect-square rounded-xl overflow-hidden bg-slate-900 relative flex items-center justify-center">
81
  {loading && (
82
+ <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">
83
  <div className="relative mb-6">
84
+ <div className="w-16 h-16 border-4 border-brand-500/20 rounded-full animate-pulse"></div>
85
  <div className="absolute inset-0 w-16 h-16 border-4 border-brand-500 border-t-transparent rounded-full animate-spin"></div>
86
  <ScanFace className="absolute inset-0 w-8 h-8 m-auto text-brand-500 animate-pulse" />
87
  </div>
88
+ <h4 className="text-xl font-bold mb-2">Creating Your Look</h4>
89
  <p className="text-brand-300 font-medium animate-pulse">{loadingTexts[progressStep]}</p>
 
90
  </div>
91
  )}
92
 
93
+ {timeLeft !== null && (
94
+ <div className="absolute inset-0 flex flex-col items-center justify-center p-8 text-center bg-slate-900 text-white z-20">
95
+ <div className="bg-brand-500/20 p-5 rounded-full mb-6">
96
+ <Timer className="w-12 h-12 text-brand-400 animate-pulse" />
97
+ </div>
98
+ <h4 className="text-2xl font-bold mb-3">AI is busy</h4>
99
+ <p className="text-slate-400 text-sm mb-8 max-w-xs">
100
+ The free AI tier is at capacity. We can try again automatically in:
101
+ </p>
102
+ <div className="text-5xl font-mono font-bold text-brand-400 mb-10">
103
+ {timeLeft}s
104
  </div>
105
+ <div className="flex gap-4">
106
+ <button onClick={onRetake} className="px-6 py-3 bg-white/10 hover:bg-white/20 rounded-xl font-bold transition-all">Cancel</button>
107
+ <button
108
+ onClick={onRetry}
109
+ disabled={timeLeft > 0}
110
+ 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'}`}
111
+ >
112
+ <Play className="w-4 h-4" />
113
+ Try Now
114
+ </button>
115
+ </div>
116
+ </div>
117
+ )}
118
+
119
+ {error && timeLeft === null && (
120
+ <div className="absolute inset-0 flex flex-col items-center justify-center p-8 text-center bg-slate-800">
121
+ <AlertCircle className="w-12 h-12 text-red-500 mb-4" />
122
+ <h4 className="text-white font-bold text-lg mb-2">Generation Error</h4>
123
+ <p className="text-gray-400 text-sm mb-8">{error}</p>
124
+ <button onClick={onRetake} className="px-8 py-3 bg-white text-black rounded-xl font-bold hover:bg-gray-100 transition-colors">Try Again</button>
125
  </div>
126
  )}
127
 
128
+ {!loading && !error && !timeLeft && generatedImage && (
129
+ <img src={generatedImage} alt="Result" className="w-full h-full object-contain animate-in fade-in zoom-in-95 duration-700" />
130
  )}
131
  </div>
132
 
133
+ {!loading && !error && !timeLeft && generatedImage && (
 
134
  <div className="grid grid-cols-2 gap-3 mt-2">
135
+ <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">
 
 
 
136
  <RefreshCw className="w-4 h-4" />
137
+ Retake Photo
138
  </button>
139
+ <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">
140
+ Add to Wardrobe
 
141
  </button>
142
  </div>
143
  )}
 
147
  );
148
  };
149
 
150
+ export default ResultView;