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:
@@ -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>
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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}>
|
||||
@@ -254,9 +248,9 @@ const AddBeneficiary: React.FC = () => {
|
||||
// disabled={isVisibilityLocked}
|
||||
readOnly={isVisibilityLocked}
|
||||
required
|
||||
onCopy={(e) => e.preventDefault()}
|
||||
onPaste={(e) => e.preventDefault()}
|
||||
onCut={(e) => e.preventDefault()}
|
||||
onCopy={(e) => e.preventDefault()}
|
||||
onPaste={(e) => e.preventDefault()}
|
||||
onCut={(e) => e.preventDefault()}
|
||||
/>
|
||||
|
||||
{validationStatus === "error" && (
|
||||
|
@@ -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>
|
||||
|
@@ -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,142 +335,161 @@ 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" }}>
|
||||
<Stack gap="xs">
|
||||
<Group grow>
|
||||
<Select
|
||||
label="Select Debit Account Number"
|
||||
placeholder="Choose account number"
|
||||
data={accountOptions}
|
||||
value={selectedAccNo}
|
||||
onChange={setSelectedAccNo}
|
||||
withAsterisk
|
||||
readOnly={isVisibilityLocked}
|
||||
/>
|
||||
<TextInput
|
||||
label="Payee Account No"
|
||||
value={showPayeeAcc ? beneficiaryAcc : getFullMaskedAccount(beneficiaryAcc)}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
if (/^\d*$/.test(value)) {
|
||||
setBeneficiaryAcc(value);
|
||||
setShowPayeeAcc(true);
|
||||
}
|
||||
}}
|
||||
onBlur={() => setShowPayeeAcc(false)}
|
||||
onFocus={() => setShowPayeeAcc(true)}
|
||||
withAsterisk
|
||||
readOnly={isVisibilityLocked}
|
||||
/>
|
||||
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
|
||||
<Stack gap="xs">
|
||||
<Group grow>
|
||||
<Select
|
||||
label="Select Debit Account Number"
|
||||
placeholder="Choose account number"
|
||||
data={accountOptions}
|
||||
value={selectedAccNo}
|
||||
onChange={setSelectedAccNo}
|
||||
withAsterisk
|
||||
readOnly={isVisibilityLocked}
|
||||
/>
|
||||
<TextInput
|
||||
label="Payee Account No"
|
||||
value={showPayeeAcc ? beneficiaryAcc : getFullMaskedAccount(beneficiaryAcc)}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
if (/^\d*$/.test(value)) {
|
||||
setBeneficiaryAcc(value);
|
||||
setShowPayeeAcc(true);
|
||||
}
|
||||
}}
|
||||
onBlur={() => setShowPayeeAcc(false)}
|
||||
onFocus={() => setShowPayeeAcc(true)}
|
||||
withAsterisk
|
||||
readOnly={isVisibilityLocked}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Confirm Payee Account No"
|
||||
value={confirmBeneficiaryAcc}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
if (/^\d*$/.test(value)) {
|
||||
setConfirmBeneficiaryAcc(value);
|
||||
}
|
||||
}}
|
||||
onCopy={(e) => e.preventDefault()}
|
||||
onPaste={(e) => e.preventDefault()}
|
||||
onCut={(e) => e.preventDefault()}
|
||||
withAsterisk
|
||||
readOnly={isVisibilityLocked}
|
||||
/>
|
||||
<TextInput
|
||||
label="Confirm Payee Account No"
|
||||
value={confirmBeneficiaryAcc}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
if (/^\d*$/.test(value)) {
|
||||
setConfirmBeneficiaryAcc(value);
|
||||
}
|
||||
}}
|
||||
onCopy={(e) => e.preventDefault()}
|
||||
onPaste={(e) => e.preventDefault()}
|
||||
onCut={(e) => e.preventDefault()}
|
||||
withAsterisk
|
||||
readOnly={isVisibilityLocked}
|
||||
/>
|
||||
</Group>
|
||||
<Group justify="space-between" >
|
||||
<Text size="xs" c="green" style={{ visibility: selectedAccount ? "visible" : "hidden" }}>Available Balance :
|
||||
{selectedAccount ? selectedAccount.stAvailableBalance : 0}
|
||||
</Text>
|
||||
<Group justify="center">
|
||||
{validationStatus === "error" && <Text size="sm" fw={700} ta="right" c="red">{beneficiaryName}</Text>}
|
||||
</Group>
|
||||
<Group justify="space-between" >
|
||||
<Text size="xs" c="green" style={{ visibility: selectedAccount ? "visible" : "hidden" }}>Available Balance :
|
||||
{selectedAccount ? selectedAccount.stAvailableBalance : 0}
|
||||
</Text>
|
||||
<Group justify="center">
|
||||
{validationStatus === "error" && <Text size="sm" fw={700} ta="right" c="red">{beneficiaryName}</Text>}
|
||||
</Group>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Payee Name"
|
||||
value={validationStatus === "success" && beneficiaryName ? beneficiaryName : ""}
|
||||
disabled
|
||||
readOnly
|
||||
withAsterisk
|
||||
/>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Payee Name"
|
||||
value={validationStatus === "success" && beneficiaryName ? beneficiaryName : ""}
|
||||
disabled
|
||||
readOnly
|
||||
withAsterisk
|
||||
/>
|
||||
|
||||
<Select
|
||||
label="Payee Account Type"
|
||||
placeholder="Select type"
|
||||
data={["Savings", "Current"]}
|
||||
value={beneficiaryType}
|
||||
onChange={setBeneficiaryType}
|
||||
withAsterisk
|
||||
readOnly={showOtpField}
|
||||
/>
|
||||
<Select
|
||||
label="Payee Account Type"
|
||||
placeholder="Select type"
|
||||
data={["Savings", "Current"]}
|
||||
value={beneficiaryType}
|
||||
onChange={setBeneficiaryType}
|
||||
withAsterisk
|
||||
readOnly={showOtpField}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Amount"
|
||||
type="number"
|
||||
value={amount}
|
||||
onChange={(e) => setAmount(e.currentTarget.value)}
|
||||
error={
|
||||
selectedAccount && Number(amount) > Number(selectedAccount.stAvailableBalance) ?
|
||||
"Amount exceeds available balance" : false}
|
||||
withAsterisk
|
||||
readOnly={showOtpField}
|
||||
/>
|
||||
<TextInput
|
||||
label="Amount"
|
||||
type="number"
|
||||
value={amount}
|
||||
onChange={(e) => setAmount(e.currentTarget.value)}
|
||||
error={
|
||||
selectedAccount && Number(amount) > Number(selectedAccount.stAvailableBalance) ?
|
||||
"Amount exceeds available balance" : false}
|
||||
withAsterisk
|
||||
readOnly={showOtpField}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Remarks"
|
||||
placeholder="Enter remarks"
|
||||
value={remarks}
|
||||
onChange={(e) => setRemarks(e.currentTarget.value)}
|
||||
// withAsterisk
|
||||
readOnly={showOtpField}
|
||||
withAsterisk
|
||||
/>
|
||||
</Group>
|
||||
<Group grow>
|
||||
{showOtpField && (
|
||||
<TextInput
|
||||
label="Remarks"
|
||||
placeholder="Enter remarks"
|
||||
value={remarks}
|
||||
onChange={(e) => setRemarks(e.currentTarget.value)}
|
||||
// withAsterisk
|
||||
readOnly={showOtpField}
|
||||
withAsterisk
|
||||
/>
|
||||
</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 && (
|
||||
<TextInput
|
||||
label="Transaction Password"
|
||||
placeholder="Enter transaction password"
|
||||
type="password"
|
||||
value={txnPassword}
|
||||
onChange={(e) => setTxnPassword(e.currentTarget.value)}
|
||||
withAsterisk
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
{!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
|
||||
label="Transaction Password"
|
||||
placeholder="Enter transaction password"
|
||||
type="password"
|
||||
value={txnPassword}
|
||||
onChange={(e) => setTxnPassword(e.currentTarget.value)}
|
||||
withAsterisk
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
|
||||
<Group justify="flex-start">
|
||||
<Button variant="filled" color="blue" onClick={handleValidate} disabled={validationStatus === "success"}>
|
||||
Validate
|
||||
</Button>
|
||||
<Button
|
||||
variant="filled"
|
||||
color="blue"
|
||||
onClick={handleProceed}
|
||||
loading={isSubmitting}
|
||||
disabled={validationStatus !== "success"}
|
||||
>
|
||||
{!showTxnPassword && showOtpField ? "Validate the OTP" : showTxnPassword ? "Proceed to Pay" : "Proceed"}
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</div>
|
||||
<Group justify="flex-start">
|
||||
<Button variant="filled" color="blue" onClick={handleValidate} disabled={validationStatus === "success"}>
|
||||
Validate
|
||||
</Button>
|
||||
<Button
|
||||
variant="filled"
|
||||
color="blue"
|
||||
onClick={handleProceed}
|
||||
loading={isSubmitting}
|
||||
disabled={validationStatus !== "success"}
|
||||
>
|
||||
{!showTxnPassword && showOtpField ? "Validate the OTP" : showTxnPassword ? "Proceed to Pay" : "Proceed"}
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</div>
|
||||
{/* ) : (
|
||||
<div>
|
||||
<OutsideQuickPay />
|
||||
|
@@ -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'
|
||||
}}
|
||||
>
|
||||
|
@@ -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>
|
||||
|
@@ -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 */}
|
||||
|
@@ -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>
|
||||
|
@@ -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;
|
@@ -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>
|
||||
<TextInput
|
||||
placeholder="Enter above text"
|
||||
value={captchaInput}
|
||||
onChange={(e) => setCaptchaInput(e.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
{captchaError && <p style={{ color: 'red', fontSize: '12px' }}>{captchaError}</p>}
|
||||
</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)}
|
||||
withAsterisk
|
||||
readOnly={captchaValidate}
|
||||
/>
|
||||
<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>
|
||||
|
@@ -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;
|
@@ -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,14 +232,14 @@ 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'>
|
||||
<Text onClick={()=>router.push("/login")}
|
||||
style={{
|
||||
position: 'absolute', top: '1rem', right: '2rem', cursor: 'pointer', fontWeight: 500, color: '#7091ecff',textDecoration:'underline'
|
||||
}}> Skip now</Text>
|
||||
<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'
|
||||
}}> Skip now</Text>
|
||||
|
||||
<Title order={3}
|
||||
// @ts-ignore
|
||||
@@ -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>
|
||||
<TextInput
|
||||
placeholder="Enter above text"
|
||||
value={captchaInput}
|
||||
onChange={(e) => setCaptchaInput(e.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
{captchaError && <p style={{ color: 'red', fontSize: '12px' }}>{captchaError}</p>}
|
||||
</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)}
|
||||
withAsterisk
|
||||
mt="sm"
|
||||
readOnly={captchaValidate}
|
||||
/>
|
||||
<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>
|
||||
|
@@ -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
BIN
src/app/image/logo1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 76 KiB |
BIN
src/app/image/set_log_pass.jpg
Normal file
BIN
src/app/image/set_log_pass.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
BIN
src/app/image/set_tran_pass.jpg
Normal file
BIN
src/app/image/set_tran_pass.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
@@ -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}
|
||||
|
@@ -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={{
|
||||
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"
|
||||
}}>
|
||||
<Box
|
||||
style={{
|
||||
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
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'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,21 +252,20 @@ 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"}}>
|
||||
<Box style={{ textAlign: "right" }}>
|
||||
<Anchor
|
||||
style={{ fontSize: "14px", color: "#1c7ed6", cursor: "pointer" }}
|
||||
onClick={() => router.push("/ValidateUser")}
|
||||
onClick={() => router.push("/ValidateUser")}
|
||||
>
|
||||
Forgot Password?
|
||||
</Anchor>
|
||||
@@ -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>
|
||||
|
Reference in New Issue
Block a user