Files
IB/src/app/ForgetPassword/page.tsx
tomosa.sarkar 97272e2ded feat : integrated forget password logic.
feat: make the screen responsive.
fix: change the frontend of login screen
2025-12-30 15:59:51 +05:30

436 lines
15 KiB
TypeScript

"use client";
import React, { useState, useEffect } from "react";
import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image, Container, Grid, Progress } from "@mantine/core";
import { notifications } from "@mantine/notifications";
import { Providers } from "@/app/providers";
import { useRouter } from "next/navigation";
import NextImage from "next/image";
import logo from '@/app/image/logo1.jpg';
import forget_psw from '@/app/image/forget_password.jpg';
import { generateCaptcha } from '@/app/captcha';
import { IconLock, IconRefresh, IconShieldCheck } from '@tabler/icons-react';
export default function ForgetLoginPwd() {
const router = useRouter();
const [authorized, setAuthorized] = useState<boolean | null>(null);
const [captcha, setCaptcha] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [captchaInput, setCaptchaInput] = useState('');
const [captchaError, setCaptchaError] = useState('');
const icon = <IconLock size={18} stroke={1.5} />;
useEffect(() => {
const loadCaptcha = async () => {
const newCaptcha = await generateCaptcha();
setCaptcha(newCaptcha);
};
loadCaptcha();
}, []);
// Add this useEffect in your component
useEffect(() => {
// Check authorization on mount
const token = localStorage.getItem("reset_pwd_token");
if (!token) {
setAuthorized(false);
router.push("/login");
return;
}
setAuthorized(true);
// Handle back button navigation
const handlePopState = () => {
localStorage.removeItem("reset_pwd_token");
router.push("/login");
};
// Handle page refresh/reload
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
localStorage.removeItem("reset_pwd_token");
};
// Add event listeners
window.addEventListener('popstate', handlePopState);
window.addEventListener('beforeunload', handleBeforeUnload);
// Cleanup listeners on unmount
return () => {
window.removeEventListener('popstate', handlePopState);
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, [router]);
useEffect(() => {
const token = localStorage.getItem("reset_pwd_token");
if (!token) {
setAuthorized(false);
router.push("/login");
} else {
setAuthorized(true);
}
}, [router]);
const handleRefreshCaptcha = async () => {
const newCaptcha = await generateCaptcha();
setCaptcha(newCaptcha);
setCaptchaInput('');
setCaptchaError('');
};
const handleSetLoginPassword = async (e: React.FormEvent) => {
e.preventDefault();
const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
if (captchaInput !== captcha) {
setCaptchaError("Incorrect CAPTCHA. Please try again.");
setCaptchaInput('');
return;
}
if (!password || !confirmPassword) {
notifications.show({
withBorder: true,
color: "red",
title: "Required Fields",
message: "Both password fields are required.",
autoClose: 5000,
});
return;
}
if (password !== confirmPassword) {
notifications.show({
withBorder: true,
color: "red",
title: "Password Mismatch",
message: "Passwords do not match.",
autoClose: 5000,
});
return;
}
if (!pwdRegex.test(password)) {
notifications.show({
withBorder: true,
color: "red",
title: "Weak Password",
message: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.",
autoClose: 5000,
});
return;
}
const token = localStorage.getItem("reset_pwd_token");
const response = await fetch('api/auth/login_password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Login-Type': 'IB',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
login_password: password,
}),
});
const data = await response.json();
if (response.ok) {
notifications.show({
withBorder: true,
color: "green",
title: "Success",
message: "Login Password has been set successfully",
autoClose: 5000,
});
localStorage.removeItem("reset_pwd_token");
router.push("/login");
} else {
notifications.show({
withBorder: true,
color: "red",
title: "Error",
message: "Please try again later",
autoClose: 5000,
});
router.push("/login");
}
};
if (authorized) {
return (
<Providers>
<Box style={{
minHeight: "100vh",
display: "flex",
flexDirection: "column",
background: "linear-gradient(135deg, #f5f7fa 0%, #e8f5e9 100%)"
}}>
{/* Header */}
<Box
style={{
position: 'sticky',
top: 0,
zIndex: 100,
display: "flex",
alignItems: "center",
justifyContent: "flex-start",
background: "linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
padding: "10px 15px",
minHeight: "80px",
}}>
<Image
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{
width: "60px",
height: "60px",
minWidth: "50px",
marginRight: "15px"
}}
/>
<Box style={{ flex: 1 }}>
<Title
order={3}
style={{
fontFamily: "Roboto",
color: "white",
marginBottom: 2,
fontSize: "clamp(0.9rem, 2.5vw, 1.25rem)",
lineHeight: 1.3
}}>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text
size="xs"
c="white"
style={{
opacity: 0.85,
fontSize: "clamp(0.65rem, 1.5vw, 0.75rem)"
}}>
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
</Text>
</Box>
</Box>
<Box
style={{
flex: 1,
padding: "2rem 0",
display: "flex",
alignItems: "center"
}}
>
<Container size="xl" style={{ width: "100%" }}>
<Grid gutter={{ base: "md", md: "xl" }} align="center">
{/* Image Column - Now visible on all screens */}
<Grid.Col span={{ base: 12, md: 6, lg: 7 }}>
<Box
style={{
position: "relative",
height: "700px",
borderRadius: "24px",
overflow: "hidden",
boxShadow: "0 20px 60px rgba(0,0,0,0.15)",
background: `url(${forget_psw.src})`,
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
backgroundSize: "cover",
}}
>
<Box style={{
position: "absolute",
bottom: 0,
left: 0,
right: 0,
padding: "2rem",
background: "linear-gradient(to top, rgba(0,0,0,0.7), transparent)",
}}>
<Title order={2} c="white" mb="sm">
Welcome to KCCB Internet Banking
</Title>
<Text c="white" size="sm" style={{ opacity: 0.9 }}>
Experience secure, fast, and convenient banking at your fingertips
</Text>
</Box>
</Box>
</Grid.Col>
{/* Form Column */}
<Grid.Col span={{ base: 12, md: 6, lg: 5 }}>
<Card
radius="xl"
shadow="xl"
p={{ base: "xl", sm: "2rem" }}
style={{
background: "rgba(255, 255, 255, 0.95)",
backdropFilter: "blur(10px)",
border: "1px solid rgba(255,255,255,0.5)",
maxWidth: "480px",
margin: "0 auto"
}}
>
<Box style={{ textAlign: "center", marginBottom: "2rem" }}>
<Title order={3} style={{ color: "#35487eff", fontWeight: 700 }}>
Set Login Password
</Title>
<Text size="sm" c="dimmed">
Create a strong password to secure your account
</Text>
</Box>
<Box mb="md">
<PasswordInput
label="Login Password"
placeholder="Enter your password"
required
size="md"
value={password}
onChange={(e) => setPassword(e.currentTarget.value)}
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onCut={(e) => e.preventDefault()}
styles={{
input: {
borderRadius: "8px",
border: "2px solid #e9ecef"
}
}}
/>
</Box>
<Box mb="md">
<PasswordInput
label="Confirm Login Password"
placeholder="Re-enter your password"
required
size="md"
rightSection={icon}
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.currentTarget.value)}
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onCut={(e) => e.preventDefault()}
styles={{
input: {
borderRadius: "8px",
border: "2px solid #e9ecef"
}
}}
/>
</Box>
{/* CAPTCHA Section */}
<Box mb="md">
<Text size="sm" fw={600} mb="xs">Verification Code</Text>
<Box style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12 }}>
<Box
style={{
flex: 1,
padding: "5px",
background: "white",
borderRadius: "8px",
border: "2px dashed #dee6deff",
textAlign: "center",
fontWeight: 500,
fontSize: "22px",
letterSpacing: "6px",
color: "#0a7228",
fontFamily: "Verdana",
userSelect: "none",
textDecoration: "line-through"
// fontFamily: "monospace"
}}
>
{captcha}
</Box>
<Button
size="md"
variant="light"
color="green"
onClick={handleRefreshCaptcha}
leftSection={<IconRefresh size={16} />}
style={{ borderRadius: "8px" }}
>
Refresh
</Button>
</Box>
<TextInput
placeholder="Enter the text above"
value={captchaInput}
onChange={(e) => {
setCaptchaInput(e.currentTarget.value);
setCaptchaError('');
}}
required
size="md"
error={captchaError}
styles={{
input: {
borderRadius: "8px"
}
}}
/>
</Box>
<Button
type="submit"
fullWidth
size="lg"
onClick={handleSetLoginPassword}
style={{
borderRadius: "10px",
fontWeight: 600,
marginBottom: "1.5rem"
}}
>
Set Password
</Button>
<Box
p="md"
style={{
background: "#cdffdfff",
borderRadius: "10px",
border: "1px solid #42c442ff",
borderLeft: "4px solid #42c442ff"
}}
>
<Text size="sm" fw={100} mb={4} c="#856404">
Password Requirements:
</Text>
<Text size="xs" c="#101010ff" style={{ lineHeight: 1.6 }}>
Minimum 8 characters<br />
At least 1 uppercase letter<br />
At least 1 number<br />
At least 1 special character (@$!%*#?&)
</Text>
</Box>
</Card>
</Grid.Col>
</Grid>
</Container>
</Box>
{/* Footer */}
<Box
style={{
flexShrink: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f8f9fa",
padding: "1rem",
}}
>
<Text c="dimmed" size="xs">
© 2025 Kangra Central Co-Operative Bank. All rights reserved.
</Text>
</Box>
</Box>
</Providers>
);
}
}