diff --git a/src/app/eMandate/login/page.tsx b/src/app/eMandate/login/page.tsx
index f9e156d..a835ef6 100644
--- a/src/app/eMandate/login/page.tsx
+++ b/src/app/eMandate/login/page.tsx
@@ -88,6 +88,7 @@ export default function Login() {
method: 'POST',
headers: {
'Content-Type': 'application/json',
+ 'X-Login-Type': 'emandate',
},
body: JSON.stringify({
customerNo: CIF,
@@ -103,33 +104,34 @@ export default function Login() {
message: data?.error || "Internal Server Error",
autoClose: 5000,
});
- localStorage.removeItem("access_token");
+ regenerateCaptcha()
+ localStorage.removeItem("mandate_token");
localStorage.clear();
sessionStorage.clear();
return;
-
}
setIsLogging(true);
if (response.ok) {
console.log(data);
const token = data.token;
- localStorage.setItem("emandate_token", token);
+ localStorage.setItem("mandate_token", token);
// localStorage.setItem("pswExpiryDate", data.loginPswExpiry);
if (data.FirstTimeLogin === true) {
notifications.show({
withBorder: true,
color: "red",
title: "Error",
- message: "Please set your credential into Internet Banking before login.",
+ message: "Please go to Internet Banking, set your credentials, and then try logging in here again.",
autoClose: 5000,
});
}
else {
- router.push("/mandate_page");
+ router.push("/eMandate/mandate_page");
}
}
else {
+ regenerateCaptcha();
setIsLogging(false);
notifications.show({
withBorder: true,
diff --git a/src/app/eMandate/mandate_page/page.tsx b/src/app/eMandate/mandate_page/page.tsx
index 4b60ee9..88a1450 100644
--- a/src/app/eMandate/mandate_page/page.tsx
+++ b/src/app/eMandate/mandate_page/page.tsx
@@ -1,5 +1,5 @@
"use client";
-import React, { useState } from "react";
+import React, { useEffect, useState } from "react";
import {
Text,
Title,
@@ -13,12 +13,16 @@ import {
Container,
ActionIcon,
Divider,
+ Modal,
+ TextInput,
} from "@mantine/core";
import { Providers } from "@/app/providers";
import { useRouter } from "next/navigation";
import NextImage from "next/image";
import logo from "@/app/image/logo1.jpg";
-import { IconLogout } from "@tabler/icons-react";
+import { IconLogout, IconX } from "@tabler/icons-react";
+import { notifications } from "@mantine/notifications";
+import { useMediaQuery } from "@mantine/hooks";
type Mandate = {
id: string;
@@ -33,15 +37,29 @@ type Mandate = {
const MandateCard = ({
mandate,
- onAccept,
- onReject,
+ onAction,
}: {
mandate: Mandate;
- onAccept: (id: string) => void;
- onReject: (id: string) => void;
+ onAction: (id: string, action: "accept" | "reject") => void;
}) => {
const [agreed, setAgreed] = useState(false);
+ const handleClick = (action: "accept" | "reject") => {
+ if (!agreed) {
+ notifications.show({
+ withBorder: true,
+ icon: ,
+ color: "red",
+ title: "Error",
+ message:
+ "Please agree to the debit of mandate processing charges first.",
+ autoClose: 4000,
+ });
+ return;
+ }
+ onAction(mandate.id, action);
+ };
+
return (
{mandate.category}
@@ -62,19 +80,10 @@ const MandateCard = ({
/>
-
@@ -84,6 +93,64 @@ const MandateCard = ({
export default function MandatePage() {
const router = useRouter();
+ const [authorized, setAuthorized] = useState(null);
+ const [custname, setCustname] = useState(null);
+ const isMobile = useMediaQuery("(max-width: 768px)");
+
+ // OTP Modal states
+ const [otpModalOpen, setOtpModalOpen] = useState(false);
+ const [otp, setOtp] = useState("");
+ const [pendingAction, setPendingAction] = useState<{ id: string; action: "accept" | "reject" } | null>(null);
+
+ useEffect(() => {
+ const token = localStorage.getItem("mandate_token");
+ if (!token) {
+ setAuthorized(false);
+ router.push("/eMandate/login");
+ } else {
+ setAuthorized(true);
+ handleFetchUserName();
+ }
+ }, []);
+
+ const handleLogout = () => {
+ localStorage.removeItem("mandate_token");
+ localStorage.removeItem("user_name");
+ localStorage.removeItem("userMobNo");
+ router.push("/eMandate/login");
+ };
+
+ const handleFetchUserName = async () => {
+ try {
+ const token = localStorage.getItem("mandate_token");
+ const response = await fetch("/api/customer", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ });
+ if (!response.ok) throw new Error();
+ const data = await response.json();
+ if (Array.isArray(data) && data.length > 0) {
+ const name = data[0].custname;
+ const mobileNumber = data[0].mobileno;
+ localStorage.setItem("user_name", name);
+ localStorage.setItem("userMobNo", mobileNumber);
+ setCustname(name);
+ }
+ } catch {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Please try again later",
+ message: "Unable to Fetch, Please try again later",
+ autoClose: 5000,
+ });
+ }
+ };
+
+ // Dummy mandates
const [mandates] = useState([
{
id: "1",
@@ -105,21 +172,95 @@ export default function MandatePage() {
firstCollection: "2025-10-01",
finalCollection: "2030-10-01",
},
-
]);
- const handleAccept = (id: string) => {
- alert(`Accepted mandate ${id}`);
+ // STEP 1: When Accept/Reject pressed → call send OTP API
+ const handleMandateAction = async (id: string, action: "accept" | "reject") => {
+ try {
+ const response = await fetch("/api/otp/send", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ mobileNumber: '7890544527',
+ type: 'EMandate'
+ }),
+ });
+ const data = await response.json();
+ console.log(data)
+ if (!response.ok) throw new Error("Failed to send OTP");
+
+ notifications.show({
+ withBorder: true,
+ color: "green",
+ title: "OTP Sent",
+ message: "An OTP has been sent to your registered mobile number.",
+ autoClose: 4000,
+ });
+
+ setPendingAction({ id, action });
+ setOtp("");
+ setOtpModalOpen(true);
+ } catch (err) {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Error",
+ message: "Failed to send OTP. Please try again.",
+ autoClose: 5000,
+ });
+ }
};
- const handleReject = (id: string) => {
- alert(`Rejected mandate ${id}`);
- };
- const handleLogout = () => {
- localStorage.removeItem("access_token");
- router.push("/eMandate/login"); // redirect to login page
+ // STEP 2: Verify OTP and complete action
+ const handleOtpSubmit = async () => {
+ // if (!otp) {
+ // notifications.show({
+ // withBorder: true,
+ // color: "red",
+ // title: "Invalid Input",
+ // message: "Please enter OTP before proceed",
+ // autoClose: 5000,
+ // });
+ // }
+ if (!pendingAction) return;
+ try {
+ const response = await fetch(`/api/otp/verify?mobileNumber=${7890544527}`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ otp: otp,
+ }),
+ });
+
+ if (!response.ok) throw new Error("Invalid OTP");
+
+ notifications.show({
+ withBorder: true,
+ color: "green",
+ title: "Success",
+ message: `Mandate ${pendingAction.action}ed successfully!`,
+ autoClose: 4000,
+ });
+
+ setOtpModalOpen(false);
+ setPendingAction(null);
+ } catch {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Error",
+ message: "Invalid OTP. Please try again.",
+ autoClose: 4000,
+ });
+ }
};
+ if (!authorized) return null;
+
return (
-
+
-
- THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
-
+ />
+ {!isMobile && (
+
+ THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
+
+ )}
- {/* Logout Icon */}
-
-
-
+ {isMobile ? (
+
+
+
+ ) : (
+ LOGOUT}
+ rightSection={}
+ />
+ )}
{/* WELCOME BAR */}
- Welcome, John Doe
+ Welcome, {custname ?? ""}
- Login Time: 9/24/2025, 12:52:05 PM
+ Last logged in at {new Date().toLocaleString()}
KCCB E-Mandate
-
+
{/* CONTENT */}
{mandates.map((mandate) => (
-
+
))}
@@ -249,6 +398,31 @@ export default function MandatePage() {
© 2025 The Kangra Central Co-Operative Bank
+
+ {/* OTP MODAL */}
+
setOtpModalOpen(false)} title="Enter OTP" centered>
+ An OTP has been sent to your registered mobile number.
+ {
+ const input = e.currentTarget.value.replace(/\D/g, "");
+ if (input.length <= 6) setOtp(input);
+ }}
+ />
+
+ if you did not received the OTP in SMS,you can click click here to resend the SMS
+
+ setOtpModalOpen(false)}>
+ Cancel
+
+
+ Submit
+
+
+
);
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index 7eee408..a762ba1 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -129,6 +129,7 @@ export default function Login() {
message: data?.error || "Internal Server Error",
autoClose: 5000,
});
+ regenerateCaptcha();
localStorage.removeItem("access_token");
localStorage.clear();
sessionStorage.clear();
@@ -150,6 +151,7 @@ export default function Login() {
}
else {
+ regenerateCaptcha();
setIsLogging(false);
notifications.show({
withBorder: true,
@@ -218,7 +220,7 @@ export default function Login() {
});
const data = await res.json();
- console.log(data)
+ // console.log(data)
if (!res.ok) {
notifications.show({
color: "red",