feat : integrated forget password logic.

feat: make the screen responsive.
fix: change the frontend of login screen
This commit is contained in:
2025-12-30 15:59:51 +05:30
parent 9925905a23
commit 97272e2ded
11 changed files with 788 additions and 439 deletions

View File

@@ -1,91 +1,126 @@
"use client"; "use client";
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image } from "@mantine/core"; import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image, Container, Grid, Progress } from "@mantine/core";
import { notifications } from "@mantine/notifications"; import { notifications } from "@mantine/notifications";
import { Providers } from "@/app/providers"; import { Providers } from "@/app/providers";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import NextImage from "next/image"; import NextImage from "next/image";
import logo from '@/app/image/logo.jpg'; import logo from '@/app/image/logo1.jpg';
import changePwdImage from '@/app/image/changepw.png'; import forget_psw from '@/app/image/forget_password.jpg';
// import CaptchaImage from './CaptchaImage'; import { generateCaptcha } from '@/app/captcha';
import { IconEye, IconEyeOff, IconLock, IconLogout } from '@tabler/icons-react'; import { IconLock, IconRefresh, IconShieldCheck } from '@tabler/icons-react';
export default function ForgetLoginPwd() { export default function ForgetLoginPwd() {
const router = useRouter(); const router = useRouter();
const [authorized, SetAuthorized] = useState<boolean | null>(null); const [authorized, setAuthorized] = useState<boolean | null>(null);
const [captcha, setCaptcha] = useState(""); const [captcha, setCaptcha] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState("");
const [captchaInput, setCaptchaInput] = useState(''); const [captchaInput, setCaptchaInput] = useState('');
const [captchaError, setCaptchaError] = useState(''); const [captchaError, setCaptchaError] = useState('');
const [confirmVisible, setConfirmVisible] = useState(false);
const toggleConfirmVisibility = () => setConfirmVisible((v) => !v);
const icon = <IconLock size={18} stroke={1.5} />; const icon = <IconLock size={18} stroke={1.5} />;
async function handleLogout(e: React.FormEvent) {
e.preventDefault();
localStorage.removeItem("access_token");
sessionStorage.removeItem("access_token")
localStorage.clear();
sessionStorage.clear();
router.push("/login")
}
useEffect(() => { useEffect(() => {
generateCaptcha(); const loadCaptcha = async () => {
const newCaptcha = await generateCaptcha();
setCaptcha(newCaptcha);
};
loadCaptcha();
}, []); }, []);
const generateCaptcha = () => { // Add this useEffect in your component
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = ''; useEffect(() => {
for (let i = 0; i < 6; i++) { // Check authorization on mount
result += chars.charAt(Math.floor(Math.random() * chars.length)); const token = localStorage.getItem("reset_pwd_token");
if (!token) {
setAuthorized(false);
router.push("/login");
return;
} }
setCaptcha(result); 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(''); setCaptchaInput('');
setCaptchaError(''); setCaptchaError('');
}; };
async function handleSetLoginPassword(e: React.FormEvent) { const handleSetLoginPassword = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/; const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
if (captchaInput !== captcha) {
setCaptchaError("Incorrect CAPTCHA. Please try again.");
setCaptchaInput('');
return;
}
if (!password || !confirmPassword) { if (!password || !confirmPassword) {
notifications.show({ notifications.show({
withBorder: true, withBorder: true,
color: "red", color: "red",
title: "Both password fields are required.", title: "Required Fields",
message: "Both password fields are required.", message: "Both password fields are required.",
autoClose: 5000, autoClose: 5000,
}); });
return; return;
// alert("Both password fields are required."); }
} else if (password !== confirmPassword) {
// alert("Passwords do not match."); if (password !== confirmPassword) {
notifications.show({ notifications.show({
withBorder: true, withBorder: true,
color: "red", color: "red",
title: "Passwords do not match.", title: "Password Mismatch",
message: "Passwords do not match.", message: "Passwords do not match.",
autoClose: 5000, autoClose: 5000,
}); });
return; return;
} }
else if (!pwdRegex.test(password)) {
// alert("Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long."); if (!pwdRegex.test(password)) {
notifications.show({ notifications.show({
withBorder: true, withBorder: true,
color: "red", color: "red",
title: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.", title: "Weak Password",
message: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.", message: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.",
autoClose: 5000, autoClose: 5000,
}); });
return; return;
} }
else if (captchaInput !== captcha) {
setCaptchaError("Incorrect CAPTCHA."); const token = localStorage.getItem("reset_pwd_token");
return;
}
const token = localStorage.getItem("access_token");
const response = await fetch('api/auth/login_password', { const response = await fetch('api/auth/login_password', {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -97,174 +132,305 @@ export default function ForgetLoginPwd() {
login_password: password, login_password: password,
}), }),
}); });
const data = await response.json(); const data = await response.json();
if (response.ok) { if (response.ok) {
// console.log(data);
notifications.show({ notifications.show({
withBorder: true, withBorder: true,
color: "green", color: "green",
title: "Login Password has been set", title: "Success",
message: "Login Password has been set", message: "Login Password has been set successfully",
autoClose: 5000, autoClose: 5000,
}); });
router.push("/SetTxn"); localStorage.removeItem("reset_pwd_token");
} router.push("/login");
else { } else {
notifications.show({ notifications.show({
withBorder: true, withBorder: true,
color: "red", color: "red",
title: "Please try again later ", title: "Error",
message: "Please try again later ", message: "Please try again later",
autoClose: 5000, autoClose: 5000,
}); });
router.push("/login"); router.push("/login");
} }
} };
// useEffect(() => { if (authorized) {
// const token = localStorage.getItem("access_token");
// if (!token) {
// SetAuthorized(false);
// router.push("/login");
// }
// else {
// SetAuthorized(true);
// }
// }, []);
// if (authorized) {
return ( return (
<Providers> <Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}> <Box style={{
<Box style={{ minHeight: "100vh",
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100, display: "flex",
display: "flex", flexDirection: "column",
justifyContent: "flex-start", background: "linear-gradient(135deg, #f5f7fa 0%, #e8f5e9 100%)"
background: "linear-gradient(15deg,rgba(2, 163, 85, 1) 55%, rgba(101, 101, 184, 1) 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 <Image
// radius="md"
fit="cover"
src={logo} src={logo}
component={NextImage} component={NextImage}
fit="contain"
alt="ebanking" alt="ebanking"
style={{ width: "100%", height: "100%" }} style={{
width: "60px",
height: "60px",
minWidth: "50px",
marginRight: "15px"
}}
/> />
<Button style={{ <Box style={{ flex: 1 }}>
position: 'absolute', <Title
top: '50%', order={3}
left: '90%', style={{
color: 'white', fontFamily: "Roboto",
textShadow: '1px 1px 2px black', color: "white",
fontSize: "20px" marginBottom: 2,
}} fontSize: "clamp(0.9rem, 2.5vw, 1.25rem)",
leftSection={<IconLogout color='white' />} variant="subtle" onClick={handleLogout}>Logout</Button> 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>
<div>
<Box style={{ display: "flex", justifyContent: "center", alignItems: "center", columnGap: "5rem" }} bg="#c1e0f0">
<Image h="85vh" fit="contain" component={NextImage} src={changePwdImage} alt="Change Password Image" />
<Box h="100%" style={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
<Card p="xl" w="40vw" h='82vh'>
<Title order={3}
// @ts-ignore
align="center" mb="md">Set Login Password</Title>
<form onSubmit={handleSetLoginPassword}> <Box
<PasswordInput style={{
label="Login Password" flex: 1,
placeholder="Enter your password" padding: "2rem 0",
required display: "flex",
id="loginPassword" alignItems: "center"
value={password} }}
onChange={(e) => setPassword(e.currentTarget.value)} >
onCopy={(e) => e.preventDefault()} <Container size="xl" style={{ width: "100%" }}>
onPaste={(e) => e.preventDefault()} <Grid gutter={{ base: "md", md: "xl" }} align="center">
onCut={(e) => e.preventDefault()} {/* 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>
<PasswordInput {/* Form Column */}
label="Confirm Login Password" <Grid.Col span={{ base: 12, md: 6, lg: 5 }}>
placeholder="Enter your password" <Card
required radius="xl"
rightSection={icon} shadow="xl"
id="confirmPassword" p={{ base: "xl", sm: "2rem" }}
value={confirmPassword} style={{
onChange={(e) => setConfirmPassword(e.currentTarget.value)} background: "rgba(255, 255, 255, 0.95)",
type={confirmVisible ? 'text' : 'password'} backdropFilter: "blur(10px)",
// rightSection={ border: "1px solid rgba(255,255,255,0.5)",
// <button maxWidth: "480px",
// type="button" margin: "0 auto"
// onClick={toggleConfirmVisibility} }}
// style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'grey' }} >
// > <Box style={{ textAlign: "center", marginBottom: "2rem" }}>
// {confirmVisible ? <IconEyeOff size={18} /> : <IconEye size={18} />}
// </button>
// }
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onCut={(e) => e.preventDefault()}
/> <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>
{/* CAPTCHA */} <Box mb="md">
<div style={{ marginTop: 20 }}> <PasswordInput
<label style={{ fontWeight: 600 }}>Enter CAPTCHA *</label> label="Login Password"
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 5 }}> placeholder="Enter your password"
{/* <CaptchaImage text={captcha} /> */}
<Button size="xs" variant="outline" onClick={generateCaptcha}>Refresh</Button>
</div>
<TextInput
placeholder="Enter above text"
value={captchaInput}
onChange={(e) => setCaptchaInput(e.currentTarget.value)}
required 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"
}
}}
/> />
{captchaError && <p style={{ color: 'red', fontSize: '12px' }}>{captchaError}</p>} </Box>
</div>
<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 <Button
type="submit" type="submit"
fullWidth fullWidth
mt="sm" size="lg"
color="blue" onClick={handleSetLoginPassword}
style={{
borderRadius: "10px",
fontWeight: 600,
marginBottom: "1.5rem"
}}
> >
Set Set Password
</Button> </Button>
</form>
<br></br>
<Box
style={{
flex: 1,
borderLeft: '1px solid #ccc',
paddingLeft: 16,
minHeight: 90,
}} <Box
> p="md"
<Text size="sm"> style={{
<strong>Note:</strong> Password will contains minimum one alphabet, one digit, one special symbol and total 8 charecters. background: "#cdffdfff",
</Text> borderRadius: "10px",
</Box> border: "1px solid #42c442ff",
</Card> borderLeft: "4px solid #42c442ff"
</Box> }}
</Box> >
<Box <Text size="sm" fw={100} mb={4} c="#856404">
style={{ Password Requirements:
flexShrink: 0, </Text>
display: "flex", <Text size="xs" c="#101010ff" style={{ lineHeight: 1.6 }}>
justifyContent: "center", Minimum 8 characters<br />
alignItems: "center", At least 1 uppercase letter<br />
backgroundColor: "#f8f9fa", At least 1 number<br />
marginTop: "0.5rem", At least 1 special character (@$!%*#?&)
}} </Text>
> </Box>
<Text c="dimmed" size="xs"> </Card>
© 2025 Kangra Central Co-Operative Bank </Grid.Col>
</Text> </Grid>
</Box> </Container>
</div> </Box>
</div>
</Providers > {/* 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>
); );
// } }
} }

View File

@@ -1,74 +0,0 @@
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 100;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.8rem 2rem;
background: linear-gradient(
15deg,
rgba(10, 114, 40, 1) 55%,
rgba(101, 101, 184, 1) 100%
);
flex-wrap: wrap;
}
.headerLogo {
width: 60px;
}
.headerText {
display: flex;
flex-direction: column;
flex: 1;
}
.desktopText {
color: white;
font-family: Roboto, sans-serif;
font-size: 1.5rem;
line-height: 1.2;
}
.desktopAddress {
font-family: Roboto, sans-serif;
color: white;
font-size: 0.9rem;
margin-top: 0.25rem;
}
.mobileText {
display: none;
color: white;
font-family: Roboto, sans-serif;
font-size: 0.9rem;
text-align: center;
}
@media screen and (max-width: 768px) {
.header {
justify-content: center;
padding: 0.5rem 0.75rem;
}
.headerLogo {
width: 50px;
margin-bottom: 0.5rem;
}
.headerText {
text-align: center;
}
.desktopText,
.desktopAddress {
display: none;
}
.mobileText {
display: block;
}
}

View File

@@ -1,13 +1,13 @@
"use client"; "use client";
import React, { useEffect, useState, useRef } from "react"; import React, { useState } from "react";
import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image } from "@mantine/core"; import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image, Container, Grid, Stack, Divider, Badge } from "@mantine/core";
import { notifications } from "@mantine/notifications"; import { notifications } from "@mantine/notifications";
import { Providers } from "@/app/providers"; import { Providers } from "@/app/providers";
import NextImage from "next/image"; import NextImage from "next/image";
import logo from '@/app/image/logo1.jpg'; import logo from '@/app/image/logo1.jpg';
import changePwdImage from '@/app/image/changepw.png'; import ValidateUserId from '@/app/image/validate_page.jpg';
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { IconShieldCheck, IconPhone, IconKey } from '@tabler/icons-react';
export default function ValidateUser() { export default function ValidateUser() {
const router = useRouter(); const router = useRouter();
@@ -15,228 +15,456 @@ export default function ValidateUser() {
const [otp, setOTP] = useState(""); const [otp, setOTP] = useState("");
const [mobileNumber, setMobileNumber] = useState(""); const [mobileNumber, setMobileNumber] = useState("");
const [isCifValidated, setIsCifValidated] = useState(false); const [isCifValidated, setIsCifValidated] = useState(false);
const [generateOtp, setGenerateOtp] = useState(""); const [loading, setLoading] = useState(false);
const headerRef = useRef<HTMLHeadingElement>(null);
const validUsers = [ const handleValidateUser = async () => {
{ cif: "11111111111", mobile: "7890544528" },
{ cif: "30022497139", mobile: "6230573848" },
{ cif: "11122233344", mobile: "9998887776" },
];
async function handleGenerateOtp() {
const value = "123456";
setGenerateOtp(value);
return value;
}
const handleValidateUser = async (e: React.FormEvent) => {
e.preventDefault();
if (!Cif) {
notifications.show({
title: "Invalid CIF",
message: "Please Enter your 11 digit CIF number.",
color: "red",
});
setIsCifValidated(false);
return;
}
if (!/^\d{11}$/.test(Cif)) { if (!/^\d{11}$/.test(Cif)) {
notifications.show({ notifications.show({
title: "Invalid CIF", title: "Invalid CIF",
message: "CIF number must be exactly 11 digits.", message: "CIF number must be exactly 11 digits.",
color: "red", color: "red",
}); });
setIsCifValidated(false);
return; return;
} }
const user = validUsers.find((u) => u.cif === Cif); setLoading(true);
if (user) {
setMobileNumber(user.mobile); try {
const res = await fetch(
`/api/otp/send/set-password?customerNo=${Cif}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Login-Type": "IB",
},
}
);
const data = await res.json();
if (!res.ok) {
throw new Error(data?.message || "OTP send failed");
}
setIsCifValidated(true); setIsCifValidated(true);
const Otp = await handleGenerateOtp(); setMobileNumber(data?.mobileNo || "");
const masked = `xxxxxx${user.mobile.slice(-4)}`;
const masked = data?.mobileNo
// ? `xxxxxx${data.mobileNo.slice(-4)}`
? "registered number"
: "registered number";
notifications.show({ notifications.show({
title: "OTP Sent", title: "OTP Sent",
message: `OTP sent to your registered mobile number ${masked}`, message: `OTP sent to ${masked}`,
color: "green", color: "green",
}); });
} else {
setIsCifValidated(false); } catch (err) {
console.error("Validation error:", err);
notifications.show({ notifications.show({
title: "User Not Found", title: "Validation Failed",
message: "No such user is present.", message: err instanceof Error ? err.message : "Unable to send OTP. Please try again.",
color: "red", color: "red",
}); });
} finally {
setLoading(false);
} }
}; };
const handleSubmitOtp = () => { const handleSubmitOtp = async () => {
if (!otp) { if (!otp || otp.length !== 6) {
notifications.show({ notifications.show({
title: "Invalid OTP", title: "Invalid OTP",
message: "Please Enter OTP Before You Submit.", message: "Please enter 6 digit OTP.",
color: "red", color: "red",
}); });
return; return;
} }
if (otp === generateOtp) {
setLoading(true);
try {
const res = await fetch(
`/api/otp/verify/set-password?customerNo=${Cif}&otp=${otp}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Login-Type": "IB",
},
}
);
const data = await res.json();
// console.log(data);
if (!res.ok) {
throw new Error(data?.message || "OTP verification failed");
}
if (data?.token) {
localStorage.setItem("reset_pwd_token", data.token);
} else {
throw new Error("Token not received from server");
}
notifications.show({ notifications.show({
title: "OTP Verified", title: "OTP Verified",
message: `OTP matched successfully`, message: "OTP verified successfully.",
color: "green", color: "green",
}); });
router.push("/ForgetPassword")
} router.push("/ForgetPassword");
else {
setOTP(""); } catch (err) {
console.error("OTP verification error:", err);
notifications.show({ notifications.show({
title: "Invalid OTP", title: "Invalid OTP",
message: `The OTP you entered is incorrect`, message: err instanceof Error ? err.message : "OTP verification failed.",
color: "red", color: "red",
}); });
return; setOTP("");
} finally {
setLoading(false);
} }
};
} const handleSubmit = () => {
if (isCifValidated) {
useEffect(() => { handleSubmitOtp();
const headerData = [ } else {
"THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.", handleValidateUser();
"कांगड़ा केन्द्रीय सहकारी बैंक सीमित", }
]; };
let index = 0;
const interval = setInterval(() => {
index = (index + 1) % headerData.length;
if (headerRef.current) {
headerRef.current.textContent = headerData[index];
}
}, 2000);
return () => clearInterval(interval);
}, []);
return ( return (
<Providers> <Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", paddingTop: "5%" }}> <Box style={{
minHeight: "100vh",
display: "flex",
flexDirection: "column",
background: "linear-gradient(135deg, #f5f7fa 0%, #e8f5e9 100%)"
}}>
{/* Header */}
<Box <Box
style={{ style={{
position: 'fixed', width: '100%', height: '15%', top: 0, left: 0, zIndex: 100, position: 'sticky',
top: 0,
zIndex: 100,
display: "flex", display: "flex",
alignItems: "center",
justifyContent: "flex-start", justifyContent: "flex-start",
background: "linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)", background: "linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
padding: "10px 15px",
minHeight: "80px",
}}> }}>
<Image <Image
src={logo} src={logo}
component={NextImage} component={NextImage}
fit="contain" fit="contain"
alt="ebanking" alt="ebanking"
style={{ width: "80px", height: "auto" ,padding:"10px"}}
/>
<Title
// ref={headerRef}
order={2}
style={{ style={{
fontFamily: 'Roboto', width: "40px",
position: 'absolute', height: "60px",
top: '30%', minWidth: "50px",
left: '7%', marginRight: "15px"
color: 'White',
transition: "opacity 0.5s ease-in-out",
}} }}
> />
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD. <Box style={{ flex: 1 }}>
</Title> <Title
</Box> order={3}
<Box style={{ display: "flex", justifyContent: "center", alignItems: "center", columnGap: "5rem" }} bg="#c1e0f0"> style={{
<Image h="85vh" fit="contain" component={NextImage} src={changePwdImage} alt="Change Password Image" /> fontFamily: "Roboto",
<Box h="100%" style={{ display: "flex", justifyContent: "center", alignItems: "center" }}> color: "white",
<Card p="xl" w="35vw" h="65vh" style={{ display: "flex", flexDirection: "column", justifyContent: "center" }}> marginBottom: 2,
{/* @ts-ignore */} fontSize: "clamp(0.9rem, 2.5vw, 1.25rem)",
<Title order={3} align="center" mb="md">Validate User</Title> lineHeight: 1.3
{isCifValidated && (
// @ts-ignore
<Text align="center"> Welcome {" "}{Cif}</Text>
)}
<form onSubmit={(e) => {
e.preventDefault();
isCifValidated ? handleSubmitOtp() : handleValidateUser(e);
}}> }}>
<TextInput THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
label="Enter Your CIF Number" </Title>
placeholder="Enter your CIF" <Text
withAsterisk size="xs"
value={Cif} c="white"
disabled={isCifValidated} style={{
onChange={(e) => { opacity: 0.85,
const input = e.currentTarget.value; fontSize: "clamp(0.65rem, 1.5vw, 0.75rem)"
if (input.length <= 11) { }}>
setCif(input); Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
} </Text>
}}
onKeyDown={(e) => {
const isNumberKey = /[0-9]/.test(e.key);
const isControlKey = ["Backspace", "Tab", "ArrowLeft", "ArrowRight"].includes(e.key);
if (!isNumberKey && !isControlKey) {
e.preventDefault();
}
}}
/>
<div style={{ marginTop: "1rem", minHeight: "80px" }}>
{!isCifValidated && (
<>
<br></br>
<Text fs="italic" c="dimmed">NOTE: Your CIF number travels in an encrypted and highly secured mode.</Text>
</>
)}
{isCifValidated && (
<>
<PasswordInput
label="Enter OTP"
placeholder="Enter your OTP"
withAsterisk
value={otp}
maxLength={6}
onKeyDown={(e) => {
const isNumberKey = /[0-9]/.test(e.key);
const isControlKey = ["Backspace", "Tab", "ArrowLeft", "ArrowRight"].includes(e.key);
if (!isNumberKey && !isControlKey) {
e.preventDefault();
}
}}
onChange={(e) => setOTP(e.currentTarget.value)}
/>
<Text size="xs" mt="xs" c='green'>
OTP sent to your registered mobile number{" "}
<b>{`xxxxxx${mobileNumber.slice(-4)}`}</b>
</Text>
</>
)}
</div>
<Button type="submit" mt="lg" color="blue">
{isCifValidated ? "Submit OTP" : "Validate"}
</Button>
</form>
</Card>
</Box> </Box>
</Box> </Box>
{/* Main Content */}
<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 - Hidden on mobile */}
<Grid.Col
span={{ base: 12, md: 6, lg: 7 }}
visibleFrom="md"
>
<Box
style={{
position: "relative",
height: "500px",
borderRadius: "24px",
overflow: "hidden",
boxShadow: "0 20px 60px rgba(0,0,0,0.15)",
background: `url(${ValidateUserId.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",
height:"100%",
margin: "0 auto"
}}
>
<Stack gap="lg">
{/* Header Section */}
<Box style={{ textAlign: "center" }}>
{/* <Box style={{
width: "70px",
height: "70px",
margin: "0 auto 1rem",
background: "linear-gradient(135deg, #3a3293ff 0%, #895fd1ff 100%)",
borderRadius: "50%",
display: "flex",
alignItems: "center",
justifyContent: "center",
boxShadow: "0 4px 20px rgba(10, 114, 40, 0.3)"
}}>
<IconShieldCheck size={36} color="white" />
</Box> */}
<Title order={3} mb="xs" style={{ color: "#35487eff", fontWeight: 700 }}>
Validate User
</Title>
<Text size="sm" c="dimmed" style={{ lineHeight: 1.6 }}>
Secure access to your KCCB Internet Banking
</Text>
</Box>
<Divider />
{/* Welcome Message */}
{isCifValidated && (
<Box style={{
background: "linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%)",
padding: "1rem",
borderRadius: "12px",
textAlign: "center",
border: "1px solid #a5d6a7"
}}>
<Text size="sm" c="dimmed">Welcome</Text>
<Text size="lg" fw={600} c="#0a7228">{Cif}</Text>
</Box>
)}
{/* Form Fields */}
<Stack gap="md">
<TextInput
label="CIF Number"
placeholder="Enter your 11-digit CIF"
size="md"
withAsterisk
value={Cif}
disabled={isCifValidated}
leftSection={<IconKey size={18} />}
styles={{
input: {
borderRadius: "12px",
border: "2px solid #e0e0e0",
fontSize: "1rem",
padding: "1.5rem 1rem 1.5rem 2.5rem",
transition: "all 0.3s ease",
'&:focus': {
borderColor: "#0a7228",
boxShadow: "0 0 0 3px rgba(10, 114, 40, 0.1)"
}
}
}}
onChange={(e) => {
const value = e.currentTarget.value;
if (value.length <= 11 && /^\d*$/.test(value)) {
setCif(value);
}
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
handleSubmit();
}
}}
/>
{!isCifValidated && (
<Box style={{
background: "#f5f5f5",
padding: "0.75rem",
borderRadius: "8px",
borderLeft: "3px solid #4caf50"
}}>
<Text size="xs" c="dimmed" style={{ lineHeight: 1.5 }}>
🔒 Your CIF is transmitted securely using encrypted channels
</Text>
</Box>
)}
{isCifValidated && (
<>
<PasswordInput
label="One-Time Password (OTP)"
placeholder="Enter 6-digit OTP"
size="md"
withAsterisk
value={otp}
maxLength={6}
leftSection={<IconPhone size={18} />}
styles={{
input: {
borderRadius: "12px",
border: "2px solid #e0e0e0",
fontSize: "1rem",
padding: "1.5rem 1rem 1.5rem 2.5rem",
transition: "all 0.3s ease",
letterSpacing: "3px",
'&:focus': {
borderColor: "#0a7228",
boxShadow: "0 0 0 3px rgba(10, 114, 40, 0.1)"
}
}
}}
onChange={(e) => {
const value = e.currentTarget.value;
if (/^\d*$/.test(value)) {
setOTP(value);
}
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
handleSubmit();
}
}}
/>
<Box style={{
background: "#e8f5e9",
padding: "0.75rem",
borderRadius: "8px",
borderLeft: "3px solid #4caf50"
}}>
<Text size="xs" c="#4caf50" style={{ lineHeight: 1.5 }}>
{/* 📱 OTP sent to <strong>{`xxxxxx${mobileNumber.slice(-4)}`}</strong> */}
📱 OTP sent to <strong>Registered Mobile Number</strong>
</Text>
</Box>
</>
)}
<Button
fullWidth
size="lg"
onClick={handleSubmit}
loading={loading}
style={{
marginTop: "1rem",
// background: "linear-gradient(135deg, #0a7228 0%, #1b5e20 100%)",
borderRadius: "12px",
height: "52px",
fontSize: "1rem",
fontWeight: 600,
letterSpacing: "0.5px",
boxShadow: "0 4px 15px #4caf50",
transition: "all 0.3s ease",
border: "none"
}}
styles={{
root: {
'&:hover': {
transform: 'translateY(-2px)',
boxShadow: "0 6px 20px rgba(10, 114, 40, 0.4)"
},
'&:active': {
transform: 'translateY(0)'
}
}
}}
>
{isCifValidated ? "Verify OTP" : "Send OTP"}
</Button>
</Stack>
{/* Security Note */}
<Box style={{
textAlign: "center",
padding: "0.75rem",
borderTop: "1px solid #e0e0e0"
}}>
<Text size="xs" c="dimmed" style={{ lineHeight: 1.6 }}>
Having trouble? Contact our support team
</Text>
</Box>
</Stack>
</Card>
</Grid.Col>
</Grid>
</Container>
</Box>
{/* Footer */}
<Box <Box
style={{ style={{
flexShrink: 0,
display: "flex", display: "flex",
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
backgroundColor: "#f8f9fa", backgroundColor: "#f8f9fa",
marginTop: "0.5rem", padding: "15px 10px",
textAlign: "center",
}} }}
> >
<Text c="dimmed" size="xs"> <Text c="dimmed" size="xs">
© 2025 Kangra Central Co-Operative Bank © 2025 Kangra Central Co-Operative Bank
</Text> </Text>
</Box> </Box>
</div> </Box>
</Providers> </Providers>
); );
} }

View File

@@ -30,7 +30,7 @@ export const generateActiveUsersPDF = (reportData: any, startDate: string, endDa
<div style="font-family:Arial, sans-serif; font-size:12px;"> <div style="font-family:Arial, sans-serif; font-size:12px;">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;"> <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">
<div style="display:flex;align-items:center;gap:10px;"> <div style="display:flex;align-items:center;gap:10px;">
<img src="/logo.jpg" alt="Bank Logo" style="height:50px;" /> <img src="/logo1.jpg" alt="Bank Logo" style="height:50px;" />
<h2 style="margin:0;">The Kangra Central Co Operative Bank</h2> <h2 style="margin:0;">The Kangra Central Co Operative Bank</h2>
</div> </div>
<div style="font-size:12px;color:#555;"> <div style="font-size:12px;color:#555;">

View File

@@ -38,7 +38,7 @@ export const generateInactiveUsersPDF = (
<div style="font-family:Arial, sans-serif; font-size:12px;"> <div style="font-family:Arial, sans-serif; font-size:12px;">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;"> <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">
<div style="display:flex;align-items:center;gap:10px;"> <div style="display:flex;align-items:center;gap:10px;">
<img src="/logo.jpg" alt="Bank Logo" style="height:50px;" /> <img src="/logo1.jpg" alt="Bank Logo" style="height:50px;" />
<h2 style="margin:0;">The Kangra Central Co Operative Bank</h2> <h2 style="margin:0;">The Kangra Central Co Operative Bank</h2>
</div> </div>
<div style="font-size:12px;color:#555;"> <div style="font-size:12px;color:#555;">

View File

@@ -77,7 +77,7 @@ export const generatePDF = (
padding-bottom:12px; padding-bottom:12px;
margin-bottom:15px; margin-bottom:15px;
"> ">
<img src="/logo.jpg" style="height:55px;width:auto;" /> <img src="/logo1.jpg" style="height:55px;width:auto;" />
<div style="flex:1;"> <div style="flex:1;">
<h2 style="margin:0 0 3px 0;font-size:18px;color:#1a5f3a;letter-spacing:0.3px;"> <h2 style="margin:0 0 3px 0;font-size:18px;color:#1a5f3a;letter-spacing:0.3px;">
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD. THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -11,7 +11,7 @@ import logo from '@/app/image/logo1.jpg';
import frontPage from '@/app/image/ib_front_3.jpg'; import frontPage from '@/app/image/ib_front_3.jpg';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { generateCaptcha } from '@/app/captcha'; import { generateCaptcha } from '@/app/captcha';
import { IconRefresh, IconShieldLockFilled } from "@tabler/icons-react"; import { IconAlertCircle, IconLock, IconPhone, IconRefresh, IconShieldLockFilled, IconUser } from "@tabler/icons-react";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { fetchAndStoreUserName } from "../_util/userdetails"; import { fetchAndStoreUserName } from "../_util/userdetails";
@@ -470,7 +470,7 @@ export default function Login() {
style={{ width: "60px", height: "auto" }} style={{ width: "60px", height: "auto" }}
/> />
<div> <div>
<Title order={3} ref={headerRef} style={{ fontFamily: "Roboto", color: "white", marginBottom: 2 }}> <Title order={3} ref={headerRef} style={{ fontFamily: "Roboto", color: "white", marginBottom: 2 }}>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD. THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title> </Title>
<Text size="xs" c="white" style={{ opacity: 0.85 }}> <Text size="xs" c="white" style={{ opacity: 0.85 }}>
@@ -479,17 +479,16 @@ export default function Login() {
</div> </div>
</Group> </Group>
</Box> </Box>
<div >
<div style={{ marginTop: '10px' }}>
{/* Movable text */} {/* Movable text */}
<Box <Box
style={{ style={{
width: "100%", width: "100%",
height: "0.5%",
overflow: "hidden", overflow: "hidden",
background: "linear-gradient(90deg, #cef7e3ff 0%, #82e8b8ff 100%)",
whiteSpace: "nowrap", whiteSpace: "nowrap",
padding: "8px 0", padding: "8px 0",
// borderBottom: "2px solid #3a95bcff"
}} }}
> >
<Text <Text
@@ -523,9 +522,9 @@ export default function Login() {
<div style={{ <div style={{
display: "flex", height: "75vh", overflow: "hidden", position: "relative", display: "flex", height: "75vh", overflow: "hidden", position: "relative",
// background: 'linear-gradient(to right, #02081eff, #0a3d91)' // background: 'linear-gradient(to right, #02081eff, #0a3d91)'
background: 'linear-gradient(179deg,rgba(1, 13, 18, 1) 49%, rgba(77, 82, 79, 1) 87%)' background: 'linear-gradient(179deg,rgba(92, 175, 210, 1) 49%, rgba(77, 82, 79, 1) 87%)'
}}> }}>
<div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}> <Box style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
<Image <Image
fit="cover" fit="cover"
src={frontPage} src={frontPage}
@@ -533,7 +532,7 @@ export default function Login() {
alt="ebanking" alt="ebanking"
style={{ width: "100%", height: "100%" }} style={{ width: "100%", height: "100%" }}
/> />
</div> </Box>
<Box <Box
w={{ base: "100%", md: "45%" }} w={{ base: "100%", md: "45%" }}
p="lg" p="lg"
@@ -559,9 +558,13 @@ export default function Login() {
}} }}
> >
<form onSubmit={handleLogin}> <form onSubmit={handleLogin}>
{/* <Title order={3} style={{ color: "#0a7228", textAlign: "center" }}>
Internet Banking Login
</Title> */}
<TextInput <TextInput
label="User ID / User Name" label="User ID / User Name"
placeholder="Enter your CIF No / User Name" placeholder="Enter your CIF No / User Name"
leftSection={<IconUser size={18} />}
value={CIF} value={CIF}
onInput={(e) => { onInput={(e) => {
// const input = e.currentTarget.value.replace(/\D/g, ""); // const input = e.currentTarget.value.replace(/\D/g, "");
@@ -576,6 +579,7 @@ export default function Login() {
<PasswordInput <PasswordInput
label="Password" label="Password"
placeholder="Enter your password" placeholder="Enter your password"
leftSection={<IconLock size={18} />}
value={psw} value={psw}
onChange={(e) => SetPsw(e.currentTarget.value)} onChange={(e) => SetPsw(e.currentTarget.value)}
withAsterisk withAsterisk
@@ -584,32 +588,49 @@ export default function Login() {
readOnly={isLogging} readOnly={isLogging}
// mt="sm" // mt="sm"
/> />
<Box style={{ textAlign: "right" }}> <Box style={{ textAlign: "right", marginTop: "0.5rem" }}>
{/* <Anchor <Anchor
style={{ fontSize: "14px", color: "#1c7ed6", cursor: "pointer" }} style={{ fontSize: "14px", color: "#1c7ed6", cursor: "pointer" }}
onClick={() => router.push("/ValidateUser")} onClick={() => router.push("/ValidateUser")}
> >
Forgot Password? Forgot Password?
</Anchor> */} </Anchor>
</Box> </Box>
<Group align="center"> <Group align="center">
<Box style={{ <Box style={{
backgroundColor: "#fff", fontSize: "18px", textDecoration: "line-through", padding: "4px 8px", fontFamily: "Verdana", 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", userSelect: "none",
pointerEvents: "none", textDecoration: "line-through"
}}
}}
onCopy={(e) => e.preventDefault()} onCopy={(e) => e.preventDefault()}
onContextMenu={(e) => e.preventDefault()} onContextMenu={(e) => e.preventDefault()}
> >
{captcha} {captcha}
</Box> </Box>
<Button
<Button size="xs" variant="light" onClick={regenerateCaptcha} disabled={otpRequired}>Refresh</Button> variant="light"
color="green"
onClick={regenerateCaptcha}
disabled={otpRequired}
leftSection={<IconRefresh size={16} />}
>
Refresh
</Button>
</Group> </Group>
<TextInput <TextInput
label="Enter CAPTCHA" label="Enter CAPTCHA"
placeholder="Enter above text" placeholder="Enter the text above"
value={inputCaptcha} value={inputCaptcha}
onChange={(e) => setInputCaptcha(e.currentTarget.value)} onChange={(e) => setInputCaptcha(e.currentTarget.value)}
withAsterisk withAsterisk
@@ -621,10 +642,11 @@ export default function Login() {
{otpRequired && ( {otpRequired && (
<Group align="end" gap="xs"> <Group align="end" gap="xs">
<PasswordInput <PasswordInput
label="Enter OTP" label="One-Time Password"
placeholder="Enter OTP" placeholder="Enter 6-digit OTP"
value={otp} value={otp}
maxLength={6} maxLength={6}
leftSection={<IconPhone size={18} />}
onChange={(e) => setOtp(e.currentTarget.value)} onChange={(e) => setOtp(e.currentTarget.value)}
withAsterisk withAsterisk
style={{ flex: 1 }} style={{ flex: 1 }}
@@ -636,25 +658,33 @@ export default function Login() {
px={10} px={10}
disabled={isLogging || otpVerified} disabled={isLogging || otpVerified}
onClick={() => handleSendOtp(mobile)} onClick={() => handleSendOtp(mobile)}
leftSection={<IconRefresh size={20} />}
style={{ alignSelf: "flex-end", marginBottom: 4 }} style={{ alignSelf: "flex-end", marginBottom: 4 }}
> >
<IconRefresh size={20} /> Resend Resend
</Button> </Button>
</Tooltip> </Tooltip>
</Group> </Group>
)} )}
<Button type="submit" fullWidth mt="sm" loading={isLogging} disabled={isLogging}> <Button type="submit" fullWidth mt="sm" loading={isLogging} disabled={isLogging}>
{isLogging ? "Processing..." : buttonLabel} {isLogging ? "Processing..." : buttonLabel}
</Button> </Button>
<Box mt="xs"> <Box mt="xs"
<Text size="md"> style={{
<Text component="span" c="red" fw={600}>Note: </Text> background: "#cdffdfff",
<Text component="span" c="black"> borderRadius: "8px",
Existing users logging in to the new Internet Banking for the first time should use their CIF number to avoid login issues. border: "1px solid #42c442ff",
</Text> borderLeft: "4px solid #42c442ff"
</Text> }}>
<Group gap="xs" align="flex-start">
<IconAlertCircle size={20} color="#856404" style={{ marginTop: 1 }} />
<Box style={{ flex: 1 }}>
<Text size="sm" fw={600} c="#856404">Important Note</Text>
<Text size="sm" c="#151615ff" mt={4}>
Existing users logging in for the first time should use their CIF number to avoid login issues.
</Text>
</Box>
</Group>
</Box> </Box>
</form> </form>
</Card> </Card>
@@ -677,7 +707,6 @@ export default function Login() {
> >
https://kccbhp.bank.in/ https://kccbhp.bank.in/
</Anchor> </Anchor>
</Box> </Box>
</Flex> </Flex>
{/* Footer */} {/* Footer */}
@@ -704,6 +733,6 @@ export default function Login() {
</Box> </Box>
</div> </div>
</div> </div>
</Providers> </Providers >
); );
} }