506 lines
20 KiB
TypeScript
506 lines
20 KiB
TypeScript
"use client";
|
|
import React, { useEffect, useState, useRef } from "react";
|
|
import {
|
|
Text,
|
|
Title,
|
|
Box,
|
|
Image,
|
|
Button,
|
|
Group,
|
|
Container,
|
|
ActionIcon,
|
|
Divider,
|
|
PinInput,
|
|
Paper,
|
|
Stack,
|
|
Center,
|
|
Loader,
|
|
} 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, IconShieldCheck, IconRefresh } from "@tabler/icons-react";
|
|
import { useMediaQuery } from "@mantine/hooks";
|
|
import { sendOtp, verifyOtp } from "../otpUtils";
|
|
import { fetchUserDetails } from "../authUtils";
|
|
|
|
export default function VerifyOtpPage() {
|
|
const router = useRouter();
|
|
const [authorized, setAuthorized] = useState<boolean | null>(null);
|
|
const [custname, setCustname] = useState<string | null>(null);
|
|
const [otp, setOtp] = useState("");
|
|
const [isVerifying, setIsVerifying] = useState(false);
|
|
const [isResending, setIsResending] = useState(false);
|
|
const [timer, setTimer] = useState(60);
|
|
const [canResend, setCanResend] = useState(false);
|
|
const isMobile = useMediaQuery("(max-width: 768px)");
|
|
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
|
const otpSentRef = useRef(false);
|
|
|
|
//On First Load: Check Token → Fetch User → Send OTP
|
|
useEffect(() => {
|
|
const token = localStorage.getItem("mandate_token");
|
|
if (!token) {
|
|
handleLogout();
|
|
setAuthorized(false);
|
|
return;
|
|
}
|
|
|
|
setAuthorized(true);
|
|
|
|
// Get User Name + Mobile
|
|
fetchUserDetails().then((res) => {
|
|
if (res) {
|
|
setCustname(res.name);
|
|
if (!otpSentRef.current) {
|
|
sendOtp(res.mobile);
|
|
// sendOtp("7890544527");
|
|
otpSentRef.current = true; // Prevent second OTP
|
|
}
|
|
}
|
|
});
|
|
|
|
// Prevent back button
|
|
const handlePopState = () => {
|
|
handleLogout();
|
|
};
|
|
window.addEventListener("popstate", handlePopState);
|
|
window.history.pushState(null, "", window.location.href);
|
|
|
|
return () => {
|
|
window.removeEventListener("popstate", handlePopState);
|
|
if (timerRef.current) clearInterval(timerRef.current);
|
|
};
|
|
}, []);
|
|
|
|
|
|
// Timer Countdown
|
|
useEffect(() => {
|
|
timerRef.current = setInterval(() => {
|
|
setTimer((prev) => {
|
|
if (prev === 1) {
|
|
setCanResend(true);
|
|
clearInterval(timerRef.current!);
|
|
}
|
|
return prev - 1;
|
|
});
|
|
}, 1000);
|
|
|
|
return () => clearInterval(timerRef.current!);
|
|
}, []);
|
|
|
|
|
|
// Logout
|
|
const handleLogout = () => {
|
|
localStorage.clear();
|
|
router.push("/eMandate/logout");
|
|
};
|
|
|
|
//Resend OTP
|
|
const handleResendOtp = async () => {
|
|
setIsResending(true);
|
|
|
|
const mobile = localStorage.getItem("userMobNo");
|
|
// const mobile = "7890544527";
|
|
if (!mobile) return;
|
|
|
|
await sendOtp(mobile);
|
|
setTimer(60);
|
|
setCanResend(false);
|
|
setOtp("");
|
|
|
|
setIsResending(false);
|
|
};
|
|
|
|
|
|
// Verify OTP using verifyOtp() Utility
|
|
|
|
// const handleVerifyOtp = async () => {
|
|
// const mobile = localStorage.getItem("userMobNo");
|
|
// // const mobile = "7890544527";
|
|
// if (!mobile || otp.length !== 6) return;
|
|
|
|
// setIsVerifying(true);
|
|
|
|
// const success = await verifyOtp(otp, mobile);
|
|
|
|
// // if (success) {
|
|
// // // const encoded_data = localStorage.getItem("Validate_data");
|
|
// // // const res = await fetch(
|
|
// // // `https://apiemandate.kccb.in:9035/EMandate/auth-cbs-resp?data=${encoded_data}`,
|
|
// // // {
|
|
// // // method: "POST",
|
|
// // // headers: {
|
|
// // // "Content-Type": "application/json",
|
|
// // // },
|
|
// // // }
|
|
// // // );
|
|
// // const formData = new FormData();
|
|
// // const encoded_data = localStorage.getItem("Validate_data");
|
|
// // formData.append("data", encoded_data);
|
|
|
|
// // const res = await fetch(
|
|
// // "https://apiemandate.kccb.in:9035/EMandate/auth-cbs-resp",
|
|
// // {
|
|
// // method: "POST",
|
|
// // body: formData,
|
|
// // }
|
|
// // );
|
|
|
|
// // const result = await res.json();
|
|
// // console.log(result);
|
|
// // if (!res.ok) {
|
|
// // throw new Error("CBS response API failed");
|
|
// // }
|
|
// // if (res.ok) {
|
|
// // // navigate only after successful API hit
|
|
// // setTimeout(() => {
|
|
// // router.push("/eMandate/mandate_page");
|
|
// // }, 1500);
|
|
// // }
|
|
// // }
|
|
// if (success) {
|
|
// try {
|
|
// const encoded_data = localStorage.getItem("Validate_data");
|
|
// if (!encoded_data) {
|
|
// console.error("Validate_data not found in localStorage");
|
|
// return;
|
|
// }
|
|
// const formData = new FormData();
|
|
// formData.append("data", encoded_data);
|
|
|
|
// const res = await fetch(
|
|
// "https://apiemandate.kccb.in:9035/EMandate/auth-cbs-resp",
|
|
// {
|
|
// method: "POST",
|
|
// body: formData,
|
|
// }
|
|
// );
|
|
|
|
// if (!res.ok) {
|
|
// throw new Error(`CBS response API failed: ${res.status}`);
|
|
// }
|
|
// const contentType = res.headers.get("content-type");
|
|
// const result =
|
|
// contentType && contentType.includes("application/json")
|
|
// ? await res.json()
|
|
// : await res.text();
|
|
|
|
// console.log("CBS Response:", result);
|
|
// setTimeout(() => {
|
|
// router.push("/eMandate/mandate_page");
|
|
// }, 1000);
|
|
|
|
// } catch (error) {
|
|
// console.error("CBS API Error:", error);
|
|
// }
|
|
// }
|
|
// else {
|
|
// setOtp("");
|
|
// }
|
|
// setIsVerifying(false);
|
|
// };
|
|
|
|
const handleVerifyOtp = async () => {
|
|
const mobile = localStorage.getItem("userMobNo");
|
|
|
|
if (!mobile || otp.length !== 6) return;
|
|
|
|
setIsVerifying(true);
|
|
const success = await verifyOtp(otp, mobile);
|
|
if (success) {
|
|
const encoded_data = localStorage.getItem("Validate_data");
|
|
|
|
if (!encoded_data) {
|
|
console.error("Validate_data not found in localStorage");
|
|
setIsVerifying(false);
|
|
return;
|
|
}
|
|
const url = "https://apiemandate.kccb.in:9035/EMandate/auth-cbs-resp";
|
|
console.log("Redirecting (POST) to URL:", url);
|
|
console.log("POST Body Data:", { data: encoded_data });
|
|
|
|
// Create a form for POST redirect
|
|
const form = document.createElement("form");
|
|
form.method = "POST";
|
|
form.action = url;
|
|
// Add hidden field "data"
|
|
const input = document.createElement("input");
|
|
input.type = "hidden";
|
|
input.name = "data";
|
|
input.value = encoded_data;
|
|
|
|
form.appendChild(input);
|
|
document.body.appendChild(form);
|
|
|
|
// Submit → browser navigates to URL using POST
|
|
form.submit();
|
|
return;
|
|
}
|
|
else {
|
|
setOtp("");
|
|
}
|
|
setIsVerifying(false);
|
|
};
|
|
|
|
|
|
if (authorized === null) {
|
|
return (
|
|
<Center style={{ height: "100vh" }}>
|
|
<Loader size="lg" color="green" />
|
|
</Center>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Providers>
|
|
<Box
|
|
style={{
|
|
minHeight: "100vh",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
// background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
|
|
background: 'linear-gradient(179deg, #3faa56ff 49%, #3aa760ff 80%)'
|
|
}}
|
|
>
|
|
{/* HEADER */}
|
|
<Paper
|
|
radius={0}
|
|
shadow="md"
|
|
style={{
|
|
position: "sticky",
|
|
top: 0,
|
|
zIndex: 100,
|
|
background: "linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
|
|
// padding: isMobile ? "0.75rem 1rem" : "1rem 1.5rem",
|
|
}}
|
|
>
|
|
<Container size="xl">
|
|
<Group justify="space-between">
|
|
<Group gap="md">
|
|
<Image
|
|
src={logo}
|
|
component={NextImage}
|
|
fit="contain"
|
|
alt="KCC Bank Logo"
|
|
style={{
|
|
width: isMobile ? "50px" : "70px",
|
|
height: isMobile ? "50px" : "70px",
|
|
}}
|
|
/>
|
|
{!isMobile && (
|
|
<Title
|
|
order={2}
|
|
c="white"
|
|
style={{
|
|
fontSize: "clamp(1rem, 2vw, 1.5rem)",
|
|
fontFamily: "Roboto",
|
|
}}
|
|
>
|
|
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
|
|
</Title>
|
|
)}
|
|
</Group>
|
|
|
|
{isMobile ? (
|
|
<ActionIcon
|
|
variant="subtle"
|
|
color="white"
|
|
size="lg"
|
|
onClick={handleLogout}
|
|
title="Logout"
|
|
>
|
|
<IconLogout size={24} />
|
|
</ActionIcon>
|
|
) : (
|
|
<Button
|
|
variant="white"
|
|
color="gray"
|
|
onClick={handleLogout}
|
|
leftSection={<IconLogout size={20} />}
|
|
>
|
|
Logout
|
|
</Button>
|
|
)}
|
|
</Group>
|
|
</Container>
|
|
</Paper>
|
|
|
|
{/* WELCOME BAR */}
|
|
<Paper
|
|
radius={0}
|
|
p={isMobile ? "sm" : "md"}
|
|
bg="white"
|
|
shadow="sm"
|
|
style={{ borderBottom: "3px solid #0a7228" }}
|
|
>
|
|
<Container size="xl">
|
|
<Stack gap="xs">
|
|
<Text
|
|
fw={600}
|
|
size={isMobile ? "lg" : "xl"}
|
|
style={{ fontFamily: "Inter" }}
|
|
>
|
|
Welcome, {custname ?? "User"}
|
|
</Text>
|
|
<Divider />
|
|
</Stack>
|
|
</Container>
|
|
</Paper>
|
|
|
|
{/* MAIN CONTENT */}
|
|
<Box style={{ flex: 1, padding: "2rem 1rem" }}>
|
|
<Container size="sm">
|
|
<Center>
|
|
<Paper
|
|
shadow="xl"
|
|
radius="xl"
|
|
p={isMobile ? "xl" : "2rem"}
|
|
style={{
|
|
maxWidth: "500px",
|
|
width: "100%",
|
|
background: "rgba(255, 255, 255, 0.95)",
|
|
backdropFilter: "blur(10px)",
|
|
}}
|
|
>
|
|
<Stack gap="xl" align="center">
|
|
{/* Icon */}
|
|
<Box
|
|
style={{
|
|
width: "80px",
|
|
height: "80px",
|
|
borderRadius: "50%",
|
|
background:
|
|
"linear-gradient(135deg, #0a7228 0%, #2563eb 100%)",
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
}}
|
|
>
|
|
<IconShieldCheck size={48} color="white" />
|
|
</Box>
|
|
|
|
{/* Title */}
|
|
<Stack gap="xs" align="center">
|
|
<Title
|
|
order={2}
|
|
ta="center"
|
|
style={{
|
|
fontSize: isMobile ? "1.5rem" : "2rem",
|
|
}}
|
|
>
|
|
OTP Verification
|
|
</Title>
|
|
<Text size="sm" c="dimmed" ta="center">
|
|
Enter the 6-digit OTP sent to your registered mobile
|
|
number
|
|
</Text>
|
|
<Text size="sm" fw={600} c="blue">
|
|
{localStorage.getItem("userMobNo")?.replace(
|
|
/(\d{2})(\d{4})(\d{4})/,
|
|
"+91 $1****$3"
|
|
)}
|
|
</Text>
|
|
</Stack>
|
|
|
|
{/* OTP Input */}
|
|
<Stack gap="md" align="center" w="100%">
|
|
<PinInput
|
|
size={isMobile ? "lg" : "xl"}
|
|
length={6}
|
|
value={otp}
|
|
onChange={setOtp}
|
|
placeholder="○"
|
|
type="number"
|
|
oneTimeCode
|
|
styles={{
|
|
input: {
|
|
fontSize: isMobile ? "1.5rem" : "2rem",
|
|
fontWeight: 600,
|
|
borderColor: "#0a7228",
|
|
},
|
|
}}
|
|
/>
|
|
|
|
{/* Timer */}
|
|
<Group gap="xs">
|
|
<Text size="sm" c="dimmed">
|
|
{canResend ? (
|
|
"Didn't receive OTP?"
|
|
) : (
|
|
<>
|
|
Resend OTP in{" "}
|
|
<Text component="span" fw={600} c="blue">
|
|
{timer}s
|
|
</Text>
|
|
</>
|
|
)}
|
|
</Text>
|
|
</Group>
|
|
|
|
{/* Verify Button */}
|
|
<Button
|
|
fullWidth
|
|
size="lg"
|
|
onClick={handleVerifyOtp}
|
|
loading={isVerifying}
|
|
disabled={otp.length !== 6 || isVerifying}
|
|
gradient={{ from: "teal", to: "blue", deg: 60 }}
|
|
variant="gradient"
|
|
radius="md"
|
|
>
|
|
{isVerifying ? "Verifying..." : "Verify OTP"}
|
|
</Button>
|
|
|
|
{/* Resend Button */}
|
|
<Button
|
|
fullWidth
|
|
variant="light"
|
|
size="md"
|
|
onClick={handleResendOtp}
|
|
disabled={!canResend || isResending}
|
|
loading={isResending}
|
|
leftSection={<IconRefresh size={18} />}
|
|
>
|
|
{isResending ? "Sending..." : "Resend OTP"}
|
|
</Button>
|
|
</Stack>
|
|
|
|
{/* Info */}
|
|
<Paper p="md" radius="md" bg="blue.0" w="100%">
|
|
<Text size="xs" c="blue.9" ta="center">
|
|
<Text component="span" fw={600}>
|
|
Note:{" "}
|
|
</Text>
|
|
Please do not share your OTP with anyone. KCC Bank
|
|
will never ask for your OTP.
|
|
</Text>
|
|
</Paper>
|
|
</Stack>
|
|
</Paper>
|
|
</Center>
|
|
</Container>
|
|
</Box>
|
|
|
|
{/* FOOTER */}
|
|
<Paper
|
|
radius={0}
|
|
p="md"
|
|
bg="gray.9"
|
|
style={{
|
|
borderTop: "1px solid #ddd",
|
|
}}
|
|
>
|
|
<Container size="xl">
|
|
<Text size="xs" c="white" ta="center">
|
|
© 2025 The Kangra Central Co-Operative Bank Ltd. All rights
|
|
reserved.
|
|
</Text>
|
|
</Container>
|
|
</Paper>
|
|
</Box>
|
|
</Providers>
|
|
);
|
|
}
|