diff --git a/src/app/(main)/funds_transfer/send_beneficiary/page.tsx b/src/app/(main)/funds_transfer/send_beneficiary/page.tsx
index 8b8135f..a7ac27b 100644
--- a/src/app/(main)/funds_transfer/send_beneficiary/page.tsx
+++ b/src/app/(main)/funds_transfer/send_beneficiary/page.tsx
@@ -56,7 +56,6 @@ export default function SendToBeneficiaryOwn() {
setCountdown(180);
setTimerActive(true);
} catch (err: any) {
- console.error('Send OTP failed', err);
notifications.show({
title: 'Error',
message: err.message || 'Send OTP failed.Please try again later.',
diff --git a/src/app/(main)/funds_transfer/send_beneficiary/sendBeneficiaryOthers.tsx b/src/app/(main)/funds_transfer/send_beneficiary/sendBeneficiaryOthers.tsx
index 0787f06..6ceb13c 100644
--- a/src/app/(main)/funds_transfer/send_beneficiary/sendBeneficiaryOthers.tsx
+++ b/src/app/(main)/funds_transfer/send_beneficiary/sendBeneficiaryOthers.tsx
@@ -71,7 +71,6 @@ export default function SendToBeneficiaryOthers() {
setCountdown(180);
setTimerActive(true);
} catch (err: any) {
- console.error('Send OTP failed', err);
notifications.show({
title: 'Error',
message: err.message || 'Send OTP failed.Please try again later.',
diff --git a/src/app/_util/otp.ts b/src/app/_util/otp.ts
index 414438b..67bdb52 100644
--- a/src/app/_util/otp.ts
+++ b/src/app/_util/otp.ts
@@ -12,6 +12,7 @@ interface SendOtpPayload {
ref?: string;
date?: string;
userOtp?: string;
+ username?:string
}
function getStoredMobileNumber(): string | null {
@@ -43,7 +44,6 @@ export async function sendOtp(payload: SendOtpPayload) {
}
}
-
export async function verifyOtp(otp: string) {
try {
const mobileNumber = getStoredMobileNumber();
@@ -58,3 +58,18 @@ export async function verifyOtp(otp: string) {
throw error.response?.data || error;
}
}
+
+export async function verifyLoginOtp(otp: string,mobileNumber:string) {
+ try {
+ // const mobileNumber = getStoredMobileNumber();
+ const response = await axios.post(
+ `http://localhost:8080/api/otp/verify?mobileNumber=${mobileNumber}`,
+ { otp },
+ { headers: { 'Content-Type': 'application/json' } }
+ );
+ return response.data;
+ } catch (error: any) {
+ console.error('Error verifying OTP:', error.response?.data || error.message);
+ throw error.response?.data || error;
+ }
+}
\ No newline at end of file
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index a14c64d..0791c4a 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -4,13 +4,14 @@ import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Flex, Box,
import { notifications } from "@mantine/notifications";
import { Providers } from "@/app/providers";
import { useRouter } from "next/navigation";
+import { sendOtp, verifyLoginOtp } from '@/app/_util/otp';
import NextImage from "next/image";
import styles from './page.module.css';
import logo from '@/app/image/logo1.jpg';
import frontPage from '@/app/image/ib_front_1.jpg';
import dynamic from 'next/dynamic';
import { generateCaptcha } from '@/app/captcha';
-import { IconShieldLockFilled } from "@tabler/icons-react";
+import { IconRefresh, IconShieldLockFilled } from "@tabler/icons-react";
import dayjs from "dayjs";
@@ -27,6 +28,46 @@ export default function Login() {
const [otpStep, setOtpStep] = useState(false);
const [otp, setOtp] = useState("");
const [loading, setLoading] = useState(false);
+ const [otpRequired, setOtpRequired] = useState(false);
+ const [otpVerified, setOtpVerified] = useState(false);
+ const [buttonLabel, setButtonLabel] = useState("Submit");
+ const [mobile, setMobile] = useState("");
+
+ async function handleSendOtp(mobile?: string) {
+ console.log("hi mobile", mobile);
+ if (!mobile) {
+ notifications.show({
+ title: 'Error',
+ message: 'Mobile number not found.Contact to administrator',
+ color: 'red',
+ });
+ return false;
+ }
+ try {
+ console.log(CIF);
+ await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: mobile });
+ return true;
+ }
+ catch (err: any) {
+ notifications.show({
+ title: 'Error',
+ message: `${err.error}.SMS vendor facing some issue.Please try again later.` || 'Send OTP failed.Please try again later.',
+ color: 'red',
+ });
+ return false;
+ }
+ }
+
+ async function handleVerifyOtp(mobile?: string) {
+ try {
+ if (mobile) {
+ await verifyLoginOtp(otp, mobile);
+ return true;
+ }
+ } catch {
+ return false;
+ }
+ }
useEffect(() => {
const loadCaptcha = async () => {
@@ -61,94 +102,329 @@ export default function Login() {
setInputCaptcha("");
};
+ // async function handleLogin(e: React.FormEvent) {
+ // e.preventDefault();
+
+ // if (!otpRequired && !otpVerified) {
+ // const onlyDigit = /^\d{11}$/;
+ // if (!onlyDigit.test(CIF)) {
+ // // setError('Input value must be 11 digit');
+ // notifications.show({
+ // withBorder: true,
+ // color: "red",
+ // title: "Invalid UserId",
+ // message: "UserID must be 11 digit",
+ // autoClose: 5000,
+ // });
+ // return;
+ // }
+ // if (!inputCaptcha) {
+ // notifications.show({
+ // withBorder: true,
+ // color: "red",
+ // title: "Invalid Captcha",
+ // message: "Please fill the Captcha filed",
+ // autoClose: 5000,
+ // });
+ // return;
+ // }
+ // if (inputCaptcha !== captcha) {
+ // notifications.show({
+ // withBorder: true,
+ // color: "red",
+ // title: "Captcha Error",
+ // message: "Please enter the correct captcha",
+ // autoClose: 5000,
+ // });
+ // regenerateCaptcha();
+ // return;
+ // }
+ // if (!CIF || !psw) {
+ // notifications.show({
+ // withBorder: true,
+ // color: "red",
+ // title: "Invalid Input",
+ // message: "Please fill UserId and Password",
+ // autoClose: 5000,
+ // });
+ // return;
+ // }
+ // }
+ // try {
+ // if (!otpRequired || otpVerified) {
+ // const response = await fetch('api/auth/login', {
+ // method: 'POST',
+ // headers: {
+ // 'Content-Type': 'application/json',
+ // 'X-Login-Type': 'IB',
+ // },
+ // body: JSON.stringify({
+ // customerNo: CIF,
+ // password: psw,
+ // otp: otp
+ // }),
+ // });
+ // const data = await response.json();
+ // console.log(data);
+ // setIsLogging(true);
+
+ // if (data.status === "OTP_REQUIRED" && response.status === 202) {
+ // console.log(data.mobile);
+ // setMobile(data.mobile);
+ // setOtpRequired(true);
+ // setButtonLabel("Verify OTP");
+
+ // const otpSent = await handleSendOtp(data.mobile); // auto-send
+ // if (otpSent) {
+ // notifications.show({
+ // color: "orange",
+ // title: "OTP Required",
+ // message: "OTP sent to your registered mobile number",
+ // });
+ // }
+ // return;
+ // }
+ // if (data.error === "MIGRATED_USER_HAS_NO_PASSWORD") {
+ // //console.log("Migration issue detected → opening modal");
+ // setOpened(true);
+ // return;
+ // }
+ // if (!response.ok) {
+ // notifications.show({
+ // withBorder: true,
+ // color: "red",
+ // title: "Error",
+ // message: data?.error || "Internal Server Error",
+ // autoClose: 5000,
+ // });
+ // regenerateCaptcha();
+ // localStorage.removeItem("access_token");
+ // localStorage.clear();
+ // sessionStorage.clear();
+ // return;
+
+ // }
+ // // setIsLogging(true);
+ // if (response.ok) {
+ // // console.log(data);
+ // setOtp("");
+ // const token = data.token;
+ // localStorage.setItem("access_token", token);
+ // localStorage.setItem("pswExpiryDate", data.loginPswExpiry);
+ // // console.log("Expiry Date:",(dayjs(data.loginPswExpiry)).diff(dayjs(), "day"));
+
+ // // Password Expiry Logic
+ // if (data.loginPswExpiry && (dayjs(data.loginPswExpiry)).diff(dayjs(), "day") < 0) {
+ // notifications.show({
+ // withBorder: true,
+ // color: "orange",
+ // title: "Password Expired",
+ // message: "Your password has expired, please set a new one.",
+ // autoClose: 4000,
+ // });
+ // router.push("/ChangePassword");
+ // return;
+ // }
+
+ // if (data.FirstTimeLogin === true) {
+ // router.push("/SetPassword")
+ // }
+ // else {
+ // router.push("/home");
+ // }
+
+ // }
+ // else {
+ // regenerateCaptcha();
+ // setIsLogging(false);
+ // notifications.show({
+ // withBorder: true,
+ // color: "red",
+ // title: "Wrong User Id or Password",
+ // message: "Wrong User Id or Password",
+ // autoClose: 5000,
+ // });
+ // }
+ // }
+ // if (otpRequired && !otpVerified) {
+ // if (!otp) {
+ // notifications.show({
+ // color: "red",
+ // title: "Invalid OTP",
+ // message: "Please enter OTP before verifying",
+ // });
+ // setIsLogging(false);
+ // return;
+ // }
+ // console.log("hi verify mob", mobile);
+ // const verified = await handleVerifyOtp(mobile);
+ // if (!verified) {
+ // notifications.show({
+ // title: "Invalid OTP",
+ // message: "The OTP entered does not match",
+ // color: "red",
+ // });
+ // return;
+ // }
+
+ // notifications.show({
+ // color: "green",
+ // title: "OTP Verified",
+ // message: "Please click Login to continue",
+ // });
+ // setOtpVerified(true);
+ // setButtonLabel("Login");
+ // setIsLogging(false);
+ // return;
+ // }
+ // }
+ // catch (error: any) {
+ // notifications.show({
+ // withBorder: true,
+ // color: "red",
+ // title: "Error",
+ // message: "Internal Server Error,Please try again Later",
+ // autoClose: 5000,
+ // });
+ // return;
+ // }
+ // finally {
+ // setIsLogging(false);
+ // }
+ // }
+
+
+
+ // For migration User
async function handleLogin(e: React.FormEvent) {
e.preventDefault();
- const onlyDigit = /^\d{11}$/;
- if (!onlyDigit.test(CIF)) {
- // setError('Input value must be 11 digit');
- notifications.show({
- withBorder: true,
- color: "red",
- title: "Invalid UserId",
- message: "UserID must be 11 digit",
- autoClose: 5000,
- });
- return;
- }
- if (!inputCaptcha) {
- notifications.show({
- withBorder: true,
- color: "red",
- title: "Invalid Captcha",
- message: "Please fill the Captcha filed",
- autoClose: 5000,
- });
- return;
- }
- if (inputCaptcha !== captcha) {
- notifications.show({
- withBorder: true,
- color: "red",
- title: "Captcha Error",
- message: "Please enter the correct captcha",
- autoClose: 5000,
- });
- regenerateCaptcha();
- return;
- }
- if (!CIF || !psw) {
- notifications.show({
- withBorder: true,
- color: "red",
- title: "Invalid Input",
- message: "Please fill UserId and Password",
- autoClose: 5000,
- });
- return;
- }
- try {
- const response = await fetch('api/auth/login', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- customerNo: CIF,
- password: psw,
- }),
- });
- const data = await response.json();
- // console.log(data);
- if (data.error === "MIGRATED_USER_HAS_NO_PASSWORD") {
- //console.log("Migration issue detected → opening modal");
- setOpened(true);
- return;
- }
- if (!response.ok) {
- notifications.show({
- withBorder: true,
- color: "red",
- title: "Error",
- message: data?.error || "Internal Server Error",
- autoClose: 5000,
- });
- regenerateCaptcha();
- localStorage.removeItem("access_token");
- localStorage.clear();
- sessionStorage.clear();
- return;
+ setIsLogging(true); // show loading & disable inputs
+ try {
+ // --- Validation (before any API call) ---
+ if (!otpRequired && !otpVerified) {
+ const onlyDigit = /^\d{11}$/;
+
+ if (!onlyDigit.test(CIF)) {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Invalid UserId",
+ message: "UserID must be 11 digit",
+ autoClose: 5000,
+ });
+ setIsLogging(false);
+ return;
+ }
+
+ if (!inputCaptcha) {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Invalid Captcha",
+ message: "Please fill the Captcha field",
+ autoClose: 5000,
+ });
+ setIsLogging(false);
+ return;
+ }
+
+ if (inputCaptcha !== captcha) {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Captcha Error",
+ message: "Please enter the correct captcha",
+ autoClose: 5000,
+ });
+ regenerateCaptcha();
+ setIsLogging(false);
+ return;
+ }
+
+ if (!CIF || !psw) {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Invalid Input",
+ message: "Please fill UserId and Password",
+ autoClose: 5000,
+ });
+ setIsLogging(false);
+ return;
+ }
}
- setIsLogging(true);
- if (response.ok) {
- // console.log(data);
+
+ // --- LOGIN API FLOW ---
+ if (!otpRequired || otpVerified) {
+ const response = await fetch("api/auth/login", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-Login-Type": "IB",
+ },
+ body: JSON.stringify({
+ customerNo: CIF,
+ password: psw,
+ otp: otp,
+ }),
+ });
+
+ const data = await response.json();
+ console.log(data);
+
+ // 1️⃣ OTP Required
+ if (data.status === "OTP_REQUIRED" && response.status === 202) {
+ setMobile(data.mobile);
+ setOtpRequired(true);
+ setButtonLabel("Verify OTP");
+
+ const otpSent = await handleSendOtp(data.mobile);
+ if (otpSent) {
+ notifications.show({
+ color: "orange",
+ title: "OTP Required",
+ message: "OTP sent to your registered mobile number",
+ });
+ }
+ setIsLogging(false);
+ return;
+ }
+
+ // 2️⃣ Migrated user (no password)
+ if (data.error === "MIGRATED_USER_HAS_NO_PASSWORD") {
+ setOpened(true);
+ setIsLogging(false);
+ return;
+ }
+
+ // 3️⃣ Invalid login
+ if (!response.ok) {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Error",
+ message: data?.error || "Internal Server Error",
+ autoClose: 5000,
+ });
+ regenerateCaptcha();
+ localStorage.removeItem("access_token");
+ localStorage.clear();
+ sessionStorage.clear();
+ setIsLogging(false);
+ return;
+ }
+
+ // 4️⃣ Successful login
+ setOtp("");
const token = data.token;
localStorage.setItem("access_token", token);
localStorage.setItem("pswExpiryDate", data.loginPswExpiry);
- // console.log("Expiry Date:",(dayjs(data.loginPswExpiry)).diff(dayjs(), "day"));
- // Password Expiry Logic todo
- if (data.loginPswExpiry && (dayjs(data.loginPswExpiry)).diff(dayjs(), "day") < 0) {
+ if (
+ data.loginPswExpiry &&
+ dayjs(data.loginPswExpiry).diff(dayjs(), "day") < 0
+ ) {
notifications.show({
withBorder: true,
color: "orange",
@@ -161,39 +437,62 @@ export default function Login() {
}
if (data.FirstTimeLogin === true) {
- router.push("/SetPassword")
- }
- else {
+ router.push("/SetPassword");
+ } else {
router.push("/home");
}
+ }
+
+ // --- OTP Verification Flow ---
+ if (otpRequired && !otpVerified) {
+ if (!otp) {
+ notifications.show({
+ color: "red",
+ title: "Invalid OTP",
+ message: "Please enter OTP before verifying",
+ });
+ setIsLogging(false);
+ return;
+ }
+
+ const verified = await handleVerifyOtp(mobile);
+ if (!verified) {
+ notifications.show({
+ title: "Invalid OTP",
+ message: "The OTP entered does not match",
+ color: "red",
+ });
+ setIsLogging(false);
+ return;
+ }
- }
- else {
- regenerateCaptcha();
- setIsLogging(false);
notifications.show({
- withBorder: true,
- color: "red",
- title: "Wrong User Id or Password",
- message: "Wrong User Id or Password",
- autoClose: 5000,
+ color: "green",
+ title: "OTP Verified",
+ message: "Please click Login to continue",
});
+
+ setOtpVerified(true);
+ setButtonLabel("Login");
+ setIsLogging(false);
+ return;
}
- }
- catch (error: any) {
+ } catch (error: any) {
notifications.show({
withBorder: true,
color: "red",
title: "Error",
- message: "Internal Server Error,Please try again Later",
+ message: "Internal Server Error, Please try again later",
autoClose: 5000,
});
- return;
+ } finally {
+ // Ensure we always stop loader if still active
+ setIsLogging(false);
}
}
- // For migration User
- const sendOtp = async () => {
+
+ const sendMigrationOtp = async () => {
try {
setLoading(true);
const res = await fetch(`/api/otp/send/set-password?customerNo=${CIF}`, {
@@ -220,7 +519,7 @@ export default function Login() {
};
// For migration User
- const verifyOtp = async () => {
+ const verifyMigrationOtp = async () => {
if (!otp) {
notifications.show({
color: "red",
@@ -294,7 +593,7 @@ export default function Login() {
Cancel
{/* Call the API for send otp */}
-
-
+
Verify OTP
@@ -415,7 +714,7 @@ export default function Login() {
/>
-
+