@@ -12,18 +12,16 @@ import React, { useState } from "react";
1212import { zodResolver } from "@hookform/resolvers/zod" ;
1313import { useForm } from "react-hook-form" ;
1414import { z } from "zod" ;
15-
16- // import { useToast } from "../../hooks/use-toast";
17- // import { HoverBorderGradient } from "../../components/ui/hover-border-gradient";
18- // import { Textarea } from "../../components/ui/textarea";
19- // import UserGenImages from "../../components/UserGenImages";
20- import { LoaderCircle , Plus } from "lucide-react" ;
15+ import { Download , LoaderCircle , Plus } from "lucide-react" ;
2116import { useSession } from "next-auth/react" ;
2217import { Spotlight } from "@/components/ui/spotlight" ;
2318import { useToast } from "@/hooks/use-toast" ;
2419import { Textarea } from "@/components/ui/textarea" ;
2520import { HoverBorderGradient } from "@/components/ui/hover-border-gradient" ;
2621import UserGenImages from "@/components/UserGenImages" ;
22+ import { motion , AnimatePresence } from "framer-motion" ;
23+ import Image from "next/image" ;
24+ import { useClearSessionIfLoginNotRequired } from "@/utils/clearSession" ;
2725
2826enum btnType { 'submit' , 'button' }
2927
@@ -36,9 +34,13 @@ const formSchema = z.object({
3634export default function Page ( ) {
3735 const [ refreshKey , setRefreshKey ] = useState < number > ( 0 ) ;
3836 const [ loading , setLoading ] = useState < boolean > ( false ) ;
37+ const [ outputImg , setOutputImg ] = useState < string | null > ( null ) ;
3938 const { data : session } = useSession ( ) ;
4039
4140 const { toast } = useToast ( ) ;
41+ const loginRequired = process . env . NEXT_PUBLIC_LOGIN_REQUIRED === "true" ;
42+
43+ useClearSessionIfLoginNotRequired ( ) ;
4244
4345 const form = useForm < z . infer < typeof formSchema > > ( {
4446 resolver : zodResolver ( formSchema ) ,
@@ -48,7 +50,7 @@ export default function Page() {
4850 } ) ;
4951
5052 async function onSubmit ( values : z . infer < typeof formSchema > ) {
51- if ( ! session ) {
53+ if ( loginRequired && ! session ) {
5254 toast ( { variant : "destructive" , description : "Login required to generate an image." } ) ;
5355 return ;
5456 }
@@ -60,16 +62,35 @@ export default function Page() {
6062 } ) ;
6163 const data = await response . json ( ) ;
6264 if ( response . status === 200 ) {
63- setRefreshKey ( prev => prev + 1 ) ;
65+ if ( loginRequired ) {
66+ setRefreshKey ( prev => prev + 1 ) ;
67+ } else {
68+ setOutputImg ( data . url ) ;
69+ }
6470 } else {
6571 toast ( { variant : "destructive" , description : data . error } ) ;
6672 }
6773 } catch ( error ) {
74+ toast ( { variant : "destructive" , description : "An error occurred while generating the image." } ) ;
6875 console . error ( error ) ;
6976 } finally {
7077 setLoading ( false ) ;
7178 }
72- }
79+ } const downloadImage = async ( imageUrl : string ) => {
80+ try {
81+ const response = await fetch ( imageUrl ) ;
82+ const blob = await response . blob ( ) ;
83+ const url = window . URL . createObjectURL ( blob ) ;
84+ const link = document . createElement ( 'a' ) ;
85+ link . href = url ;
86+ link . download = 'generated-image.png' ;
87+ document . body . appendChild ( link ) ;
88+ link . click ( ) ;
89+ document . body . removeChild ( link ) ;
90+ } catch ( error ) {
91+ console . error ( 'Error downloading image:' , error ) ;
92+ }
93+ } ;
7394
7495 return (
7596 < >
@@ -98,7 +119,7 @@ export default function Page() {
98119 role = "group"
99120 id = "prompt-input"
100121 disabled = { loading }
101- className = "disabled:pointer-events-none resize-none w-full transition-all border-white h-auto bg-white/5 shadow-lg shadow-neutral-600/5 backdrop-blur-lg hover:backdrop-blur-0"
122+ className = "disabled:pointer-events-none resize-none w-full transition-all text-white/90 border-white h-auto bg-white/5 shadow-lg shadow-neutral-600/5 backdrop-blur-lg hover:backdrop-blur-0"
102123 { ...field }
103124 />
104125 </ FormControl >
@@ -110,7 +131,7 @@ export default function Page() {
110131 containerClassName = "rounded-full"
111132 as = "button"
112133 buttonType = { btnType . submit }
113- btnDisabled = { loading }
134+ btnDisabled = { ! form . formState . isValid || loading }
114135 className = "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50
115136 bg-black text-white flex items-center space-x-2 w-full md:w-auto" >
116137 < span className = "flex justify-center items-center gap-2 w-auto" >
@@ -121,20 +142,61 @@ export default function Page() {
121142 </ Form >
122143 </ div >
123144
124- { session && (
125- < >
126- { loading && (
127- < div className = "flex items-center justify-center gap-2 w-full max-w-6xl md:w-[80%] py-1 h-[30px]
145+ < >
146+ { loading && (
147+ < div className = "flex items-center justify-center gap-2 w-full max-w-6xl md:w-[80%] py-1 h-[30px]
128148 bg-white/5 animate-pulse rounded-lg p-1 image-loading-bg cursor-not-allowed" >
129- Generating ... < LoaderCircle className = "animate-spin" />
130- </ div >
131- ) }
149+ Generating ... < LoaderCircle className = "animate-spin" />
150+ </ div >
151+ ) }
152+ { loginRequired && session && (
132153 < div className = "w-full max-w-6xl py-5 md:py-10" >
133154 < UserGenImages key = { refreshKey } />
134155 </ div >
135- </ >
136- ) }
137- </ section >
156+ ) }
157+ { ! loginRequired && (
158+ < div className = "w-full md:max-w-6xl py-5 md:py-10 flex items-center justify-center flex-col gap-3" >
159+ < AnimatePresence mode = "wait" >
160+ { ! loginRequired && (
161+ < >
162+ < motion . div
163+ className = { `bg-white/5 rounded-lg p-1 w-full md:w-[500px] h-full md:h-[500px] relative ${ outputImg ? '' : 'animate-pulse' } ` }
164+ initial = { { opacity : 0 , y : 20 } }
165+ animate = { { opacity : 1 , y : 0 } }
166+ transition = { { duration : 0.5 } }
167+ >
168+ { outputImg ? (
169+ < Image
170+ src = { outputImg || '' }
171+ alt = { 'image' }
172+ width = { 0 }
173+ height = { 0 }
174+ sizes = "100vw"
175+ style = { { width : '100%' , height : 'auto' } }
176+ className = "!w-full !h-auto object-cover rounded-t-lg md:rounded-lg shadow-lg cursor-pointer"
177+ />
178+ ) : (
179+ < div className = "w-full h-full flex flex-col justify-center items-center gap-3 text-white/70 text-center p-3" >
180+ Enter your prompt and hit generate! < Plus />
181+ </ div >
182+ ) }
183+ </ motion . div >
184+ { outputImg && (
185+ < button
186+ onClick = { ( ) => downloadImage ( outputImg || '' ) }
187+ className = "p-2 bg-white/5 rounded-full hover:bg-white/60 transition-colors text-white/90 flex items-center justify-center gap-1 text-base py-2 px-5"
188+ title = "Download image"
189+ >
190+ Download < Download className = "w-5 h-5" />
191+ </ button >
192+ ) }
193+ </ >
194+ ) }
195+ </ AnimatePresence >
196+ </ div >
197+ ) }
198+ </ >
199+ </ section >
138200 </ >
139201 ) ;
140202}
0 commit comments