11"use client" ;
22
3- import {
4- Download ,
5- Home ,
6- ImageIcon ,
7- Settings ,
8- User ,
9- WandSparklesIcon ,
10- } from "lucide-react" ;
11- import { useState } from "react" ;
12- import CustomPromptCard from "./components/CustomPromptCard" ;
13- import GeneratedCard from "./components/GeneratedCard" ;
3+ import { Download , Home , Settings , User , WandSparklesIcon } from "lucide-react" ;
4+ import { useSearchParams } from "next/navigation" ;
5+ import { GeneratedCard } from "./components/GeneratedCard" ;
146import { Button } from "./components/ui/button" ;
15- import { Card } from "./components/ui/card" ;
16- import UploadCard from "./components/UploadCard" ;
17- import type { ProductAnalysis } from "./types/trigger" ;
18-
19- interface ProductImageGeneratorProps {
20- triggerToken : string ;
21- }
22-
23- export default function ProductImageGenerator ( {
24- triggerToken,
25- } : ProductImageGeneratorProps ) {
26- const [ uploadedImageUrl , setUploadedImageUrl ] = useState < string | null > ( null ) ;
27- const [ productAnalysis , setProductAnalysis ] =
28- useState < ProductAnalysis | null > ( null ) ;
29-
30- // Track all generated images
31- const [ generatedImages , setGeneratedImages ] = useState < {
32- [ key : string ] : { runId : string ; prompt : string ; imageUrl ?: string } ;
33- } > ( { } ) ;
34-
35- // Track custom generations for bottom row
36- const [ customGenerations , setCustomGenerations ] = useState < {
37- runIds : ( string | null ) [ ] ;
38- prompts : ( string | null ) [ ] ;
39- } > ( {
40- runIds : [ null , null , null , null ] ,
41- prompts : [ null , null , null , null ] ,
42- } ) ;
43-
44- const handleUploadComplete = (
45- imageUrl : string ,
46- productAnalysis ?: ProductAnalysis
47- ) => {
48- setUploadedImageUrl ( imageUrl ) ;
49- if ( productAnalysis ) {
50- setProductAnalysis ( productAnalysis ) ;
51- }
52- } ;
53-
54- const handleGenerationComplete = (
55- runId : string ,
56- prompt : string ,
57- imageUrl ?: string ,
58- key ?: string
59- ) => {
60- console . log ( "Generation completed:" , { runId, prompt, imageUrl, key } ) ;
61- setGeneratedImages ( ( prev ) => {
62- const updated = {
63- ...prev ,
64- [ key || runId ] : { runId, prompt, imageUrl } ,
65- } ;
66- console . log ( "Updated generated images:" , updated ) ;
67- return updated ;
68- } ) ;
69- } ;
70-
71- const handleCustomGenerationComplete = (
72- runId : string ,
73- prompt : string ,
74- index : number ,
75- imageUrl ?: string
76- ) => {
77- setCustomGenerations ( ( prev ) => ( {
78- runIds : prev . runIds . map ( ( id , i ) => ( i === index ? runId : id ) ) ,
79- prompts : prev . prompts . map ( ( p , i ) => ( i === index ? prompt : p ) ) ,
80- } ) ) ;
81- handleGenerationComplete ( runId , prompt , imageUrl , `custom-${ index } ` ) ;
82- } ;
83-
84- const handlePresetGenerationComplete = (
85- runId : string ,
86- promptId : string ,
87- promptTitle : string ,
88- imageUrl ?: string
89- ) => {
90- handleGenerationComplete ( runId , promptTitle , imageUrl , promptId ) ;
91- } ;
92-
93- const handleDownloadAll = async ( ) => {
94- console . log ( "Download button clicked!" ) ;
95- console . log ( "Generated images:" , generatedImages ) ;
96- console . log ( "Total generated images:" , totalGeneratedImages ) ;
97-
98- if ( totalGeneratedImages === 0 ) {
99- console . log ( "No images to download" ) ;
100- return ;
101- }
102-
103- try {
104- // For a single image, download directly
105- if ( totalGeneratedImages === 1 ) {
106- const imageData = Object . values ( generatedImages ) [ 0 ] ;
107- console . log ( "Single image data:" , imageData ) ;
108-
109- if ( imageData . imageUrl ) {
110- console . log ( "Downloading single image:" , imageData . imageUrl ) ;
111-
112- // Try to fetch the image first to handle CORS
113- try {
114- const response = await fetch ( imageData . imageUrl ) ;
115- const blob = await response . blob ( ) ;
116- const url = window . URL . createObjectURL ( blob ) ;
117-
118- const link = document . createElement ( "a" ) ;
119- link . href = url ;
120- link . download = `${ imageData . prompt
121- . replace ( / \s + / g, "-" )
122- . toLowerCase ( ) } -${ Date . now ( ) } .png`;
123- document . body . appendChild ( link ) ;
124- link . click ( ) ;
125- document . body . removeChild ( link ) ;
126-
127- // Clean up the blob URL
128- window . URL . revokeObjectURL ( url ) ;
129- } catch ( fetchError ) {
130- console . log ( "Fetch failed, trying direct download:" , fetchError ) ;
131- // Fallback to direct download
132- const link = document . createElement ( "a" ) ;
133- link . href = imageData . imageUrl ;
134- link . download = `${ imageData . prompt
135- . replace ( / \s + / g, "-" )
136- . toLowerCase ( ) } -${ Date . now ( ) } .png`;
137- document . body . appendChild ( link ) ;
138- link . click ( ) ;
139- document . body . removeChild ( link ) ;
140- }
141- } else {
142- console . log ( "No image URL found for single image" ) ;
143- }
144- return ;
145- }
146-
147- // For multiple images, download each individually
148- console . log ( "Downloading multiple images..." ) ;
149- Object . entries ( generatedImages ) . forEach ( ( [ key , imageData ] , index ) => {
150- console . log ( `Image ${ index + 1 } :` , key , imageData ) ;
151-
152- if ( imageData . imageUrl ) {
153- setTimeout ( async ( ) => {
154- try {
155- console . log (
156- `Downloading image ${ index + 1 } :` ,
157- imageData . imageUrl
158- ) ;
159-
160- // Try to fetch the image first to handle CORS
161- const response = await fetch ( imageData . imageUrl ! ) ;
162- const blob = await response . blob ( ) ;
163- const url = window . URL . createObjectURL ( blob ) ;
164-
165- const link = document . createElement ( "a" ) ;
166- link . href = url ;
167- link . download = `${ imageData . prompt
168- . replace ( / \s + / g, "-" )
169- . toLowerCase ( ) } -${ Date . now ( ) } -${ index + 1 } .png`;
170- document . body . appendChild ( link ) ;
171- link . click ( ) ;
172- document . body . removeChild ( link ) ;
173-
174- // Clean up the blob URL
175- window . URL . revokeObjectURL ( url ) ;
176- } catch ( fetchError ) {
177- console . log (
178- `Fetch failed for image ${ index + 1 } , trying direct download:` ,
179- fetchError
180- ) ;
181- // Fallback to direct download
182- const link = document . createElement ( "a" ) ;
183- link . href = imageData . imageUrl ! ;
184- link . download = `${ imageData . prompt
185- . replace ( / \s + / g, "-" )
186- . toLowerCase ( ) } -${ Date . now ( ) } -${ index + 1 } .png`;
187- document . body . appendChild ( link ) ;
188- link . click ( ) ;
189- document . body . removeChild ( link ) ;
190- }
191- } , index * 1000 ) ; // Stagger downloads by 1 second
192- } else {
193- console . log ( `No image URL found for image ${ index + 1 } ` ) ;
194- }
195- } ) ;
196- } catch ( error ) {
197- console . error ( "Failed to download images:" , error ) ;
198- }
199- } ;
200-
201- const promptTitles = {
202- "isolated-table" : "Clean Product Shot" ,
203- "lifestyle-scene" : "Lifestyle Scene" ,
204- "hero-shot" : "Hero Shot" ,
205- } ;
206-
207- // Calculate total generated images
208- const totalGeneratedImages = Object . keys ( generatedImages ) . length ;
209- const hasGeneratedImages = totalGeneratedImages > 0 ;
210-
211- // Determine which custom cards have completed generations
212- const completedCustomCards = customGenerations . runIds . filter (
213- ( runId ) => runId !== null
214- ) . length ;
7+ import { UploadCard } from "./components/UploadCard" ;
8+ import CustomPromptCard from "./components/CustomPromptCard" ;
9+ import Link from "next/link" ;
21510
216- // Find the next available custom card slot
217- const nextCustomCardIndex = customGenerations . runIds . findIndex (
218- ( runId ) => runId === null
219- ) ;
11+ const promptTitles = {
12+ "isolated-table" : "Clean Product Shot" ,
13+ "lifestyle-scene" : "Lifestyle Scene" ,
14+ "hero-shot" : "Hero Shot" ,
15+ } ;
22016
221- // Check if top row is complete (upload + 3 generated images)
222- const topRowGenerationsComplete =
223- uploadedImageUrl && productAnalysis ? true : false ;
17+ export function ProductImageGenerator ( ) {
18+ const searchParams = useSearchParams ( ) ;
19+ const publicAccessToken = searchParams . get ( "publicAccessToken" ) ;
20+ const generateToken = searchParams . get ( "triggerToken" ) ;
21+ const fileUrl = searchParams . get ( "fileUrl" ) ;
22+ const runId = searchParams . get ( "runId" ) ;
22423
22524 return (
22625 < div className = "min-h-screen bg-gray-100/20 " >
@@ -229,7 +28,9 @@ export default function ProductImageGenerator({
22928 < div className = "flex h-14 items-center justify-between" >
23029 < div className = "flex items-center space-x-4" >
23130 < div className = "flex items-center space-x-2" >
232- < WandSparklesIcon className = "h-5 w-5 text-purple-500" />
31+ < Link href = "/" className = "flex items-center space-x-2" >
32+ < WandSparklesIcon className = "h-5 w-5 text-purple-500" />
33+ </ Link >
23334 < h1 className = "text-xl font-bold text-foreground" > ImageFlow</ h1 >
23435 </ div >
23536 </ div >
@@ -265,69 +66,47 @@ export default function ProductImageGenerator({
26566 </ p >
26667 </ div >
26768 < div >
268- < Button
269- variant = { hasGeneratedImages ? "default" : "outline" }
270- disabled = { ! hasGeneratedImages }
271- onClick = { handleDownloadAll }
272- className = {
273- ! hasGeneratedImages
274- ? "opacity-50 cursor-not-allowed"
275- : "cursor-pointer"
276- }
277- >
69+ < Button variant = { "default" } className = { "cursor-pointer" } >
27870 < Download className = "h-4 w-4 mr-1" />
279- { hasGeneratedImages
280- ? `Download ${ totalGeneratedImages } image${
281- totalGeneratedImages === 1 ? "" : "s"
282- } `
283- : "Download images" }
71+ Download images
28472 </ Button >
28573 </ div >
28674 </ div >
28775
28876 < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8" >
28977 < UploadCard
290- triggerToken = { triggerToken }
291- onUploadComplete = { handleUploadComplete }
78+ runId = { runId ?? undefined }
79+ accessToken = { publicAccessToken ?? undefined }
80+ fileUrl = { fileUrl ?? undefined }
29281 />
29382 < GeneratedCard
294- baseImageUrl = { uploadedImageUrl }
295- productAnalysis = { productAnalysis }
296- promptId = "isolated-table"
83+ id = "isolated-table"
84+ runId = { runId ?? undefined }
85+ accessToken = { publicAccessToken ?? undefined }
29786 promptTitle = { promptTitles [ "isolated-table" ] }
298- onGenerationComplete = { handlePresetGenerationComplete }
29987 />
30088 < GeneratedCard
301- baseImageUrl = { uploadedImageUrl }
302- productAnalysis = { productAnalysis }
303- promptId = "lifestyle-scene"
89+ id = "lifestyle-scene"
90+ runId = { runId ?? undefined }
91+ accessToken = { publicAccessToken ?? undefined }
30492 promptTitle = { promptTitles [ "lifestyle-scene" ] }
305- onGenerationComplete = { handlePresetGenerationComplete }
30693 />
30794 < GeneratedCard
308- baseImageUrl = { uploadedImageUrl }
309- productAnalysis = { productAnalysis }
310- promptId = "hero-shot"
95+ id = "hero-shot"
96+ runId = { runId ?? undefined }
97+ accessToken = { publicAccessToken ?? undefined }
31198 promptTitle = { promptTitles [ "hero-shot" ] }
312- onGenerationComplete = { handlePresetGenerationComplete }
31399 />
314100 </ div >
315101
316102 < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6" >
317103 { Array . from ( { length : 4 } ) . map ( ( _ , index ) => {
318104 return (
319105 < CustomPromptCard
106+ id = { `custom-prompt-${ index } ` }
320107 key = { `custom-prompt-${ index } ` }
321- baseImageUrl = { uploadedImageUrl }
322- productAnalysis = { productAnalysis }
323- onGenerationComplete = { ( runId , prompt , imageUrl ) =>
324- handleCustomGenerationComplete (
325- runId ,
326- prompt ,
327- index ,
328- imageUrl
329- )
330- }
108+ fileUrl = { fileUrl ?? undefined }
109+ generateToken = { generateToken ?? undefined }
331110 />
332111 ) ;
333112 } ) }
0 commit comments