fix: design in view profile and account overview
feat : page add for e mandate otp
This commit is contained in:
394
src/app/eMandate/otp_page/page.tsx
Normal file
394
src/app/eMandate/otp_page/page.tsx
Normal file
@@ -0,0 +1,394 @@
|
||||
"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) {
|
||||
setTimeout(() => router.push("/eMandate/mandate_page"), 1500);
|
||||
} 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user