Skip to content

Commit f6d5ec0

Browse files
authored
Updates and bug fixes
- Fixes : 1. updated implementation of stack using linked list 2. auth page continue with google layering updated 3. added display name to basic email based input auth
2 parents f0a9db8 + 877cf78 commit f6d5ec0

File tree

9 files changed

+340
-249
lines changed

9 files changed

+340
-249
lines changed

app/api/auth/route.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export async function POST(req) {
99
try {
1010
// Parse JSON body safely
1111
const body = await req.json()
12-
const { email, password, captchaToken, action } = body || {}
12+
const { email, password, captchaToken, action, name } = body || {}
1313

1414
// Validate required fields
1515
if (!email || !password) {
@@ -34,8 +34,11 @@ export async function POST(req) {
3434
}
3535

3636
if (action === 'signup') {
37-
// Create Supabase user
38-
const { user, error } = await supabase.auth.admin.createUser({ email, password })
37+
// Create Supabase user with metadata
38+
const { user, error } = await supabase.auth.signUp(
39+
{ email, password },
40+
{ data: { display_name: name } }
41+
)
3942
if (error) {
4043
return new Response(JSON.stringify({ success: false, message: error.message }), { status: 400 })
4144
}

app/login/page.jsx

Lines changed: 151 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,111 @@
1-
'use client'
2-
import { useState, useEffect } from 'react'
3-
import { supabase } from '../../lib/supabase'
4-
import { useRouter } from 'next/navigation'
5-
import { FiMail, FiLock, FiUser, FiLogIn, FiUserPlus, FiSun, FiMoon } from 'react-icons/fi'
6-
import { motion } from 'framer-motion'
7-
import Link from 'next/link'
8-
import dynamic from 'next/dynamic'
1+
"use client";
2+
import { useState, useEffect } from "react";
3+
import { supabase } from "../../lib/supabase";
4+
import { useRouter } from "next/navigation";
5+
import {
6+
FiMail,
7+
FiLock,
8+
FiUser,
9+
FiLogIn,
10+
FiUserPlus,
11+
FiSun,
12+
FiMoon,
13+
} from "react-icons/fi";
14+
import { motion } from "framer-motion";
15+
import Link from "next/link";
16+
import dynamic from "next/dynamic";
917

1018
const Turnstile = dynamic(
11-
() => import('@marsidev/react-turnstile').then((mod) => mod.Turnstile),
19+
() => import("@marsidev/react-turnstile").then((mod) => mod.Turnstile),
1220
{ ssr: false }
13-
)
21+
);
1422

1523
export default function LoginPage() {
16-
const [email, setEmail] = useState('')
17-
const [password, setPassword] = useState('')
18-
const [isLogin, setIsLogin] = useState(true)
19-
const [loading, setLoading] = useState(false)
20-
const [error, setError] = useState('')
21-
const [theme, setTheme] = useState('light')
22-
const [captchaToken, setCaptchaToken] = useState(null)
23-
const router = useRouter()
24+
const [email, setEmail] = useState("");
25+
const [password, setPassword] = useState("");
26+
const [name, setName] = useState("");
27+
const [isLogin, setIsLogin] = useState(true);
28+
const [loading, setLoading] = useState(false);
29+
const [error, setError] = useState("");
30+
const [theme, setTheme] = useState("light");
31+
const [captchaToken, setCaptchaToken] = useState(null);
32+
const router = useRouter();
2433

2534
useEffect(() => {
26-
const savedTheme = localStorage.getItem('theme') || 'light'
27-
setTheme(savedTheme)
28-
document.documentElement.classList.toggle('dark', savedTheme === 'dark')
29-
}, [])
35+
const savedTheme = localStorage.getItem("theme") || "light";
36+
setTheme(savedTheme);
37+
document.documentElement.classList.toggle("dark", savedTheme === "dark");
38+
}, []);
3039

3140
const toggleTheme = () => {
32-
const newTheme = theme === 'light' ? 'dark' : 'light'
33-
setTheme(newTheme)
34-
localStorage.setItem('theme', newTheme)
35-
document.documentElement.classList.toggle('dark', newTheme === 'dark')
36-
}
41+
const newTheme = theme === "light" ? "dark" : "light";
42+
setTheme(newTheme);
43+
localStorage.setItem("theme", newTheme);
44+
document.documentElement.classList.toggle("dark", newTheme === "dark");
45+
};
3746

3847
const handleAuth = async () => {
39-
setLoading(true)
40-
setError('')
48+
setLoading(true);
49+
setError("");
4150

4251
try {
43-
if (!captchaToken) throw new Error('Please complete captcha')
52+
if (!captchaToken) throw new Error("Please complete captcha");
4453

4554
if (isLogin) {
4655
// Verify captcha first via API route
47-
const verifyRes = await fetch('/api/auth', {
48-
method: 'POST',
49-
headers: { 'Content-Type': 'application/json' },
50-
body: JSON.stringify({ email, password, captchaToken, action: 'login' }),
51-
})
52-
const verifyData = await verifyRes.json()
53-
if (!verifyData.success) throw new Error(verifyData.message || 'Captcha verification failed')
56+
const verifyRes = await fetch("/api/auth", {
57+
method: "POST",
58+
headers: { "Content-Type": "application/json" },
59+
body: JSON.stringify({
60+
email,
61+
password,
62+
captchaToken,
63+
action: "login",
64+
}),
65+
});
66+
const verifyData = await verifyRes.json();
67+
if (!verifyData.success)
68+
throw new Error(verifyData.message || "Captcha verification failed");
5469

5570
// After captcha verified, login using frontend anon key
56-
const { error } = await supabase.auth.signInWithPassword({ email, password })
57-
if (error) throw error
71+
const { error } = await supabase.auth.signInWithPassword({
72+
email,
73+
password,
74+
});
75+
if (error) throw error;
5876

59-
router.push('/dashboard')
77+
router.push("/dashboard");
6078
} else {
6179
// Signup flow remains the same
62-
const res = await fetch('/api/auth', {
63-
method: 'POST',
64-
headers: { 'Content-Type': 'application/json' },
65-
body: JSON.stringify({ email, password, captchaToken, action: 'signup' }),
66-
})
67-
const data = await res.json()
68-
if (!data.success) throw new Error(data.message || 'Signup failed')
69-
alert(data.message)
70-
setIsLogin(true)
80+
const res = await fetch("/api/auth", {
81+
method: "POST",
82+
headers: { "Content-Type": "application/json" },
83+
body: JSON.stringify({
84+
email,
85+
password,
86+
captchaToken,
87+
action: "signup",
88+
name,
89+
}),
90+
});
91+
const data = await res.json();
92+
if (!data.success) throw new Error(data.message || "Signup failed");
93+
alert(data.message);
94+
setIsLogin(true);
7195
}
7296
} catch (err) {
73-
setError(err.message || 'Something went wrong')
97+
setError(err.message || "Something went wrong");
7498
} finally {
75-
setLoading(false)
99+
setLoading(false);
76100
}
77-
}
101+
};
78102

