Skip to content

Commit 6160e75

Browse files
committed
Validation and frontend mod
1 parent a1408f1 commit 6160e75

14 files changed

Lines changed: 506 additions & 307 deletions

File tree

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"axios": "^1.8.4",
1515
"clsx": "^2.0.0",
1616
"framer-motion": "^12.6.5",
17+
"lodash": "^4.17.21",
1718
"next": "^15.2.4",
1819
"notistack": "^3.0.1",
1920
"preline": "^2.0.2",
@@ -31,6 +32,7 @@
3132
"@rollup/plugin-terser": "^0.4.4",
3233
"@tailwindcss/forms": "^0.5.7",
3334
"@types/crypto-js": "^4.2.1",
35+
"@types/lodash": "^4.17.16",
3436
"@types/node": "^20.8.8",
3537
"@types/react": "^18.2.15",
3638
"@types/react-dom": "^18.2.7",

src/App.css

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
.with-base-gradient {
66
@apply bg-gradient-to-tl from-blue-600 to-violet-600;
77
}
8+
89
.left-shadow {
910
width: 100%;
1011
height: 100%;
@@ -17,4 +18,44 @@
1718
height: 100%;
1819
box-shadow: -10px 0 15px 5px #f6f6f600;
1920
}
21+
}
22+
23+
@layer utilities {
24+
.neon-glow {
25+
text-shadow:
26+
0 0 5px #774A67,
27+
0 0 10px #774A67,
28+
0 0 20px #774A67,
29+
0 0 40px #774A67,
30+
0 0 80px #774A67;
31+
}
32+
}
33+
34+
@layer utilities {
35+
.neon-border-glow {
36+
box-shadow:
37+
0 0 5px #774A67,
38+
0 0 10px #774A67,
39+
0 0 20px #774A67,
40+
0 0 40px #774A67,
41+
0 0 80px #774A67;
42+
}
43+
44+
.animate-border-glow {
45+
animation: border-glow 3s ease-in-out infinite;
46+
}
47+
48+
/* @keyframes border-glow {
49+
0% {
50+
box-shadow: 0 0 10px #774A67;
51+
}
52+
53+
50% {
54+
box-shadow: 0 0 25px #774A67;
55+
}
56+
57+
100% {
58+
box-shadow: 0 0 10px #774A67;
59+
}
60+
} */
2061
}

src/api/useAxiosSWR.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,30 @@
22
import useSWR from "swr";
33
import AxiosFetcher from "./AxiosFetcher";
44
import { VITE_LAMBDA_URL } from "@constants/index";
5+
56
// VITE_BE_DOMAIN,
67

78
// ENDPOINTS keys
89
export const ENDPOINTS = {
910
// Auth
1011
login: "https://test.neotechis.com/api/method/alphax_erp.api.login.login", // Login
11-
logout: "https://test.neotechis.com/api/method/alphax_erp.api.login.logout",
12+
logout: "https://test.neotechis.com/api/method/alphax_erp.api.login.logout_user",
1213
// signup: "http://test.neotec.ai/api/method/alphax_erp.api.auth.signup_and_get_token",
1314
// createSite: "http://test.neotec.ai/api/method/alphax_erp.api.utils.create_new_site",
1415
signup: "https://test.neotechis.com/api/method/alphax_erp.api.auth.signup_and_get_token",
1516
createSite: "https://test.neotechis.com/api/method/alphax_erp.api.utils.create_new_site",
17+
// checkUserInputAvailability: "https://test.neotechis.com/api/method/alphax_erp.api.validate_user_input.validate_user_input",
18+
validateFirstName: "https://test.neotechis.com/api/method/alphax_erp.api.validate_user_input.validate_first_name",
19+
validateEmail: "https://test.neotechis.com/api/method/alphax_erp.api.validate_user_input.validate_email",
20+
validateSiteName: "https://test.neotechis.com/api/method/alphax_erp.api.validate_user_input.validate_site_name",
1621

1722
// Optional
1823
configSite: "/server/config-site",
1924
registerTrial: "/user/trial",
2025
registerPremium: "/user/premium",
2126
};
2227

28+
2329
// Axios instances
2430
export const fetcher = new AxiosFetcher(import.meta.env.VITE_BE_DOMAIN);
2531
export const serverFetcher = new AxiosFetcher(VITE_LAMBDA_URL);

