Skip to content

Commit e45ac82

Browse files
committed
Added switch between login req to gen img or not
1 parent f4914e0 commit e45ac82

File tree

8 files changed

+275
-85
lines changed

8 files changed

+275
-85
lines changed

next.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const nextConfig = {
33
images: {
44
remotePatterns: [
55
{
6-
hostname: "image.pollinations.ai",
6+
hostname: "**",
77
pathname: "/**",
88
port: "",
99
protocol: "https",

src/app/api/image/route.ts

Lines changed: 73 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,36 @@ import { NEXT_AUTH_CONFIG } from "@/utils/auth";
33
import { getServerSession } from "next-auth";
44
import { NextRequest, NextResponse } from "next/server";
55

6+
const loginRequired = process.env.LOGIN_REQUIRED === "true";
67
export const maxDuration = 60;
78

89
export async function POST(req: NextRequest) {
9-
const session = await getServerSession(NEXT_AUTH_CONFIG);
10-
if (!session) {
11-
return NextResponse.json({
12-
error: 'You are not logged in',
13-
}, { status: 401 })
10+
let session = null;
11+
let user = null;
12+
13+
if (loginRequired) {
14+
session = await getServerSession(NEXT_AUTH_CONFIG);
15+
if (!session) {
16+
return NextResponse.json({
17+
error: 'You are not logged in',
18+
}, { status: 401 })
19+
}
20+
21+
user = await prisma.user.findUnique({
22+
where: { id: session.user.id },
23+
});
24+
25+
if (!user) {
26+
return NextResponse.json({ error: "No user found" }, { status: 401 });
27+
}
1428
}
1529

1630
const { prompt }: { prompt: string } = await req.json();
17-
18-
const user = await prisma.user.findUnique({
19-
where: {
20-
id: session.user.id,
21-
},
22-
});
23-
24-
if (!user) {
25-
return NextResponse.json({ error: "No user found" }, { status: 401 });
31+
if (!prompt || prompt.length < 5) {
32+
return NextResponse.json(
33+
{ error: "Invalid prompt. It must be at least 5 characters long." },
34+
{ status: 400 }
35+
);
2636
}
2737

2838
function generateRandomNumber(): number {
@@ -35,45 +45,60 @@ export async function POST(req: NextRequest) {
3545
prompt
3646
)}?seed=${randomSeed}&width=512&height=512&nologo=True`;
3747

38-
await fetch(imageUrl);
39-
40-
await prisma.post.create({
41-
data: {
42-
prompt: prompt,
43-
url: imageUrl,
44-
seed: randomSeed,
45-
userId: user.id,
46-
},
47-
});
48-
49-
return NextResponse.json({ url: imageUrl })
50-
}
51-
52-
export async function GET() {
53-
const session = await getServerSession(NEXT_AUTH_CONFIG);
54-
if (!session) {
48+
try {
49+
const fetchResponse = await fetch(imageUrl);
50+
if (!fetchResponse.ok) {
51+
throw new Error("Failed to generate image.");
52+
}
53+
} catch (error) {
54+
console.error(error);
5555
return NextResponse.json(
56-
{ error: "You are Unauthorized" },
57-
{ status: 401 }
56+
{ error: "Failed to fetch image. Please try again later." },
57+
{ status: 500 }
5858
);
5959
}
6060

61-
const user = await prisma.user.findUnique({
62-
where: {
63-
id: session.user.id,
64-
},
65-
});
66-
67-
if (!user) {
68-
return NextResponse.json({ error: "No user found" }, { status: 401 });
61+
if (loginRequired && user) {
62+
await prisma.post.create({
63+
data: {
64+
prompt: prompt,
65+
url: imageUrl,
66+
seed: randomSeed,
67+
userId: user.id,
68+
},
69+
});
6970
}
7071

71-
const posts = await prisma.post.findMany({
72-
where: {
73-
userId: user.id,
74-
},
75-
orderBy: { createdAt: "desc" },
76-
});
72+
return NextResponse.json({ url: imageUrl })
73+
}
7774

78-
return NextResponse.json(posts);
75+
export async function GET() {
76+
if (loginRequired) {
77+
const session = await getServerSession(NEXT_AUTH_CONFIG);
78+
if (!session) {
79+
return NextResponse.json(
80+
{ error: "You are Unauthorized" },
81+
{ status: 401 }
82+
);
83+
}
84+
85+
const user = await prisma.user.findUnique({
86+
where: {
87+
id: session.user.id,
88+
},
89+
});
90+
91+
if (!user) {
92+
return NextResponse.json({ error: "No user found" }, { status: 401 });
93+
}
94+
95+
const posts = await prisma.post.findMany({
96+
where: {
97+
userId: user.id,
98+
},
99+
orderBy: { createdAt: "desc" },
100+
});
101+
102+
return NextResponse.json(posts);
103+
}
79104
}

src/app/api/user/route.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { NEXT_AUTH_CONFIG } from "@/utils/auth";
2+
import { getServerSession } from "next-auth"
3+
import { NextResponse } from "next/server";
4+
5+
export async function GET() {
6+
const session = await getServerSession(NEXT_AUTH_CONFIG);
7+
return NextResponse.json({
8+
name: session?.user?.name,
9+
email: session?.user?.email
10+
})
11+
}

src/app/generate-image/page.tsx

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,16 @@ import React, { useState } from "react";
1212
import { zodResolver } from "@hookform/resolvers/zod";
1313
import { useForm } from "react-hook-form";
1414
import { 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";
2116
import { useSession } from "next-auth/react";
2217
import { Spotlight } from "@/components/ui/spotlight";
2318
import { useToast } from "@/hooks/use-toast";
2419
import { Textarea } from "@/components/ui/textarea";
2520
import { HoverBorderGradient } from "@/components/ui/hover-border-gradient";
2621
import UserGenImages from "@/components/UserGenImages";
22+
import { motion, AnimatePresence } from "framer-motion";
23+
import Image from "next/image";
24+
import { useClearSessionIfLoginNotRequired } from "@/utils/clearSession";
2725

2826
enum btnType { 'submit', 'button' }
2927

@@ -36,9 +34,13 @@ const formSchema = z.object({
3634
export 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

Comments
 (0)