79103
const handleGoogleSignIn = async () => {
80-
const { error } = await supabase.auth.signInWithOAuth({ provider: 'google' })
81-
if (error) console.error('Google sign-in error:', error.message)
82-
}
104+
const { error } = await supabase.auth.signInWithOAuth({
105+
provider: "google",
106+
});
107+
if (error) console.error("Google sign-in error:", error.message);
108+
};
83109

84110
return (
85111
<div className="min-h-screen flex items-center justify-center p-4 bg-white dark:bg-neutral-900">
@@ -91,19 +117,54 @@ export default function LoginPage() {
91117
{/* Header */}
92118
<div className="bg-blue-500 p-6 text-white flex justify-between items-center">
93119
<div>
94-
<h1 className="text-2xl font-bold">{isLogin ? 'Welcome Back' : 'Create Account'}</h1>
120+
<h1 className="text-2xl font-bold">
121+
{isLogin ? "Welcome Back" : "Create Account"}
122+
</h1>
95123
<p className="text-blue-100 dark:text-blue-200">
96-
{isLogin ? 'Sign in to access your dashboard' : 'Join us to get started'}
124+
{isLogin
125+
? "Sign in to access your dashboard"
126+
: "Join us to get started"}
97127
</p>
98128
</div>
99-
<button onClick={toggleTheme} className="p-2 rounded-full hover:bg-blue-700" aria-label="Toggle theme">
100-
{theme === 'light' ? <FiMoon className="w-5 h-5" /> : <FiSun className="w-5 h-5" />}
129+
<button
130+
onClick={toggleTheme}
131+
className="p-2 rounded-full hover:bg-blue-700"
132+
aria-label="Toggle theme"
133+
>
134+
{theme === "light" ? (
135+
<FiMoon className="w-5 h-5" />
136+
) : (
137+
<FiSun className="w-5 h-5" />
138+
)}
101139
</button>
102140
</div>
103141

142+
<div className="flex justify-center items-center p-6">
143+
{/* Google OAuth */}
144+
<button
145+
onClick={handleGoogleSignIn}
146+
className="w-full flex items-center justify-center py-3 px-4 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-neutral-950 text-gray-700 dark:text-gray-200 font-medium hover:bg-gray-50 dark:hover:bg-neutral-900 duration-300 transition-all"
147+
>
148+
<img src="./google.webp" width={24}></img>
149+
<span className="mx-2">Continue with Google</span>
150+
</button>
151+
</div>
152+
153+
<div className="relative flex items-center px-6">
154+
<div className="flex-grow border-t border-gray-300 dark:border-gray-600"></div>
155+
<span className="flex-shrink mx-4 text-gray-500 dark:text-gray-400">
156+
or
157+
</span>
158+
<div className="flex-grow border-t border-gray-300 dark:border-gray-600"></div>
159+
</div>
160+
104161
<div className="p-6 space-y-4">
105162
{error && (
106-
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="bg-red-100 dark:bg-red-900/30 border-l-4 border-red-500 text-red-700 dark:text-red-300 p-3 rounded">
163+
<motion.div
164+
initial={{ opacity: 0 }}
165+
animate={{ opacity: 1 }}
166+
className="bg-red-100 dark:bg-red-900/30 border-l-4 border-red-500 text-red-700 dark:text-red-300 p-3 rounded"
167+
>
107168
{error}
108169
</motion.div>
109170
)}
@@ -145,6 +206,8 @@ export default function LoginPage() {
145206
type="text"
146207
className="w-full pl-10 pr-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-950 dark:text-gray-200"
147208
placeholder="Full name"
209+
value={name}
210+
onChange={(e) => setName(e.target.value)}
148211
/>
149212
</div>
150213
)}
@@ -162,19 +225,19 @@ export default function LoginPage() {
162225
disabled={loading}
163226
className={`w-full flex items-center justify-center py-3 px-4 rounded-lg text-white font-medium transition-all ${
164227
loading
165-
? 'bg-gray-400 dark:bg-gray-600 cursor-not-allowed'
166-
: 'bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-800 shadow-md hover:shadow-lg'
228+
? "bg-gray-400 dark:bg-gray-600 cursor-not-allowed"
229+
: "bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-800 shadow-md hover:shadow-lg"
167230
}`}
168231
>
169232
{loading ? (
170-
'Processing...'
233+
"Processing..."
171234
) : isLogin ? (
172235
<>
173-
<FiLogIn className="mr-2" /> Sign In
236+
<FiLogIn className="mr-2" /> Continue
174237
</>
175238
) : (
176239
<>
177-
<FiUserPlus className="mr-2" /> Sign Up
240+
<FiUserPlus className="mr-2" /> Continue
178241
</>
179242
)}
180243
</button>
@@ -184,48 +247,45 @@ export default function LoginPage() {
184247
<div className="text-center text-sm text-gray-600 dark:text-gray-400">
185248
{isLogin ? (
186249
<p>
187-
Don't have an account?{' '}
188-
<button onClick={() => setIsLogin(false)} className="text-blue-600 dark:text-blue-400 hover:underline">
250+
Don't have an account?{" "}
251+
<button
252+
onClick={() => setIsLogin(false)}
253+
className="text-blue-600 dark:text-blue-400 hover:underline"
254+
>
189255
Sign up
190256
</button>
191257
</p>
192258
) : (
193259
<p>
194-
Already have an account?{' '}
195-
<button onClick={() => setIsLogin(true)} className="text-blue-600 dark:text-blue-400 hover:underline">
260+
Already have an account?{" "}
261+
<button
262+
onClick={() => setIsLogin(true)}
263+
className="text-blue-600 dark:text-blue-400 hover:underline"
264+
>
196265
Sign in
197266
</button>
198267
</p>
199268
)}
200269
</div>
201270

202-
{/* Google OAuth */}
203-
<div className="relative flex items-center py-4">
204-
<div className="flex-grow border-t border-gray-300 dark:border-gray-600"></div>
205-
<span className="flex-shrink mx-4 text-gray-500 dark:text-gray-400">or</span>
206-
<div className="flex-grow border-t border-gray-300 dark:border-gray-600"></div>
207-
</div>
208-
209-
<button
210-
onClick={handleGoogleSignIn}
211-
className="w-full flex items-center justify-center py-3 px-4 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-neutral-950 text-gray-700 dark:text-gray-200 font-medium hover:bg-gray-50 dark:hover:bg-neutral-900 duration-300 transition-all"
212-
>
213-
<img src="./google.webp" width={24}></img>
214-
<span className='mx-2'>Continue with Google</span>
215-
</button>
216-
217271
<div className="text-center text-xs text-gray-500 dark:text-gray-400 mt-6">
218-
By continuing, you agree to our{' '}
219-
<Link href="/terms" className="text-blue-500 dark:text-blue-400 hover:underline">
272+
By continuing, you agree to our{" "}
273+
<Link
274+
href="/terms"
275+
className="text-blue-500 dark:text-blue-400 hover:underline"
276+
>
220277
Terms of Service
221-
</Link>{' '}
222-
and{' '}
223-
<Link href="/privacy" className="text-blue-500 dark:text-blue-400 hover:underline">
278+
</Link>{" "}
279+
and{" "}
280+
<Link
281+
href="/privacy"
282+
className="text-blue-500 dark:text-blue-400 hover:underline"
283+
>
224284
Privacy Policy
225285
</Link>
226286
</div>
227287
</div>
228288
</motion.div>
229289
</div>
230-
)
231-
}
290+
);
291+
}

app/visualizer/stack/implementation/usingLinkedList/animation.jsx

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)