Skip to content

Commit 23d2471

Browse files
author
Boopathi
committed
refactor: improve recaptcha integration, header UX, and main-view logic; fix ESLint config
1 parent 6dffc43 commit 23d2471

File tree

10 files changed

+96
-127
lines changed

10 files changed

+96
-127
lines changed

.eslintrc.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"extends": [
3+
"next/core-web-vitals"
4+
]
5+
}

out/404.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

out/index.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

out/index.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
2:"$Sreact.suspense"
2-
3:I[74344,["9990","static/chunks/7c86ec74-5d3e2c324eba8f04.js","8415","static/chunks/8415-3647249926a008b4.js","5844","static/chunks/5844-71d41ecabde65adb.js","9635","static/chunks/9635-1974f6391a1f5d48.js","8437","static/chunks/8437-9cca2dc77cd479a5.js","3145","static/chunks/3145-96a9e135101030c6.js","5935","static/chunks/5935-e7af8502207931af.js","7094","static/chunks/7094-2b10a40822cc84b1.js","1931","static/chunks/app/page-809537aa54103941.js"],"default"]
3-
4:I[11225,["8068","static/chunks/8068-111f0b00c8797a1e.js","8415","static/chunks/8415-3647249926a008b4.js","5844","static/chunks/5844-71d41ecabde65adb.js","1915","static/chunks/1915-bfb0f97fd1af2908.js","8003","static/chunks/8003-638df8dcb4557297.js","3185","static/chunks/app/layout-e17b7c04d848095c.js"],"default"]
2+
3:I[74344,["9990","static/chunks/7c86ec74-5d3e2c324eba8f04.js","8415","static/chunks/8415-3647249926a008b4.js","5844","static/chunks/5844-71d41ecabde65adb.js","9635","static/chunks/9635-c1242a475b801a6a.js","8437","static/chunks/8437-9cca2dc77cd479a5.js","3145","static/chunks/3145-96a9e135101030c6.js","5935","static/chunks/5935-e7af8502207931af.js","7094","static/chunks/7094-fdb52e9197204303.js","1931","static/chunks/app/page-fe19e23c1c7e01c9.js"],"default"]
3+
4:I[11225,["8068","static/chunks/8068-111f0b00c8797a1e.js","8415","static/chunks/8415-3647249926a008b4.js","5844","static/chunks/5844-71d41ecabde65adb.js","1915","static/chunks/1915-bfb0f97fd1af2908.js","3185","static/chunks/app/layout-a21bbe360d2476df.js"],"default"]
44
5:I[4707,[],""]
55
6:I[36423,[],""]
66
7:I[75292,["8415","static/chunks/8415-3647249926a008b4.js","5896","static/chunks/5896-dd3fa908e6e2380d.js","9160","static/chunks/app/not-found-4ad8109c7ea602ca.js"],"default"]
7-
8:I[94886,["8068","static/chunks/8068-111f0b00c8797a1e.js","8415","static/chunks/8415-3647249926a008b4.js","5844","static/chunks/5844-71d41ecabde65adb.js","1915","static/chunks/1915-bfb0f97fd1af2908.js","8003","static/chunks/8003-638df8dcb4557297.js","3185","static/chunks/app/layout-e17b7c04d848095c.js"],"Toaster"]
8-
9:I[88003,["8068","static/chunks/8068-111f0b00c8797a1e.js","8415","static/chunks/8415-3647249926a008b4.js","5844","static/chunks/5844-71d41ecabde65adb.js","1915","static/chunks/1915-bfb0f97fd1af2908.js","8003","static/chunks/8003-638df8dcb4557297.js","3185","static/chunks/app/layout-e17b7c04d848095c.js"],""]
7+
8:I[94886,["8068","static/chunks/8068-111f0b00c8797a1e.js","8415","static/chunks/8415-3647249926a008b4.js","5844","static/chunks/5844-71d41ecabde65adb.js","1915","static/chunks/1915-bfb0f97fd1af2908.js","3185","static/chunks/app/layout-a21bbe360d2476df.js"],"Toaster"]
8+
9:I[88003,["8068","static/chunks/8068-111f0b00c8797a1e.js","8415","static/chunks/8415-3647249926a008b4.js","5844","static/chunks/5844-71d41ecabde65adb.js","1915","static/chunks/1915-bfb0f97fd1af2908.js","3185","static/chunks/app/layout-a21bbe360d2476df.js"],""]
99
a:T43f,
1010
window.$zoho = window.$zoho || {};
1111
window.$zoho.salesiq = window.$zoho.salesiq || {
@@ -32,6 +32,6 @@ s.defer = true;
3232
s.src = "https://salesiq.zohopublic.in/widget";
3333
var t = d.getElementsByTagName("script")[0];
3434
t.parentNode.insertBefore(s, t);
35-
0:["aCrr5ginpDcnQ6BR98iCY",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$2",null,{"fallback":["$","div",null,{"children":"Loading..."}],"children":["$","$L3",null,{}]}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/02b2aee02a368ff7.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"__variable_19640c __variable_9f6af0","suppressHydrationWarning":true,"children":[["$","head",null,{"children":["$","script",null,{"dangerouslySetInnerHTML":{"__html":"\n (function() {\n try {\n let theme = localStorage.getItem('theme');\n if (!theme) {\n theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n if (theme === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n } catch (e) {}\n })();\n "}}]}],["$","body",null,{"className":"antialiased bg-background font-sans","children":[["$","div",null,{"className":"flex flex-col min-h-screen","children":[["$","div",null,{"className":"hidden dark:block","children":["$","$L4",null,{}]}],["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":["$","$L7",null,{}],"notFoundStyles":[]}]]}],["$","$L8",null,{}],["$","$L9",null,{"id":"zoho-salesiq-script","strategy":"lazyOnload","children":"$a"}]]}]]}]],null],null],["$Lb",null]]]]
35+
0:["93wN5Evye5YSltvIKc15Z",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$2",null,{"fallback":["$","div",null,{"children":"Loading..."}],"children":["$","$L3",null,{}]}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/02b2aee02a368ff7.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"__variable_19640c __variable_9f6af0","suppressHydrationWarning":true,"children":[["$","head",null,{"children":["$","script",null,{"dangerouslySetInnerHTML":{"__html":"\n (function() {\n try {\n let theme = localStorage.getItem('theme');\n if (!theme) {\n theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n if (theme === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n } catch (e) {}\n })();\n "}}]}],["$","body",null,{"className":"antialiased bg-background font-sans","children":[["$","div",null,{"className":"flex flex-col min-h-screen","children":[["$","div",null,{"className":"hidden dark:block","children":["$","$L4",null,{}]}],["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":["$","$L7",null,{}],"notFoundStyles":[]}]]}],["$","$L8",null,{}],["$","$L9",null,{"id":"zoho-salesiq-script","strategy":"lazyOnload","children":"$a"}]]}]]}]],null],null],["$Lb",null]]]]
3636
b:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Hustloop | Connect, Collaborate, Build Stronger Startup & Innovators Meet"}],["$","meta","3",{"name":"description","content":"A prototype startup platform that includes modules such as Blog, Mentors, Incubators, Pricing, and MSMEs."}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"48x48"}],["$","meta","5",{"name":"next-size-adjust"}]]
3737
1:null

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"@types/react": "^18",
5555
"@types/react-dom": "^18",
5656
"eslint": "^8",
57-
"eslint-config-next": "14.2.5",
57+
"eslint-config-next": "^14.2.5",
5858
"postcss": "^8",
5959
"tailwindcss": "^3.4.1",
6060
"typescript": "^5"

src/components/auth/login-modal.tsx

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {
2020
signInWithPopup
2121
} from "firebase/auth";
2222
import { useRouter } from "next/navigation";
23-
import Script from "next/script";
2423

2524
const GoogleIcon = (props: React.SVGProps<SVGSVGElement>) => (
2625
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="18" height="18" {...props}>
@@ -67,23 +66,26 @@ export default function LoginModal({ isOpen, setIsOpen, onLoginSuccess }: LoginM
6766

6867
const { formState: { isSubmitting }, getValues } = form;
6968

70-
const executeRecaptcha = (callback: (token: string) => void) => {
71-
if (!window.grecaptcha) {
72-
toast({ variant: 'destructive', title: 'reCAPTCHA Error', description: 'reCAPTCHA not loaded. Please try again.' });
73-
return;
74-
}
75-
window.grecaptcha.enterprise.ready(() => {
76-
window.grecaptcha.enterprise.execute('6LfZ4H8rAAAAAA0NMVH1C-sCiE9-Vz4obaWy9eUI', { action: 'login' }).then(callback);
69+
const executeRecaptcha = (action: 'login' | 'register'): Promise<string> => {
70+
return new Promise((resolve, reject) => {
71+
if (!window.grecaptcha || !window.grecaptcha.enterprise) {
72+
toast({ variant: 'destructive', title: 'reCAPTCHA Error', description: 'reCAPTCHA not loaded. Please try again.' });
73+
return reject('reCAPTCHA not loaded');
74+
}
75+
window.grecaptcha.enterprise.ready(() => {
76+
window.grecaptcha.enterprise.execute('6LfZ4H8rAAAAAA0NMVH1C-sCiE9-Vz4obaWy9eUI', { action }).then(resolve).catch(reject);
77+
});
7778
});
7879
};
7980

80-
const handlePasswordLogin = async (values: LoginSchema, recaptchaToken: string) => {
81+
const handlePasswordLogin = async (values: LoginSchema) => {
8182
if (!auth) {
8283
toast({ variant: 'destructive', title: 'Error', description: 'Authentication service is not available.' });
8384
return;
8485
}
85-
86+
8687
try {
88+
const recaptchaToken = await executeRecaptcha('login');
8789
const userCredential = await signInWithEmailAndPassword(auth, values.email, values.password);
8890
const firebaseUser = userCredential.user;
8991

@@ -123,12 +125,6 @@ export default function LoginModal({ isOpen, setIsOpen, onLoginSuccess }: LoginM
123125
}
124126
};
125127

126-
const handleLoginSubmit = (values: LoginSchema) => {
127-
executeRecaptcha((token) => {
128-
handlePasswordLogin(values, token);
129-
});
130-
};
131-
132128
const handleSocialLogin = async (provider: 'google') => {
133129
if (!auth) {
134130
toast({ variant: 'destructive', title: 'Error', description: 'Authentication service is not available.' });
@@ -171,27 +167,22 @@ export default function LoginModal({ isOpen, setIsOpen, onLoginSuccess }: LoginM
171167
}
172168
const email = getValues("email");
173169
if (!email) {
174-
toast({ variant: "destructive", title: "Email Required", description: "Please enter your email address." });
170+
toast({ variant: "destructive", title: "Email Required", description: "Please enter your email address to reset your password." });
175171
return;
176172
}
177173
const actionCodeSettings = {
178-
url: `${window.location.origin}/?action=login&from=reset`,
174+
url: `${window.location.origin}/auth/action`,
179175
handleCodeInApp: true,
180176
};
181177
try {
182178
await sendPasswordResetEmail(auth, email, actionCodeSettings);
183-
toast({ title: "Password Reset Email Sent", description: "Please check your inbox." });
179+
toast({ title: "Password Reset Email Sent", description: "Please check your inbox for a link to reset your password." });
184180
} catch (error: any) {
185-
toast({ variant: "destructive", title: "Failed to Send Email", description: "Could not send password reset email." });
181+
toast({ variant: "destructive", title: "Failed to Send Email", description: "Could not send password reset email. Please ensure the email address is correct." });
186182
}
187183
};
188184

189185
return (
190-
<>
191-
<Script
192-
src="https://www.google.com/recaptcha/enterprise.js?render=6LfZ4H8rAAAAAA0NMVH1C-sCiE9-Vz4obaWy9eUI"
193-
strategy="lazyOnload"
194-
/>
195186
<Dialog open={isOpen} onOpenChange={setIsOpen}>
196187
<DialogContent className="sm:max-w-lg auth-modal-glow overflow-hidden">
197188
<DialogHeader className="text-center">
@@ -211,7 +202,7 @@ export default function LoginModal({ isOpen, setIsOpen, onLoginSuccess }: LoginM
211202
</div>
212203

213204
<Form {...form}>
214-
<form onSubmit={form.handleSubmit(handleLoginSubmit)} className="space-y-4">
205+
<form onSubmit={form.handleSubmit(handlePasswordLogin)} className="space-y-4">
215206
<FormField
216207
control={form.control}
217208
name="email"
@@ -247,8 +238,5 @@ export default function LoginModal({ isOpen, setIsOpen, onLoginSuccess }: LoginM
247238
</Form>
248239
</DialogContent>
249240
</Dialog>
250-
</>
251241
);
252242
}
253-
254-

src/components/auth/signup-modal.tsx

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
signInWithPopup
1818
} from "firebase/auth";
1919
import { useRouter } from "next/navigation";
20-
import Script from 'next/script';
2120

2221

2322
const GoogleIcon = (props: React.SVGProps<SVGSVGElement>) => (
@@ -70,48 +69,49 @@ export default function SignupModal({ isOpen, setIsOpen }: SignupModalProps) {
7069

7170
const { formState: { isSubmitting } } = form;
7271

73-
const executeRecaptcha = (callback: (token: string) => void) => {
74-
if (!window.grecaptcha) {
75-
toast({ variant: 'destructive', title: 'reCAPTCHA Error', description: 'reCAPTCHA not loaded. Please try again.' });
76-
return;
77-
}
78-
window.grecaptcha.enterprise.ready(() => {
79-
window.grecaptcha.enterprise.execute('6LfZ4H8rAAAAAA0NMVH1C-sCiE9-Vz4obaWy9eUI', { action: 'register' }).then(callback);
72+
const executeRecaptcha = (action: 'login' | 'register'): Promise<string> => {
73+
return new Promise((resolve, reject) => {
74+
if (!window.grecaptcha || !window.grecaptcha.enterprise) {
75+
toast({ variant: 'destructive', title: 'reCAPTCHA Error', description: 'reCAPTCHA not loaded. Please try again.' });
76+
return reject('reCAPTCHA not loaded');
77+
}
78+
window.grecaptcha.enterprise.ready(() => {
79+
window.grecaptcha.enterprise.execute('6LfZ4H8rAAAAAA0NMVH1C-sCiE9-Vz4obaWy9eUI', { action }).then(resolve).catch(reject);
80+
});
8081
});
8182
};
8283

83-
const handleSignup = (values: SignupSchema) => {
84-
executeRecaptcha(async (recaptchaToken: string) => {
85-
try {
86-
const response = await fetch(`${API_BASE_URL}/api/register`, {
87-
method: 'POST',
88-
headers: { 'Content-Type': 'application/json' },
89-
body: JSON.stringify({ ...values, recaptchaToken }),
90-
});
84+
const handleSignup = async (values: SignupSchema) => {
85+
try {
86+
const recaptchaToken = await executeRecaptcha('register');
87+
const response = await fetch(`${API_BASE_URL}/api/register`, {
88+
method: 'POST',
89+
headers: { 'Content-Type': 'application/json' },
90+
body: JSON.stringify({ ...values, recaptchaToken }),
91+
});
9192

92-
const data = await response.json();
93-
94-
if (response.ok) {
95-
toast({
96-
title: "Registration Successful",
97-
description: "Your account has been created. Please check your email to verify your account.",
98-
});
99-
setIsOpen(false);
100-
} else {
101-
toast({
102-
variant: "destructive",
103-
title: "Registration Failed",
104-
description: data.error || 'An unexpected error occurred.',
105-
});
106-
}
107-
} catch (error) {
93+
const data = await response.json();
94+
95+
if (response.ok) {
96+
toast({
97+
title: "Registration Successful",
98+
description: "Your account has been created. Please check your email to verify your account.",
99+
});
100+
setIsOpen(false);
101+
} else {
108102
toast({
109103
variant: "destructive",
110104
title: "Registration Failed",
111-
description: "Could not connect to the server. Please try again later.",
105+
description: data.error || 'An unexpected error occurred.',
112106
});
113107
}
114-
});
108+
} catch (error) {
109+
toast({
110+
variant: "destructive",
111+
title: "Registration Failed",
112+
description: "Could not connect to the server. Please try again later.",
113+
});
114+
}
115115
};
116116

117117
const handleSocialLogin = async (provider: 'google') => {
@@ -141,11 +141,6 @@ export default function SignupModal({ isOpen, setIsOpen }: SignupModalProps) {
141141
};
142142

143143
return (
144-
<>
145-
<Script
146-
src="https://www.google.com/recaptcha/enterprise.js?render=6LfZ4H8rAAAAAA0NMVH1C-sCiE9-Vz4obaWy9eUI"
147-
strategy="lazyOnload"
148-
/>
149144
<Dialog open={isOpen} onOpenChange={setIsOpen}>
150145
<DialogContent className="sm:max-w-lg auth-modal-glow overflow-hidden">
151146
<DialogHeader className="text-center">
@@ -224,6 +219,5 @@ export default function SignupModal({ isOpen, setIsOpen }: SignupModalProps) {
224219
</Form>
225220
</DialogContent>
226221
</Dialog>
227-
</>
228222
);
229223
}

0 commit comments

Comments
 (0)