src/components/sections/Features/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const Features = () => {
55
<section className="my-5 md:my-12">
66
{/* features title and subtitle */}
77
<div className="max-w-2xl mx-auto text-center mb-8 lg:mb-10 px-4">
8-
<h2 className="text-2xl font-bold md:text-4xl md:leading-tight dark:text-white">
8+
<h2 className="text-2xl font-bold md:text-4xl md:leading-tight dark:text-white neon-glow">
99
Right Service, Right Result
1010
</h2>
1111
<p className="mt-1 text-gray-600 dark:text-gray-400">
@@ -16,10 +16,9 @@ const Features = () => {
1616
<div className="w-full flex justify-center">
1717
<div
1818
className="rounded-md md:rounded-xl mx-4 mb-5 flex-1 max-w-[85rem]
19-
bg-gradient-to-tl from-[#774A67] to-[#774A67] dark:from-[#774A67] dark:to-[#774A67] p-0 md:p-[2px]"
20-
>
19+
bg-gradient-to-tl from-[#774A67] to-[#774A67] dark:from-[#774A67] dark:to-[#774A67] p-0 md:p-[2px]">
2120
{/* features grid */}
22-
<div className="grid sm:grid-cols-2 lg:grid-cols-4 items-center gap-8 md:gap-10 bg-white/90 dark:bg-[#03020395] backdrop-blur-sm p-5 md:p-10 rounded-md md:rounded-xl">
21+
<div className="relative grid sm:grid-cols-2 lg:grid-cols-4 items-center gap-8 md:gap-10 bg-white/90 dark:bg-[#03020395] backdrop-blur-sm p-5 md:p-10 rounded-md md:rounded-xl overflow-hidden neon-border-glow animate-border-glow">
2322
{FEATURES.map((feat) => {
2423
return (
2524
<div key={feat.title}>
@@ -38,6 +37,7 @@ const Features = () => {
3837
);
3938
})}
4039
</div>
40+
4141
{/* features grid */}
4242
</div>
4343
</div>

src/components/sections/Footer/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const Fotter = () => {
2424
<div className="col-span-full hidden lg:col-span-1 lg:block">
2525
<a
2626
aria-label="Brand"
27-
className="font-mono flex-none text-xl font-semibold dark:text-white"
27+
className="font-mono flex-none text-xl font-semibold dark:text-white neon-glow"
2828
href="#"
2929
>
3030
AlphaX

src/components/sections/GetStartedModal/components/SignInForm.tsx

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -31,39 +31,75 @@ const SignInForm = ({ toggleSignUp, loginSuccess, setLoginSuccess }: Props) => {
3131
const onSubmit = async (data: { email: string; password: string }) => {
3232
console.log("🔐 Attempting login with:", data);
3333
setLogging(true);
34-
// final working
3534
try {
36-
// Step 1: Clear previous session
35+
// Step 1: Clear previous session if it exists
36+
const sid = localStorage.getItem("sid");
3737
localStorage.removeItem("sid");
3838
console.log("🧹 Cleared localStorage token");
3939

40-
await fetch("https://test.neotechis.com/api/method/logout", {
41-
method: "GET",
42-
credentials: "include",
43-
});
44-
console.log("🔄 Forced logout of any existing session");
40+
if (sid) {
41+
// Only call logout if there was a previous session
42+
try {
43+
const logoutRes = await fetch(
44+
"https://test.neotechis.com/api/method/alphax_erp.api.login.logout_user",
45+
{
46+
method: "GET",
47+
credentials: "include",
48+
}
49+
);
50+
console.log("🔄 Logout response status:", logoutRes.status);
51+
52+
if (!logoutRes.ok) {
53+
console.warn("⚠️ Logout failed:", logoutRes.status, await logoutRes.text());
54+
// Proceed with login even if logout fails (e.g., 403 for no active session)
55+
} else {
56+
console.log("🔄 Forced logout of any existing session");
57+
}
58+
} catch (logoutError) {
59+
console.warn("⚠️ Error during logout, proceeding with login:", logoutError);
60+
// Continue with login even if logout fails
61+
}
62+
} else {
63+
console.log("ℹ️ No previous session, skipping logout");
64+
}
4565

4666
// Step 2: Login
47-
const loginRes = await fetch("https://test.neotechis.com/api/method/alphax_erp.api.login.login", {
48-
method: "POST",
49-
headers: {
50-
"Content-Type": "application/json",
51-
},
52-
credentials: "include",
53-
body: JSON.stringify({
54-
email: data.email,
55-
password: data.password,
56-
}),
57-
});
67+
const loginRes = await fetch(
68+
"https://test.neotechis.com/api/method/alphax_erp.api.login.login",
69+
{
70+
method: "POST",
71+
headers: {
72+
"Content-Type": "application/json",
73+
},
74+
credentials: "include",
75+
body: JSON.stringify({
76+
email: data.email,
77+
password: data.password,
78+
}),
79+
}
80+
);
5881

5982
console.log("📥 Login response status:", loginRes.status);
6083

6184
if (!loginRes.ok) {
6285
const err = await loginRes.json();
6386
console.error("❌ Login failed:", err);
6487

65-
const messages = JSON.parse(err._server_messages || "[]");
66-
const errorMsg = messages.length ? messages[0] : err.message || "Login failed";
88+
let errorMsg = "Login failed";
89+
if (loginRes.status === 401) {
90+
errorMsg = err.message || "Invalid email or password";
91+
} else if (loginRes.status === 500) {
92+
errorMsg = err.message || "Something went wrong, please try again later.";
93+
} else {
94+
try {
95+
const messages = JSON.parse(err._server_messages || "[]");
96+
errorMsg = messages.length ? messages[0] : err.message || "Login failed";
97+
} catch {
98+
errorMsg = err.message || "Unexpected error occurred";
99+
}
100+
}
101+
102+
enqueueSnackbar(errorMsg, { variant: "error" });
67103
throw new Error(errorMsg);
68104
}
69105

@@ -89,12 +125,12 @@ const SignInForm = ({ toggleSignUp, loginSuccess, setLoginSuccess }: Props) => {
89125

90126
setTimeout(() => {
91127
const redirectUrl = url || "https://test.neotechis.com/dashboard";
92-
console.log("➡️ Redirecting to:", redirectUrl);
93-
location.replace(redirectUrl);
128+
console.log("➡️ Opening in new tab:", redirectUrl);
129+
window.open(redirectUrl, "_blank");
94130
}, 500);
95131
} catch (error) {
96132
console.error("🚨 Login error:", error);
97-
enqueueSnackbar((error as Error).message || "Login failed", {
133+
enqueueSnackbar("An unexpected error occurred. Please try again.", {
98134
variant: "error",
99135
});
100136
} finally {
@@ -105,28 +141,28 @@ const SignInForm = ({ toggleSignUp, loginSuccess, setLoginSuccess }: Props) => {
105141
return (
106142
<div
107143
className={cn(
108-
"w-full mx-4 my-4 lg:mx-0 lg:mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700 md:max-w-[450px]",
144+
"w-full mx-4 my-4 lg:mx-0 lg:mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700 md:max-w-[450px] ",
109145
loginSuccess && "md:max-w-max"
110146
)}
111147
>
112148
{!loginSuccess && (
113149
<div className="p-4 sm:p-7">
114-
<h1 className="block text-2xl font-bold text-gray-800 dark:text-white text-center">
150+
<h1 className="text-4xl font-bold text-center text-gray-800 dark:text-[#00f0ff] neon-glow">
115151
Sign in
116152
</h1>
117153

118154
<div className="mt-5">
119155
<form className="w-full" onSubmit={handleSubmit(onSubmit)}>
120156
<div className="grid gap-y-4">
121157
<div>
122-
<label htmlFor="email" className="block text-sm mb-2 dark:text-white">
158+
<label htmlFor="email" className="block text-base mb-2 dark:text-white">
123159
Email <span className="text-red-400">*</span>
124160
</label>
125161
<input
126162
type="email"
127163
id="email"
128-
className="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600"
129-
placeholder="Enter your lovely email"
164+
className="py-3 px-4 block w-full border rounded-lg text-sm dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 placeholder:text-gray-400 focus:outline-none focus:border-[#774A67] focus:shadow-[0_0_15px_#774A67] transition duration-300"
165+
placeholder="Enter your E-mail"
130166
{...register("email", {
131167
required: "Email is required",
132168
pattern: {
@@ -144,13 +180,13 @@ const SignInForm = ({ toggleSignUp, loginSuccess, setLoginSuccess }: Props) => {
144180
</div>
145181

146182
<div>
147-
<label htmlFor="password" className="block text-sm mb-2 dark:text-white">
183+
<label htmlFor="password" className="block text-base mb-2 dark:text-white">
148184
Password <span className="text-red-400">*</span>
149185
</label>
150186
<input
151187
type="password"
152188
id="password"
153-
className="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600"
189+
className="py-3 px-4 block w-full border rounded-lg text-sm dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 placeholder:text-gray-400 focus:outline-none focus:border-[#774A67] focus:shadow-[0_0_15px_#774A67] transition duration-300"
154190
placeholder="Enter your password"
155191
{...register("password", {
156192
required: "Password is required",
@@ -171,7 +207,7 @@ const SignInForm = ({ toggleSignUp, loginSuccess, setLoginSuccess }: Props) => {
171207
<button
172208
type="submit"
173209
disabled={logging}
174-
className="w-full mt-4 py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-[#774A67] text-white hover:bg-[#774A67] disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600"
210+
className="w-full mt-4 py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-[#774A67] text-white hover:bg-[#774A67] hover:shadow-[0_0_15px_#774A67] focus:outline-none focus:ring-2 focus:ring-[#774A67] focus:shadow-[0_0_15px_#774A67] transition duration-300 disabled:opacity-50 disabled:pointer-events-none"
175211
>
176212
{logging ? <Loader /> : "Sign in"}
177213
</button>
@@ -184,7 +220,7 @@ const SignInForm = ({ toggleSignUp, loginSuccess, setLoginSuccess }: Props) => {
184220
</div>
185221

186222
<div className="text-center">
187-
<p className="mt-2 text-sm text-gray-600 dark:text-gray-400">
223+
<p className="mt-2 text-base text-gray-600 dark:text-gray-400">
188224
Don't have an account yet?
189225
<a
190226
className="text-blue-600 decoration-2 hover:underline font-medium dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600"
@@ -207,7 +243,7 @@ const SignInForm = ({ toggleSignUp, loginSuccess, setLoginSuccess }: Props) => {
207243
export default SignInForm;
208244

209245

210-
246+
// location.replace(redirectUrl); <----- imp do not remove
211247

212248
// import { EMAIL_PATTERN } from "@constants/index";
213249
// import { ENDPOINTS, fetcher } from "@api/useAxiosSWR";

0 commit comments

Comments
 (0)