Wip: update the login page,

feat: update Otp in set login and transaction page.
Feat: Add validation for external account in add beneficiary.
This commit is contained in:
2025-08-14 17:05:21 +05:30
parent c9181881e0
commit 78426747e5
20 changed files with 687 additions and 474 deletions

View File

@@ -37,8 +37,8 @@ export default function Layout({ children }: { children: React.ReactNode }) {
}}
>
<Stack style={{ background: '#228be6', height: '10%', alignItems: 'center' }}>
<Text fw={700} fs="italic" c='white' style={{ textAlign: 'center', marginTop: '10px' }}>
Accounts
<Text fw={700} c='white' style={{ textAlign: 'center', marginTop: '10px' }}>
My Accounts
</Text>
</Stack>

View File

@@ -1,19 +1,9 @@
"use client";
import React, { useEffect, useState } from 'react';
import {
TextInput,
Button,
Select,
Title,
Paper,
Grid,
Group,
Radio,
Text,
PasswordInput,
} from '@mantine/core';
import { TextInput, Button, Grid, Text, PasswordInput } from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { useRouter } from "next/navigation";
const MockOthersAccountValidation =
[
@@ -31,8 +21,9 @@ const MockOthersAccountValidation =
},
]
const AddBeneficiaryOthers: React.FC = () => {
export default function AddBeneficiaryOthers() {
const router = useRouter();
const [authorized, setAuthorized] = useState<boolean | null>(null);
const [bankName, setBankName] = useState('');
const [ifsccode, setIfsccode] = useState('');
const [branchName, setBranchName] = useState('');
@@ -40,24 +31,28 @@ const AddBeneficiaryOthers: React.FC = () => {
const [confirmAccountNo, setConfirmAccountNo] = useState('');
const [nickName, setNickName] = useState('');
const [beneficiaryName, setBeneficiaryName] = useState<string | null>(null);
const [otp, setOtp] = useState('');
const [generatedOtp, setGeneratedOtp] = useState('');
const [otpSent, setOtpSent] = useState(false);
const [otpVerified, setOtpVerified] = useState(false);
const [validationStatus, setValidationStatus] = useState<'success' | 'error' | null>(null);
const [isVisibilityLocked, setIsVisibilityLocked] = useState(false);
const [showPayeeAcc, setShowPayeeAcc] = useState(true);
const getFullMaskedAccount = (acc: string) => { return "X".repeat(acc.length); };
useEffect(() => {
const token = localStorage.getItem("access_token");
if (!token) {
setAuthorized(false);
router.push("/login");
} else {
setAuthorized(true);
}
}, []);
useEffect(() => {
const ifscTrimmed = ifsccode.trim();
if (ifscTrimmed.length === 11) { // Only call API when IFSC is valid length
const fetchIfscDetails = async () => {
try {
@@ -115,15 +110,6 @@ const AddBeneficiaryOthers: React.FC = () => {
return;
}
// if ( !/^[A-Za-z ]{1,5}$/.test(bankName)) {
// notifications.show({
// color: "red",
// title: "Invalid Bank Name",
// message: "Use only alphabets/spaces, max 100 characters.",
// });
// return;
// }
const trimmedIfsc = ifsccode.trim().toUpperCase();
const isValidIfscCode = (code: string) => {
return /^[A-Z]{4}0[0-9]{6}$/.test(code);
@@ -161,12 +147,25 @@ const AddBeneficiaryOthers: React.FC = () => {
}
// Validation for now
try {
const matched = MockOthersAccountValidation.find(
(entry) => entry.stBenAccountNo === accountNo
);
// const matched = MockOthersAccountValidation.find(
// (entry) => entry.stBenAccountNo === accountNo
// );
if (matched) {
setBeneficiaryName(matched.stBenName);
const token = localStorage.getItem("access_token");
const response = await fetch(
`http://localhost:8080/api/beneficiary/validate/outside-bank?accountNo=${accountNo}&ifscCode=${ifsccode}&remitterName=""`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
}
);
const data = await response.json();
if (response.ok && data?.name) {
setBeneficiaryName(data.name);
setValidationStatus("success");
setIsVisibilityLocked(true);
setOtpSent(true);
@@ -190,55 +189,6 @@ const AddBeneficiaryOthers: React.FC = () => {
setBeneficiaryName("Something went wrong");
setValidationStatus("error");
}
// Later need to add api
// try {
// // API will be changed
// const token = localStorage.getItem("access_token");
// const response = await fetch(`/api/beneficiary/validate/within-bank?accountNumber=${accountNo}`, {
// method: "GET",
// headers: {
// "Content-Type": "application/json",
// Authorization: `Bearer ${token}`,
// },
// });
// const data = await response.json();
// if (response.ok && data?.name) {
// setBeneficiaryName(data.name);
// setValidationStatus("success");
// setIsVisibilityLocked(true);
// setOtpSent(true);
// await handleGenerateOtp();
// notifications.show({
// withBorder: true,
// color: "green",
// title: "OTP Sent",
// message: "OTP has been sent to your registered mobile number.",
// autoClose: 5000,
// });
// } else {
// setBeneficiaryName("Invalid beneficiary account number");
// setValidationStatus("error");
// setAccountNo("");
// setConfirmAccountNo("");
// }
// }
// catch (error) {
// setBeneficiaryName("Invalid beneficiary account number");
// setValidationStatus("error");
// notifications.show({
// withBorder: true,
// color: "red",
// title: "Error",
// message: "Could not validate account number.",
// autoClose: 5000,
// });
// }
};
const verifyOtp = () => {
@@ -271,6 +221,7 @@ const AddBeneficiaryOthers: React.FC = () => {
});
};
if (!authorized) return null;
return (
<Grid gutter="md">
@@ -278,9 +229,7 @@ const AddBeneficiaryOthers: React.FC = () => {
<TextInput
label="IFSC Code"
placeholder="e.g.,ABCD0123456"
//data={bankOptions}
value={ifsccode}
// onChange={(e) => setIfsccode(e.currentTarget.value)}
onChange={(e) => {
let val = e.currentTarget.value.toUpperCase();
val = val.replace(/[^A-Z0-9]/g, ""); // block special chars
@@ -305,8 +254,6 @@ const AddBeneficiaryOthers: React.FC = () => {
/>
</Grid.Col>
<Grid.Col span={4}>
<TextInput
label="Branch Name"
@@ -422,4 +369,4 @@ const AddBeneficiaryOthers: React.FC = () => {
);
};
export default AddBeneficiaryOthers;

View File

@@ -1,27 +1,20 @@
"use client";
import React, { useState } from 'react';
import {
TextInput,
Button,
Select,
Title,
Paper,
Grid,
Group,
Radio,
Text,
PasswordInput,
} from '@mantine/core';
import React, { useEffect, useState } from 'react';
import {TextInput,Button,Select,Title,Paper,Grid,Group,Radio,Text,PasswordInput} from '@mantine/core';
import { useRouter } from "next/navigation";
import { notifications } from '@mantine/notifications';
import AddBeneficiaryOthers from './addBeneficiaryOthers';
import { generateOTP } from '@/app/OTPGenerator';
const bankOptions = [
{ value: 'KCCB', label: 'KCCB - The Kangra Central Co-Operative Bank' },
];
const AddBeneficiary: React.FC = () => {
const router = useRouter();
const [bankName, setBankName] = useState('');
const [authorized, setAuthorized] = useState<boolean | null>(null);
const [bankType, setBankType] = useState('own');
const [accountNo, setAccountNo] = useState('');
const [confirmAccountNo, setConfirmAccountNo] = useState('');
@@ -37,11 +30,20 @@ const AddBeneficiary: React.FC = () => {
const getFullMaskedAccount = (acc: string) => { return "X".repeat(acc.length); };
const handleGenerateOtp = async () => {
// const value = await generateOTP(6);
const value = "123456"; // Or generate a random OTP
setGeneratedOtp(value);
return value;
};
useEffect(() => {
const token = localStorage.getItem("access_token");
if (!token) {
setAuthorized(false);
router.push("/login");
} else {
setAuthorized(true);
}
}, []);
// const isValidBankName = (name: string) => {
// const regex = /^[A-Za-z\s]{3,5}$/;
// return regex.test(name.trim());
@@ -51,8 +53,6 @@ const AddBeneficiary: React.FC = () => {
// return /^[A-Z]{4}0[0-9]{6}$/.test(code);
// };
const validateAndSendOtp = async () => {
if (!bankName || !accountNo || !confirmAccountNo) {
notifications.show({
@@ -86,10 +86,6 @@ const AddBeneficiary: React.FC = () => {
// return;
// }
if (accountNo.length < 10 || accountNo.length > 17) {
notifications.show({
withBorder: true,
@@ -101,9 +97,6 @@ const AddBeneficiary: React.FC = () => {
return;
}
if (accountNo !== confirmAccountNo) {
notifications.show({
withBorder: true,
@@ -193,6 +186,7 @@ const AddBeneficiary: React.FC = () => {
});
};
if (!authorized) return null;
return (
<Paper shadow="sm" radius="md" p="md" withBorder h={400}>

View File

@@ -38,7 +38,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
}}
>
<Stack style={{ background: '#228be6', height: '10%', alignItems: 'center' }}>
<Text fw={700} fs="italic" c='white' style={{ textAlign: 'center', marginTop: '10px' }}>
<Text fw={700} c='white' style={{ textAlign: 'center', marginTop: '10px' }}>
Send Money
</Text>
</Stack>

View File

@@ -6,6 +6,7 @@ import { notifications } from "@mantine/notifications";
import { useRouter } from "next/navigation";
import { generateOTP } from '@/app/OTPGenerator';
import OutsideQuickPay from "./outside_quick_pay";
import { IconRefresh } from "@tabler/icons-react";
interface accountData {
stAccountNo: string;
@@ -34,6 +35,8 @@ export default function QuickPay() {
const [validationStatus, setValidationStatus] = useState<"success" | "error" | null>(null);
const [beneficiaryName, setBeneficiaryName] = useState<string | null>(null);
const [showOtpField, setShowOtpField] = useState(false);
const [countdown, setCountdown] = useState(60);
const [timerActive, setTimerActive] = useState(false);
const [otp, setOtp] = useState("");
const [generateOtp, setGenerateOtp] = useState("");
@@ -41,6 +44,8 @@ export default function QuickPay() {
// const value = await generateOTP(6);
const value = "123456";
setGenerateOtp(value);
setCountdown(60);
setTimerActive(true);
return value;
}
@@ -94,6 +99,22 @@ export default function QuickPay() {
}
}, [authorized]);
useEffect(() => {
let interval: number | undefined;
if (timerActive && countdown > 0) {
interval = window.setInterval(() => {
setCountdown((prev) => prev - 1);
}, 1000);
}
if (countdown === 0) {
if (interval) clearInterval(interval);
setTimerActive(false);
}
return () => {
if (interval) clearInterval(interval);
};
}, [timerActive, countdown]);
async function handleValidate() {
if (!selectedAccNo || !beneficiaryAcc ||
!confirmBeneficiaryAcc
@@ -257,6 +278,7 @@ export default function QuickPay() {
color: "red",
});
} finally {
setValidationStatus(null);
setSelectedAccNo(null);
setBeneficiaryAcc('');
setBeneficiaryName('');
@@ -313,7 +335,7 @@ export default function QuickPay() {
{/* main content */}
<Paper shadow="sm" radius="md" p="md" withBorder h={400}>
<Title order={3} mb="md">
Quick Pay
Quick Pay - Own Bank
</Title>
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
@@ -411,15 +433,34 @@ export default function QuickPay() {
</Group>
<Group grow>
{showOtpField && (
<>
<PasswordInput
label="OTP"
placeholder="Enter OTP"
type="otp"
value={otp}
maxLength={6}
onChange={(e) => setOtp(e.currentTarget.value)}
withAsterisk
disabled={showTxnPassword}
/>
{!showTxnPassword && (
timerActive ? (
<Text size="xs" c="dimmed">
Resend OTP will be enabled in 00:{countdown < 10 ? `0${countdown}` : countdown} min
</Text>
) : (
<Button
variant="subtle"
px={8}
onClick={handleGenerateOtp}
leftSection={<IconRefresh size={16} />}
>
Resend
</Button>
)
)}
</>
)}
{showTxnPassword && (
<TextInput

View File

@@ -143,7 +143,7 @@ export default function Home() {
{/* Loan Account Card */}
<Paper p="md" radius="md" style={{
backgroundColor: '#c1e0f0', width: 350, height: 195, display: 'flex',
backgroundColor: '#c1e0f0', width: 355, height: 195, display: 'flex',
flexDirection: 'column', justifyContent: 'space-between'
}}
>

View File

@@ -5,7 +5,7 @@ import { IconBook, IconCurrencyRupee, IconHome, IconLogout, IconPhoneFilled, Ico
import Link from 'next/link';
import { useRouter, usePathname } from "next/navigation";
import { Providers } from '../providers';
import logo from '@/app/image/logo.jpg';
import logo from '@/app/image/logo1.jpg';
import NextImage from 'next/image';
import { notifications } from '@mantine/notifications';
@@ -25,7 +25,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
async function handleFetchUserName() {
try {
const token = localStorage.getItem("access_token");
const response = await fetch('api/customer', {
const response = await fetch('/api/customer', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
@@ -67,7 +67,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
async function handleFetchUserDetails(e: React.FormEvent) {
e.preventDefault();
const token = localStorage.getItem("access_token");
const response = await fetch('api/auth/user_details', {
const response = await fetch('/api/auth/user_details', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
@@ -124,7 +124,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
width: '100%',
display: "flex",
justifyContent: "flex-start",
background: "linear-gradient(15deg,rgba(2, 163, 85, 1) 55%, rgba(101, 101, 184, 1) 100%)",
background: "linear-gradient(15deg,rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
}}
>
<Image
@@ -134,6 +134,19 @@ export default function RootLayout({ children }: { children: React.ReactNode })
alt="ebanking"
style={{ width: "100%", height: "100%" }}
/>
<Title
order={2}
style={{
fontFamily: 'Roboto',
position: 'absolute',
top: '30%',
left: '6%',
color: 'White',
transition: "opacity 0.5s ease-in-out",
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text
style={{
position: 'absolute',
@@ -173,7 +186,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<Link key={item.href} href={item.href}>
<Button
leftSection={<Icon size={20} />}
variant={isActive ? "light" : "subtle"}
variant={isActive ? "dark" : "subtle"}
color={isActive ? "blue" : undefined}
>
{item.label}
@@ -213,7 +226,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
}}
>
<Text c="dimmed" size="xs">
© 2025 Kangra Central Co-Operative Bank
© 2025 The Kangra Central Co-Operative Bank
</Text>
</Box>
</div>

View File

@@ -14,7 +14,7 @@ import {
} from "@mantine/core";
import { notifications } from "@mantine/notifications";
import { IconEye, IconEyeOff, IconLock } from "@tabler/icons-react";
import CaptchaImage from "@/app/SetPassword/CaptchaImage";
// import CaptchaImage from "@/app/SetPassword/CaptchaImage";
import { generateCaptcha } from "@/app/captcha";
const ChangePassword: React.FC = () => {
@@ -193,7 +193,7 @@ const ChangePassword: React.FC = () => {
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 5 }}>
{/* CAPTCHA Image */}
<div style={{ display: 'flex', alignItems: 'center', height: 30 }}>
<CaptchaImage text={captcha} />
{/* <CaptchaImage text={captcha} /> */}
</div>
{/* Refresh Button */}

View File

@@ -38,7 +38,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
}}
>
<Stack style={{ background: '#228be6', height: '10%', alignItems: 'center' }}>
<Text fw={700} fs="italic" c='white' style={{ textAlign: 'center', marginTop: '10px' }}>
<Text fw={700} c='white' style={{ textAlign: 'center', marginTop: '10px' }}>
Settings
</Text>
</Stack>

View File

@@ -1,23 +0,0 @@
import React, { useEffect, useRef } from 'react';
const CaptchaImage = ({ text }: { text: string }) => {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas?.getContext('2d');
if (canvas && ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.font = '26px Arial';
ctx.fillStyle = '#000';
ctx.setTransform(1, 0.1, -0.1, 1, 0, 0);
ctx.fillText(text, 10, 30);
}
}, [text]);
return <canvas ref={canvasRef} width={120} height={40} />;
};
export default CaptchaImage;

View File

@@ -1,14 +1,15 @@
"use client";
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, Group } 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/logo.jpg';
import changePwdImage from '@/app/image/changepw.png';
import CaptchaImage from './CaptchaImage';
import { IconEye, IconEyeOff, IconLock, IconLogout } from '@tabler/icons-react';
import logo from '@/app/image/logo1.jpg';
import changePwdImage from '@/app/image/set_log_pass.jpg';
import { IconLock, IconLogout, IconRefresh } from '@tabler/icons-react';
import { generateCaptcha } from '@/app/captcha';
import { generateOTP } from "../OTPGenerator";
export default function SetLoginPwd() {
const router = useRouter();
@@ -16,33 +17,35 @@ export default function SetLoginPwd() {
const [captcha, setCaptcha] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [captchaInput, setCaptchaInput] = useState('');
const [captchaError, setCaptchaError] = useState('');
const [confirmVisible, setConfirmVisible] = useState(false);
const toggleConfirmVisibility = () => setConfirmVisible((v) => !v);
const [captchaInput, setCaptchaInput] = useState("");
const [captchaValidate, setCaptchaValidate] = useState(false);
const [otp, setOtp] = useState("");
const [countdown, setCountdown] = useState(60);
const [timerActive, setTimerActive] = useState(false);
const icon = <IconLock size={18} stroke={1.5} />;
const [generateOtp, setGenerateOtp] = useState("");
async function handleGenerateOtp() {
// const value = await generateOTP(6);
const value = "123456";
setGenerateOtp(value);
setCountdown(60);
setTimerActive(true);
// return value;
}
async function handleLogout(e: React.FormEvent) {
e.preventDefault();
localStorage.removeItem("access_token");
router.push("/login")
}
useEffect(() => {
generateCaptcha();
}, []);
const generateCaptcha = () => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < 6; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
setCaptcha(result);
setCaptchaInput('');
setCaptchaError('');
const regenerateCaptcha = () => {
const loadCaptcha = async () => {
const newCaptcha = await generateCaptcha();
setCaptcha(newCaptcha);
};
loadCaptcha();
setCaptchaInput("");
};
async function handleSetLoginPassword(e: React.FormEvent) {
e.preventDefault();
const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
@@ -50,36 +53,72 @@ export default function SetLoginPwd() {
notifications.show({
withBorder: true,
color: "red",
title: "Both password fields are required.",
message: "Both password fields are required.",
title: "Field Required",
message: "Password and Confirm Password Both fields are required.",
autoClose: 5000,
});
return;
// alert("Both password fields are required.");
} else if (password !== confirmPassword) {
// alert("Passwords do not match.");
}
if (!captchaInput) {
notifications.show({
withBorder: true,
color: "red",
title: "Passwords do not match.",
title: "Field Required",
message: "Please Enter Captcha details",
autoClose: 5000,
});
return;
}
if (password !== confirmPassword) {
notifications.show({
withBorder: true,
color: "red",
title: "Password Mismatch",
message: "Passwords do not match.",
autoClose: 5000,
});
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({
withBorder: true,
color: "red",
title: "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.",
title: "Invalid Password",
message: "Password must contain at least one capital letter, one number, one special character, and be 8-15 characters long.",
autoClose: 5000,
});
return;
}
else if (captchaInput !== captcha) {
setCaptchaError("Incorrect CAPTCHA.");
if (captchaInput !== captcha) {
notifications.show({
withBorder: true,
color: "red",
title: "Captcha Error",
message: "Please enter the correct captcha",
autoClose: 5000,
});
regenerateCaptcha();
return;
}
if (!captchaValidate) {
setCaptchaValidate(true);
handleGenerateOtp();
return;
}
if (!otp) {
notifications.show({
title: "Null Field",
message: "Please enter the OTP",
color: "red",
});
return;
}
if (otp !== generateOtp) {
notifications.show({
title: "Invalid OTP",
message: "The OTP entered does not match",
color: "red",
});
return;
}
const token = localStorage.getItem("access_token");
@@ -116,6 +155,29 @@ export default function SetLoginPwd() {
router.push("/login");
}
}
useEffect(() => {
const loadCaptcha = async () => {
const newCaptcha = await generateCaptcha();
setCaptcha(newCaptcha);
};
loadCaptcha();
}, []);
useEffect(() => {
let interval: number | undefined;
if (timerActive && countdown > 0) {
interval = window.setInterval(() => {
setCountdown((prev) => prev - 1);
}, 1000);
}
if (countdown === 0) {
if (interval) clearInterval(interval);
setTimerActive(false);
}
return () => {
if (interval) clearInterval(interval);
};
}, [timerActive, countdown]);
useEffect(() => {
const token = localStorage.getItem("access_token");
@@ -136,16 +198,28 @@ export default function SetLoginPwd() {
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
display: "flex",
justifyContent: "flex-start",
background: "linear-gradient(15deg,rgba(2, 163, 85, 1) 55%, rgba(101, 101, 184, 1) 100%)"
background: "linear-gradient(15deg,rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)"
}}>
<Image
// radius="md"
fit="cover"
src={logo}
component={NextImage}
alt="ebanking"
style={{ width: "100%", height: "100%" }}
/>
<Title
order={2}
style={{
fontFamily: 'Roboto',
position: 'absolute',
top: '30%',
left: '7%',
color: 'White',
transition: "opacity 0.5s ease-in-out",
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Button style={{
position: 'absolute',
top: '50%',
@@ -157,80 +231,101 @@ export default function SetLoginPwd() {
leftSection={<IconLogout color='white' />} variant="subtle" onClick={handleLogout}>Logout</Button>
</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 style={{ display: "flex", justifyContent: "center", alignItems: "center" }} bg="#80868989">
<Image h="85vh" w="100%" 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}
<Card p="xl" w="40vw" h='85vh'>
<Title order={4}
// @ts-ignore
align="center" mb="md">Set Login Password</Title>
<form onSubmit={handleSetLoginPassword}>
<PasswordInput
label="Login Password"
placeholder="Enter your password"
required
withAsterisk
id="loginPassword"
value={password}
minLength={8}
maxLength={15}
onChange={(e) => setPassword(e.currentTarget.value)}
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onCut={(e) => e.preventDefault()}
readOnly={captchaValidate}
/>
<PasswordInput
label="Confirm Login Password"
placeholder="Enter your password"
required
withAsterisk
rightSection={icon}
id="confirmPassword"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.currentTarget.value)}
type={confirmVisible ? 'text' : 'password'}
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onCut={(e) => e.preventDefault()}
readOnly={captchaValidate}
/>
{/* CAPTCHA */}
<div style={{ marginTop: 20 }}>
<label style={{ fontWeight: 600 }}>Enter CAPTCHA *</label>
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 5 }}>
<CaptchaImage text={captcha} />
<Button size="xs" variant="outline" onClick={generateCaptcha}>Refresh</Button>
</div>
<Group mt="sm" align="center">
<Box style={{ backgroundColor: "#fff", fontSize: "18px", textDecoration: "line-through", padding: "4px 8px", fontFamily: "cursive" }}>{captcha}</Box>
<Button size="xs" variant="light" onClick={regenerateCaptcha}>Refresh</Button>
</Group>
<TextInput
label="Enter CAPTCHA"
placeholder="Enter above text"
value={captchaInput}
onChange={(e) => setCaptchaInput(e.currentTarget.value)}
required
withAsterisk
readOnly={captchaValidate}
/>
{captchaError && <p style={{ color: 'red', fontSize: '12px' }}>{captchaError}</p>}
</div>
<Box style={{ height: 60 }}>
{captchaValidate && (
<Group gap="xs" align="flex-end">
<PasswordInput
label="Enter OTP"
placeholder="Enter the OTP"
value={otp}
maxLength={6}
onChange={(e) => setOtp(e.currentTarget.value)}
withAsterisk
style={{ flex: 1 }}
/>
{timerActive ? (
<Text size="xs" c="dimmed">
Resend OTP will be enabled in 00:{countdown < 10 ? `0${countdown}` : countdown} min
</Text>
) : (
<Button
variant="subtle"
px={8}
onClick={handleGenerateOtp}
leftSection={<IconRefresh size={16} />}
>
Resend
</Button>
)}
</Group>
)}
</Box>
<Button
type="submit"
fullWidth
mt="sm"
color="blue"
>
Set
{!captchaValidate ? "Validate" : "Set"}
</Button>
</form>
<br></br>
<Box
style={{
flex: 1,
borderLeft: '1px solid #ccc',
paddingLeft: 16,
minHeight: 90,
minHeight: 80,
gap: "sm"
}}
>
<Text size="sm">
<strong>Note:</strong> Password will contains minimum one alphabet, one digit, one special symbol and total 8 charecters.
<strong>Note:</strong> Password must contain at least one capital letter(A-Z), one digit(0-9), one special symbol(e.g.,@,#,$), and be 8-15 characters long.
</Text>
</Box>
</Card>
@@ -247,7 +342,7 @@ export default function SetLoginPwd() {
}}
>
<Text c="dimmed" size="xs">
© 2025 Kangra Central Co-Operative Bank
© 2025 The Kangra Central Co-Operative Bank
</Text>
</Box>
</div>

View File

@@ -1,24 +0,0 @@
import React, { useEffect, useRef } from 'react';
const CaptchaImage = ({ text }: { text: string }) => {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas?.getContext('2d');
if (canvas && ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.font = '26px Arial';
ctx.fillStyle = '#000';
ctx.setTransform(1, 0.1, -0.1, 1, 0, 0);
ctx.fillText(text, 10, 30);
}
}, [text]);
return <canvas ref={canvasRef} width={120} height={40} />;
};
export default CaptchaImage;

View File

@@ -1,14 +1,14 @@
"use client";
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, Group } 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/logo.jpg';
import changePwdImage from '@/app/image/changepw.png';
import CaptchaImage from './CaptchaImage';
import { IconEye, IconEyeOff, IconLock, IconLogout } from '@tabler/icons-react';
import logo from '@/app/image/logo1.jpg';
import changePwdImage from '@/app/image/set_tran_pass.jpg';
import { generateCaptcha } from '@/app/captcha';
import { IconLock, IconLogout, IconRefresh } from '@tabler/icons-react';
export default function SetTransactionPwd() {
const router = useRouter();
@@ -16,32 +16,59 @@ export default function SetTransactionPwd() {
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [captcha, setCaptcha] = useState("");
const [captchaInput, setCaptchaInput] = useState('');
const [captchaError, setCaptchaError] = useState('');
const [confirmVisible, setConfirmVisible] = useState(false);
const toggleConfirmVisibility = () => setConfirmVisible((v) => !v);
const [captchaInput, setCaptchaInput] = useState("");
const [captchaValidate, setCaptchaValidate] = useState(false);
const [otp, setOtp] = useState("");
const [countdown, setCountdown] = useState(60);
const [timerActive, setTimerActive] = useState(false);
const icon = <IconLock size={18} stroke={1.5} />;
const [generateOtp, setGenerateOtp] = useState("");
async function handleGenerateOtp() {
// const value = await generateOTP(6);
const value = "123456";
setGenerateOtp(value);
setCountdown(60);
setTimerActive(true);
}
async function handleLogout(e: React.FormEvent) {
e.preventDefault();
localStorage.removeItem("access_token");
router.push("/login")
}
const regenerateCaptcha = () => {
const loadCaptcha = async () => {
const newCaptcha = await generateCaptcha();
setCaptcha(newCaptcha);
};
loadCaptcha();
setCaptchaInput("");
};
useEffect(() => {
generateCaptcha();
const loadCaptcha = async () => {
const newCaptcha = await generateCaptcha();
setCaptcha(newCaptcha);
};
loadCaptcha();
}, []);
const generateCaptcha = () => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < 6; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
useEffect(() => {
let interval: number | undefined;
if (timerActive && countdown > 0) {
interval = window.setInterval(() => {
setCountdown((prev) => prev - 1);
}, 1000);
}
setCaptcha(result);
setCaptchaInput('');
setCaptchaError('');
if (countdown === 0) {
if (interval) clearInterval(interval);
setTimerActive(false);
}
return () => {
if (interval) clearInterval(interval);
};
}, [timerActive, countdown]);
async function handleSetTransactionPassword(e: React.FormEvent) {
e.preventDefault();
@@ -50,36 +77,72 @@ export default function SetTransactionPwd() {
notifications.show({
withBorder: true,
color: "red",
title: "Both password fields are required.",
title: "Field Required",
message: "Both password fields are required.",
autoClose: 5000,
});
return;
// alert("Both password fields are required.");
} else if (password !== confirmPassword) {
// alert("Passwords do not match.");
}
if (!captchaInput) {
notifications.show({
withBorder: true,
color: "red",
title: "Passwords do not match.",
title: "Field Required",
message: "Please Enter Captcha details",
autoClose: 5000,
});
return;
}
if (password !== confirmPassword) {
notifications.show({
withBorder: true,
color: "red",
title: "Password Mismatch",
message: "Passwords do not match.",
autoClose: 5000,
});
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({
withBorder: true,
color: "red",
title: "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.",
title: "Invalid Password",
message: "Password must contain at least one capital letter, one number, one special character, and be 8-15 characters long.",
autoClose: 5000,
});
return;
}
else if (captchaInput !== captcha) {
setCaptchaError("Incorrect CAPTCHA.");
if (captchaInput !== captcha) {
notifications.show({
withBorder: true,
color: "red",
title: "Captcha Error",
message: "Please enter the correct captcha",
autoClose: 5000,
});
regenerateCaptcha();
return;
}
if (!captchaValidate) {
setCaptchaValidate(true);
handleGenerateOtp();
return;
}
if (!otp) {
notifications.show({
title: "Null Field",
message: "Please enter the OTP",
color: "red",
});
return;
}
if (otp !== generateOtp) {
notifications.show({
title: "Invalid OTP",
message: "The OTP entered does not match",
color: "red",
});
return;
}
const token = localStorage.getItem("access_token");
@@ -116,7 +179,6 @@ export default function SetTransactionPwd() {
router.push("/login");
}
}
useEffect(() => {
const token = localStorage.getItem("access_token");
if (!token) {
@@ -136,16 +198,28 @@ export default function SetTransactionPwd() {
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
display: "flex",
justifyContent: "flex-start",
background: "linear-gradient(15deg,rgba(2, 163, 85, 1) 55%, rgba(101, 101, 184, 1) 100%)"
background: "linear-gradient(15deg,rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)"
}}>
<Image
// radius="md"
fit="cover"
src={logo}
component={NextImage}
alt="ebanking"
style={{ width: "100%", height: "100%" }}
/>
<Title
order={2}
style={{
fontFamily: 'Roboto',
position: 'absolute',
top: '30%',
left: '7%',
color: 'White',
transition: "opacity 0.5s ease-in-out",
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Button style={{
position: 'absolute',
top: '50%',
@@ -158,10 +232,10 @@ export default function SetTransactionPwd() {
</Button>
</Box>
<div>
<Box style={{ display: "flex", justifyContent: "center", alignItems: "center", columnGap: "5rem" }} bg="#c1e0f0">
<Box style={{ display: "flex", justifyContent: "center", alignItems: "center" }} bg="#80868989">
<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'>
<Card p="xl" w="40vw" h='85vh'>
<Text onClick={() => router.push("/login")}
style={{
position: 'absolute', top: '1rem', right: '2rem', cursor: 'pointer', fontWeight: 500, color: '#7091ecff', textDecoration: 'underline'
@@ -174,52 +248,71 @@ export default function SetTransactionPwd() {
<PasswordInput
label="Transaction Password"
placeholder="Enter your Transaction password"
required
withAsterisk
id="loginPassword"
value={password}
onChange={(e) => setPassword(e.currentTarget.value)}
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onCut={(e) => e.preventDefault()}
readOnly={captchaValidate}
/>
<PasswordInput
label="Confirm Transaction Password"
placeholder="Re-enter your Transaction password"
required
withAsterisk
id="confirmPassword"
rightSection={icon}
value={confirmPassword}
type={confirmVisible ? 'text' : 'password'}
// rightSection={
// <button
// type="button"
// onClick={toggleConfirmVisibility}
// style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'grey' }}
// >
// {confirmVisible ? <IconEyeOff size={18} /> : <IconEye size={18} />}
// </button>
// }
onChange={(e) => setConfirmPassword(e.currentTarget.value)}
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onCut={(e) => e.preventDefault()}
readOnly={captchaValidate}
/>
{/* CAPTCHA */}
<div style={{ marginTop: 20 }}>
<label style={{ fontWeight: 600 }}>Enter CAPTCHA *</label>
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 5 }}>
<CaptchaImage text={captcha} />
<Button size="xs" variant="outline" onClick={generateCaptcha}>Refresh</Button>
</div>
<Group mt="sm" align="center">
<Box style={{ backgroundColor: "#fff", fontSize: "18px", textDecoration: "line-through", padding: "4px 8px", fontFamily: "cursive" }}>{captcha}</Box>
<Button size="xs" variant="light" onClick={regenerateCaptcha}>Refresh</Button>
</Group>
<TextInput
label="Enter CAPTCHA"
placeholder="Enter above text"
value={captchaInput}
onChange={(e) => setCaptchaInput(e.currentTarget.value)}
required
withAsterisk
mt="sm"
readOnly={captchaValidate}
/>
{captchaError && <p style={{ color: 'red', fontSize: '12px' }}>{captchaError}</p>}
</div>
<Box style={{ height: 60 }}>
{captchaValidate && (
<Group gap="xs" align="flex-end">
<PasswordInput
label="Enter OTP"
placeholder="Enter the OTP"
value={otp}
maxLength={6}
onChange={(e) => setOtp(e.currentTarget.value)}
withAsterisk
style={{ flex: 1 }}
/>
{timerActive ? (
<Text size="xs" c="dimmed">
Resend OTP will be enabled in 00:{countdown < 10 ? `0${countdown}` : countdown} min
</Text>
) : (
<Button
variant="subtle"
px={8}
onClick={handleGenerateOtp}
leftSection={<IconRefresh size={16} />}
>
Resend
</Button>
)}
</Group>
)}
</Box>
<Button
type="submit"
fullWidth
@@ -228,10 +321,7 @@ export default function SetTransactionPwd() {
>
Set
</Button>
</form>
<br></br>
<Box
style={{
@@ -243,7 +333,7 @@ export default function SetTransactionPwd() {
}}
>
<Text size="sm">
<strong>Note:</strong> Password will contains minimum one alphabet, one digit, one special symbol and total 8 charecters.
<strong>Note:</strong> Password must contain at least one capital letter(A-Z), one digit(0-9), one special symbol(e.g.,@,#,$), and be 8-15 characters long.
</Text>
</Box>
</Card>

View File

@@ -12,6 +12,23 @@ export const KccbTheme = createTheme({
primaryColor: 'kccb-colors',
colors: {
'kccb-colors': KccbColors
}
// primaryColor: 'kccb-colors'
},
//Typography settings
fontFamily: "Inter, Roboto, sans-serif",
headings: {
fontFamily: "Inter, Roboto, sans-serif",
fontWeight: '700',
sizes: {
h1: { fontSize: "2.2rem", lineHeight: '1.2' },
h2: { fontSize: "1.8rem", lineHeight: '1.3' },
h3: { fontSize: "1.5rem", lineHeight: '1.35' },
},
},
fontSizes: {
xs: "0.75rem",
sm: "0.875rem",
md: "1rem",
lg: "1.125rem",
xl: "1.25rem",
},
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

BIN
src/app/image/logo1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View File

@@ -40,7 +40,7 @@ export default function CustomCarousel() {
}, [currentIndex]);
return (
<Box style={{ position: 'relative', width: '83%', overflow: 'hidden',backgroundColor:"white" }}>
<Box style={{ position: 'relative', width: '90%', overflow: 'hidden',backgroundColor:"white" }}>
{/* Scrollable container */}
<Box
ref={scrollRef}

View File

@@ -1,24 +1,25 @@
"use client";
import React, { useState, useEffect } from "react";
import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Flex, Box, Image, Anchor, Stack, Popover, ActionIcon } from "@mantine/core";
import React, { useState, useEffect, memo, useRef } from "react";
import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Flex, Box, Image, Anchor, Tooltip } 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/logo.jpg';
import logo from '@/app/image/logo1.jpg';
import frontPage from '@/app/image/ib_front.jpg';
import dynamic from 'next/dynamic';
import { generateCaptcha } from '@/app/captcha';
import { IconShieldLockFilled } from "@tabler/icons-react";
export default function Login() {
const router = useRouter();
const [error, setError] = useState<string | null>(null);
const [CIF, SetCIF] = useState("");
const [psw, SetPsw] = useState("");
const [captcha, setCaptcha] = useState("");
const [inputCaptcha, setInputCaptcha] = useState("");
const [isLogging, setIsLogging] = useState(false);
const ClientCarousel = dynamic(() => import('./clientCarousel'), { ssr: false });
const headerRef = useRef<HTMLHeadingElement>(null);
useEffect(() => {
const loadCaptcha = async () => {
@@ -42,7 +43,25 @@ export default function Login() {
e.preventDefault();
const onlyDigit = /^\d{11}$/;
if (!onlyDigit.test(CIF)) {
setError('Input value must be 11 digit');
// setError('Input value must be 11 digit');
notifications.show({
withBorder: true,
color: "red",
title: "Invalid UserId",
message: "UserID must be 11 digit",
autoClose: 5000,
});
return;
}
if (!inputCaptcha) {
notifications.show({
withBorder: true,
color: "red",
title: "Invalid Captcha",
message: "Please fill the Captcha filed",
autoClose: 5000,
});
return;
}
if (inputCaptcha !== captcha) {
notifications.show({
@@ -55,6 +74,16 @@ export default function Login() {
regenerateCaptcha();
return;
}
if (!CIF || !psw) {
notifications.show({
withBorder: true,
color: "red",
title: "Invalid Input",
message: "Please fill UserId and Password",
autoClose: 5000,
});
return;
}
const response = await fetch('api/auth/login', {
method: 'POST',
headers: {
@@ -90,38 +119,75 @@ export default function Login() {
});
}
}
useEffect(() => {
const headerData = [
"THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.",
"कांगड़ा केन्द्रीय सहकारी बैंक सीमित",
];
let index = 0;
const interval = setInterval(() => {
index = (index + 1) % headerData.length;
if (headerRef.current) {
headerRef.current.textContent = headerData[index];
}
}, 2000);
return () => clearInterval(interval);
}, []);
return (
<Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}>
{/* Header */}
<Box style={{
<Box
style={{
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
display: "flex",
justifyContent: "flex-start",
background: "linear-gradient(15deg,rgba(2, 163, 85, 1) 55%, rgba(101, 101, 184, 1) 100%)",
// border: "1px solid black"
background: "linear-gradient(15deg,rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
}}>
<Image
fit="cover"
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{ width: "40%", height: "100%", objectFit: "contain", marginLeft: 0 }}
style={{ width: "100%", height: "auto", flexShrink: 0 }}
/>
<Text
<Title ref={headerRef}
order={2}
style={{
fontFamily: 'Roboto',
position: 'absolute',
top: '50%',
left: '64%',
top: '30%',
left: '7%',
color: 'White',
transition: "opacity 0.5s ease-in-out",
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text size="sm" c="white"
style={{
backgroundColor: '#1f1f14',
fontFamily: 'Roboto',
position: 'absolute',
top: '59%',
left: '72%',
color: 'white',
textShadow: '1px 1px 2px blue',
}}
>
{/* <IconBuildingBank/> */}
Head Office : Dharmshala, District: Kangra(H.P), Pincode: 176215
Head Office : Dharmshala, District: Kangra(H.P), Pin: 176215
</Text>
{/* <Box style={{ position: "absolute", right: "1rem", top: "50%", transform: 'translateY(-50%)' }}>
<Tooltip
label='Head Office : Dharmshala, District: Kangra(H.P), Pin: 176215'
position="right"
withArrow>
<IconBuildingBank size={40} style={{ cursor: "pointer", color: "white" }} />
</Tooltip>
</Box> */}
</Box>
<div style={{ marginTop: '10px' }}>
{/* Movable text */}
<Box
@@ -148,7 +214,7 @@ export default function Login() {
KCC Bank never asks for User Id,Passwords and Pins through email or phone.
Be ware of Phishing mails with links to fake bank&apos;s websites asking for personal information are in circulation.
Please DO NOT Click on the links given in the emails asking for personal details like bank account number, user ID and password.
If you had shard your User Id and Password through such mails or links, please change your Password immediately.
If you had shared your User Id and Password through such mails or links, please change your Password immediately.
Inform the Bank/branch in which your account is maintained for resetting your password.
</Text>
<style>
@@ -164,8 +230,7 @@ export default function Login() {
<div style={{
display: "flex", height: "75vh", overflow: "hidden", position: "relative",
// background: 'linear-gradient(to right, #02081eff, #0a3d91)'
background:'linear-gradient(179deg,rgba(1, 13, 18, 1) 49%, rgba(181, 196, 187, 1) 87%)'
// background:'linear-gradient(179deg,rgba(1, 7, 10, 1) 48%, rgba(87, 94, 89, 1) 87%)'
background: 'linear-gradient(179deg,rgba(1, 13, 18, 1) 49%, rgba(77, 82, 79, 1) 87%)'
}}>
<div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
<Image
@@ -176,8 +241,8 @@ export default function Login() {
style={{ width: "100%", height: "100%" }}
/>
</div>
<Box w={{ base: "100%", md: "50%" }} p="lg">
<Card shadow="md" padding="xl" radius="md" style={{ maxWidth: 400, margin: "0 auto", height: '68vh' }}>
<Box w={{ base: "100%", md: "45%" }} p="lg">
<Card shadow="md" padding="xl" radius="md" style={{ maxWidth: 550, margin: "0 auto", height: '68vh' }}>
<form onSubmit={handleLogin}>
<TextInput
label="User ID"
@@ -187,15 +252,14 @@ export default function Login() {
const input = e.currentTarget.value.replace(/\D/g, "");
if (input.length <= 11) SetCIF(input);
}}
error={error}
required
withAsterisk
/>
<PasswordInput
label="Password"
placeholder="Enter your password"
value={psw}
onChange={(e) => SetPsw(e.currentTarget.value)}
required
withAsterisk
mt="sm"
/>
<Box style={{ textAlign: "right" }}>
@@ -209,14 +273,13 @@ export default function Login() {
<Group mt="sm" align="center">
<Box style={{ backgroundColor: "#fff", fontSize: "18px", textDecoration: "line-through", padding: "4px 8px", fontFamily: "cursive" }}>{captcha}</Box>
<Button size="xs" variant="light" onClick={regenerateCaptcha}>Refresh</Button>
</Group>
<TextInput
label="Enter CAPTCHA"
placeholder="Enter above text"
value={inputCaptcha}
onChange={(e) => setInputCaptcha(e.currentTarget.value)}
required
withAsterisk
mt="sm"
/>
<Button type="submit" fullWidth mt="md" disabled={isLogging}>
@@ -227,12 +290,12 @@ export default function Login() {
</Box>
</div>
{/* Carousel and Notes */}
<Flex direction={{ base: "column", md: "row" }} mt="lg" p="lg">
<Box w={{ base: "100%", md: "60%" }}>
<Flex direction={{ base: "column", md: "row" }} mt="md" px="md" py="sm" gap="sm">
<Box w={{ base: "100%", md: "85%" }}>
<ClientCarousel />
</Box>
<Box w={{ base: "100%", md: "40%" }} p="md" style={{ textAlign: "center" }}>
<Title order={2}>Security Notes :</Title>
<Box w={{ base: "100%", md: "25%" }} p="md" style={{ textAlign: "center", border: '1px solid #5c5c3d' }}>
<Title order={2}> <IconShieldLockFilled />Security Notes :</Title>
<Text mt="sm" size="md">When you Login, Your User Id and Password travels in an encrypted and highly secured mode.</Text>
<Text mt="sm" fs="italic">For more information on Products and Services, Please Visit</Text>
<Anchor href="http://www.kccb.in/"> http://www.kccb.in/</Anchor>