@@ -625,7 +635,7 @@ export default function SendToBeneficiaryOthers() {
)
)}
diff --git a/src/app/(main)/home/page.tsx b/src/app/(main)/home/page.tsx
index 4f58504..0ea1c1b 100644
--- a/src/app/(main)/home/page.tsx
+++ b/src/app/(main)/home/page.tsx
@@ -71,6 +71,7 @@ export default function Home() {
const data = await response.json();
if (response.ok && Array.isArray(data)) {
SetAccountData(data);
+ sessionStorage.setItem("accountData", JSON.stringify(data));
if (data.length > 0) {
const firstDeposit = data.find(acc => acc.stAccountType !== "LN");
const firstLoan = data.find(acc => acc.stAccountType === "LN");
diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx
index 83f3e14..5c5e6c3 100644
--- a/src/app/(main)/layout.tsx
+++ b/src/app/(main)/layout.tsx
@@ -1,6 +1,6 @@
"use client";
import React, { useEffect, useState } from 'react';
-import { Box, Button, Divider, Group, Image, Popover, Stack, Text, Title } from '@mantine/core';
+import { Box, Button, Divider, Group, Image, Modal, Popover, Stack, Text, Title } from '@mantine/core';
import { IconBook, IconCurrencyRupee, IconHome, IconLogout, IconPhoneFilled, IconSettings } from '@tabler/icons-react';
import Link from 'next/link';
import { useRouter, usePathname } from "next/navigation";
@@ -17,6 +17,8 @@ export default function RootLayout({ children }: { children: React.ReactNode })
const [userLastLoginDetails, setUserLastLoginDetails] = useState(null);
const [custname, setCustname] = useState
(null);
const isMobile = useMediaQuery("(max-width: 768px)");
+ const [sessionModal, setSessionModal] = useState(false);
+ const [countdown, setCountdown] = useState(30); // 30 sec countdown before auto logout
const [opened, { open, close }] = useDisclosure(false);
@@ -80,6 +82,8 @@ export default function RootLayout({ children }: { children: React.ReactNode })
});
}
}
+
+ // When reload and click on back then logout
useEffect(() => {
// Push fake history state to trap navigation
window.history.pushState(null, "", window.location.href);
@@ -155,6 +159,58 @@ export default function RootLayout({ children }: { children: React.ReactNode })
fetchLoginTime();
}, []);
+ // LOGOUT AFTER 5 MINUTES OF INACTIVITY OR TAB SWITCH
+ useEffect(() => {
+ const INACTIVITY_LIMIT = 5 * 60 * 1000; // 5 minutes
+ let inactiveSince: number | null = null;
+ let countdownTimer: NodeJS.Timeout;
+
+ const startCountdown = () => {
+ setSessionModal(true);
+ setCountdown(30); // start from 30 seconds
+
+ countdownTimer = setInterval(() => {
+ setCountdown((prev) => {
+ if (prev <= 1) {
+ clearInterval(countdownTimer);
+ doLogout(); // auto logout after countdown
+ return 0;
+ }
+ return prev - 1;
+ });
+ }, 1000);
+ };
+
+ const handleVisibilityChange = () => {
+ if (document.hidden) {
+ // User switched tab → mark inactive time
+ inactiveSince = Date.now();
+ } else {
+ // User returned to tab
+ if (inactiveSince && Date.now() - inactiveSince >= INACTIVITY_LIMIT) {
+ // Inactive for ≥ 5 min → show modal
+ startCountdown();
+ }
+ inactiveSince = null; // reset inactiveSince
+ }
+ };
+
+ const handleUserActivity = () => {
+ // Reset inactivity timestamp if user interacts
+ inactiveSince = null;
+ };
+
+ const activityEvents = ["mousemove", "keydown", "click", "scroll", "touchstart"];
+ activityEvents.forEach((event) => window.addEventListener(event, handleUserActivity));
+ document.addEventListener("visibilitychange", handleVisibilityChange);
+
+ return () => {
+ activityEvents.forEach((event) => window.removeEventListener(event, handleUserActivity));
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
+ clearInterval(countdownTimer);
+ };
+ }, []);
+
const navItems = [
{ href: "/home", label: "Home", icon: IconHome },
{ href: "/accounts", label: "Accounts", icon: IconBook },
@@ -274,6 +330,32 @@ export default function RootLayout({ children }: { children: React.ReactNode })
>
{children}
+ {/* this model for session logout */}
+ setSessionModal(false)}
+ withCloseButton={false}
+ centered
+ closeOnClickOutside={false} // <--- prevents clicking outside to close
+ closeOnEscape={false} // <--- prevents ESC key
+ title="Session Timeout Warning"
+ >
+
+
+ You have been inactive for a while.
+
+ You’ll be logged out automatically in {countdown} seconds.
+
+
+ {/* */}
+
+
+
+
diff --git a/src/app/(main)/settings/change_login_password/page.tsx b/src/app/(main)/settings/change_login_password/page.tsx
index 7d85988..a3c460d 100644
--- a/src/app/(main)/settings/change_login_password/page.tsx
+++ b/src/app/(main)/settings/change_login_password/page.tsx
@@ -160,7 +160,7 @@ export default function ChangePassword() {
return;
}
const result = await response.json();
- console.log(result);
+ // console.log(result);
if (!response.ok) {
notifications.show({
title: "Failed",
diff --git a/src/app/(main)/settings/change_txn_password/page.tsx b/src/app/(main)/settings/change_txn_password/page.tsx
index 8d794bf..aff3c0d 100644
--- a/src/app/(main)/settings/change_txn_password/page.tsx
+++ b/src/app/(main)/settings/change_txn_password/page.tsx
@@ -160,7 +160,7 @@ export default function ChangePassword() {
return;
}
const result = await response.json();
- console.log(result);
+ // console.log(result);
if (!response.ok) {
notifications.show({
title: "Failed",
diff --git a/src/app/ChangePassword/page.tsx b/src/app/ChangePassword/page.tsx
index 0c55906..9077efa 100644
--- a/src/app/ChangePassword/page.tsx
+++ b/src/app/ChangePassword/page.tsx
@@ -184,6 +184,7 @@ export default function ChangePassword() {
color: "red",
autoClose: false,
});
+ resetForm();
} else {
notifications.show({
title: "Success",
@@ -199,6 +200,7 @@ export default function ChangePassword() {
message: err.message || "Server error, please try again later",
color: "red",
});
+ resetForm();
}
}
};
diff --git a/src/app/ForgetPassword/page.tsx b/src/app/ForgetPassword/page.tsx
index 9e58864..a77dbab 100644
--- a/src/app/ForgetPassword/page.tsx
+++ b/src/app/ForgetPassword/page.tsx
@@ -98,7 +98,7 @@ export default function ForgetLoginPwd() {
});
const data = await response.json();
if (response.ok) {
- console.log(data);
+ // console.log(data);
notifications.show({
withBorder: true,
color: "green",
diff --git a/src/app/SetPassword/page.tsx b/src/app/SetPassword/page.tsx
index 07da2ff..b004612 100644
--- a/src/app/SetPassword/page.tsx
+++ b/src/app/SetPassword/page.tsx
@@ -136,7 +136,7 @@ export default function SetLoginPwd() {
});
const data = await response.json();
if (response.ok) {
- console.log(data);
+ // console.log(data);
notifications.show({
withBorder: true,
color: "green",
diff --git a/src/app/SetTxn/page.tsx b/src/app/SetTxn/page.tsx
index 6d71c89..6a741fb 100644
--- a/src/app/SetTxn/page.tsx
+++ b/src/app/SetTxn/page.tsx
@@ -160,7 +160,7 @@ export default function SetTransactionPwd() {
});
const data = await response.json();
if (response.ok) {
- console.log(data);
+ // console.log(data);
notifications.show({
withBorder: true,
color: "green",
diff --git a/src/app/_util/otp.ts b/src/app/_util/otp.ts
new file mode 100644
index 0000000..414438b
--- /dev/null
+++ b/src/app/_util/otp.ts
@@ -0,0 +1,60 @@
+import { notifications } from '@mantine/notifications';
+import axios from 'axios';
+
+interface SendOtpPayload {
+ mobileNumber?: string;
+ type: string;
+ amount?: number;
+ beneficiary?: string;
+ ifsc?: string;
+ acctFrom?: string;
+ acctTo?: string;
+ ref?: string;
+ date?: string;
+ userOtp?: string;
+}
+
+function getStoredMobileNumber(): string | null {
+ // const mobileNumber = localStorage.getItem('remitter_mobile_no');
+ const mobileNumber= "7890544527";
+ if (!mobileNumber) {
+ notifications.show({
+ title: 'Missing Mobile Number',
+ message: 'Mobile number not found. Please re-login or update your profile.',
+ color: 'red',
+ });
+ return null;
+ }
+ return mobileNumber;
+}
+
+export async function sendOtp(payload: SendOtpPayload) {
+ try {
+ const mobileNumber = payload.mobileNumber || getStoredMobileNumber();
+ const response = await axios.post(
+ 'http://localhost:8080/api/otp/send',
+ { ...payload, mobileNumber },
+ { headers: { 'Content-Type': 'application/json' } }
+ );
+ return response.data;
+ } catch (error: any) {
+ console.error('Error sending OTP:', error.response?.data || error.message);
+ throw error.response?.data || error;
+ }
+}
+
+
+export async function verifyOtp(otp: 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;
+ }
+}
diff --git a/src/app/eMandate/mandate_page/page.tsx b/src/app/eMandate/mandate_page/page.tsx
index c2a5ee9..ec30b2c 100644
--- a/src/app/eMandate/mandate_page/page.tsx
+++ b/src/app/eMandate/mandate_page/page.tsx
@@ -188,7 +188,7 @@ export default function MandatePage() {
}),
});
const data = await response.json();
- console.log(data)
+ // console.log(data)
if (!response.ok) throw new Error("Failed to send OTP");
notifications.show({
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index 1bf4976..9b8fc8b 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -119,7 +119,7 @@ export default function Login() {
}),
});
const data = await response.json();
- console.log(data);
+ // console.log(data);
if (data.error === "MIGRATED_USER_HAS_NO_PASSWORD") {
//console.log("Migration issue detected → opening modal");
setOpened(true);
@@ -142,10 +142,11 @@ export default function Login() {
}
setIsLogging(true);
if (response.ok) {
- console.log(data);
+ // console.log(data);
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) {
@@ -156,14 +157,10 @@ export default function Login() {
message: "Your password has expired, please set a new one.",
autoClose: 4000,
});
-
-
-
router.push("/ChangePassword");
return;
}
-
if (data.FirstTimeLogin === true) {
router.push("/SetPassword")
}