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' }}>
|
<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' }}>
|
||||||
Accounts
|
My Accounts
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
|
@@ -1,19 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import {
|
import { TextInput, Button, Grid, Text, PasswordInput } from '@mantine/core';
|
||||||
TextInput,
|
|
||||||
Button,
|
|
||||||
Select,
|
|
||||||
Title,
|
|
||||||
Paper,
|
|
||||||
Grid,
|
|
||||||
Group,
|
|
||||||
Radio,
|
|
||||||
Text,
|
|
||||||
PasswordInput,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { notifications } from '@mantine/notifications';
|
import { notifications } from '@mantine/notifications';
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
const MockOthersAccountValidation =
|
const MockOthersAccountValidation =
|
||||||
[
|
[
|
||||||
@@ -31,8 +21,9 @@ const MockOthersAccountValidation =
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export default function AddBeneficiaryOthers() {
|
||||||
const AddBeneficiaryOthers: React.FC = () => {
|
const router = useRouter();
|
||||||
|
const [authorized, setAuthorized] = useState<boolean | null>(null);
|
||||||
const [bankName, setBankName] = useState('');
|
const [bankName, setBankName] = useState('');
|
||||||
const [ifsccode, setIfsccode] = useState('');
|
const [ifsccode, setIfsccode] = useState('');
|
||||||
const [branchName, setBranchName] = useState('');
|
const [branchName, setBranchName] = useState('');
|
||||||
@@ -40,24 +31,28 @@ const AddBeneficiaryOthers: React.FC = () => {
|
|||||||
const [confirmAccountNo, setConfirmAccountNo] = useState('');
|
const [confirmAccountNo, setConfirmAccountNo] = useState('');
|
||||||
const [nickName, setNickName] = useState('');
|
const [nickName, setNickName] = useState('');
|
||||||
const [beneficiaryName, setBeneficiaryName] = useState<string | null>(null);
|
const [beneficiaryName, setBeneficiaryName] = useState<string | null>(null);
|
||||||
|
|
||||||
const [otp, setOtp] = useState('');
|
const [otp, setOtp] = useState('');
|
||||||
const [generatedOtp, setGeneratedOtp] = useState('');
|
const [generatedOtp, setGeneratedOtp] = useState('');
|
||||||
const [otpSent, setOtpSent] = useState(false);
|
const [otpSent, setOtpSent] = useState(false);
|
||||||
const [otpVerified, setOtpVerified] = useState(false);
|
const [otpVerified, setOtpVerified] = useState(false);
|
||||||
const [validationStatus, setValidationStatus] = useState<'success' | 'error' | null>(null);
|
const [validationStatus, setValidationStatus] = useState<'success' | 'error' | null>(null);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const [isVisibilityLocked, setIsVisibilityLocked] = useState(false);
|
const [isVisibilityLocked, setIsVisibilityLocked] = useState(false);
|
||||||
const [showPayeeAcc, setShowPayeeAcc] = useState(true);
|
const [showPayeeAcc, setShowPayeeAcc] = useState(true);
|
||||||
|
|
||||||
const getFullMaskedAccount = (acc: string) => { return "X".repeat(acc.length); };
|
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(() => {
|
useEffect(() => {
|
||||||
const ifscTrimmed = ifsccode.trim();
|
const ifscTrimmed = ifsccode.trim();
|
||||||
|
|
||||||
if (ifscTrimmed.length === 11) { // Only call API when IFSC is valid length
|
if (ifscTrimmed.length === 11) { // Only call API when IFSC is valid length
|
||||||
const fetchIfscDetails = async () => {
|
const fetchIfscDetails = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -115,15 +110,6 @@ const AddBeneficiaryOthers: React.FC = () => {
|
|||||||
return;
|
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 trimmedIfsc = ifsccode.trim().toUpperCase();
|
||||||
const isValidIfscCode = (code: string) => {
|
const isValidIfscCode = (code: string) => {
|
||||||
return /^[A-Z]{4}0[0-9]{6}$/.test(code);
|
return /^[A-Z]{4}0[0-9]{6}$/.test(code);
|
||||||
@@ -161,12 +147,25 @@ const AddBeneficiaryOthers: React.FC = () => {
|
|||||||
}
|
}
|
||||||
// Validation for now
|
// Validation for now
|
||||||
try {
|
try {
|
||||||
const matched = MockOthersAccountValidation.find(
|
// const matched = MockOthersAccountValidation.find(
|
||||||
(entry) => entry.stBenAccountNo === accountNo
|
// (entry) => entry.stBenAccountNo === accountNo
|
||||||
);
|
// );
|
||||||
|
|
||||||
if (matched) {
|
const token = localStorage.getItem("access_token");
|
||||||
setBeneficiaryName(matched.stBenName);
|
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");
|
setValidationStatus("success");
|
||||||
setIsVisibilityLocked(true);
|
setIsVisibilityLocked(true);
|
||||||
setOtpSent(true);
|
setOtpSent(true);
|
||||||
@@ -190,55 +189,6 @@ const AddBeneficiaryOthers: React.FC = () => {
|
|||||||
setBeneficiaryName("Something went wrong");
|
setBeneficiaryName("Something went wrong");
|
||||||
setValidationStatus("error");
|
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 = () => {
|
const verifyOtp = () => {
|
||||||
@@ -271,6 +221,7 @@ const AddBeneficiaryOthers: React.FC = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!authorized) return null;
|
||||||
return (
|
return (
|
||||||
<Grid gutter="md">
|
<Grid gutter="md">
|
||||||
|
|
||||||
@@ -278,9 +229,7 @@ const AddBeneficiaryOthers: React.FC = () => {
|
|||||||
<TextInput
|
<TextInput
|
||||||
label="IFSC Code"
|
label="IFSC Code"
|
||||||
placeholder="e.g.,ABCD0123456"
|
placeholder="e.g.,ABCD0123456"
|
||||||
//data={bankOptions}
|
|
||||||
value={ifsccode}
|
value={ifsccode}
|
||||||
// onChange={(e) => setIfsccode(e.currentTarget.value)}
|
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
let val = e.currentTarget.value.toUpperCase();
|
let val = e.currentTarget.value.toUpperCase();
|
||||||
val = val.replace(/[^A-Z0-9]/g, ""); // block special chars
|
val = val.replace(/[^A-Z0-9]/g, ""); // block special chars
|
||||||
@@ -305,8 +254,6 @@ const AddBeneficiaryOthers: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Grid.Col span={4}>
|
<Grid.Col span={4}>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Branch Name"
|
label="Branch Name"
|
||||||
@@ -422,4 +369,4 @@ const AddBeneficiaryOthers: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddBeneficiaryOthers;
|
|
||||||
|
@@ -1,27 +1,20 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import {
|
import {TextInput,Button,Select,Title,Paper,Grid,Group,Radio,Text,PasswordInput} from '@mantine/core';
|
||||||
TextInput,
|
import { useRouter } from "next/navigation";
|
||||||
Button,
|
|
||||||
Select,
|
|
||||||
Title,
|
|
||||||
Paper,
|
|
||||||
Grid,
|
|
||||||
Group,
|
|
||||||
Radio,
|
|
||||||
Text,
|
|
||||||
PasswordInput,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { notifications } from '@mantine/notifications';
|
import { notifications } from '@mantine/notifications';
|
||||||
import AddBeneficiaryOthers from './addBeneficiaryOthers';
|
import AddBeneficiaryOthers from './addBeneficiaryOthers';
|
||||||
|
import { generateOTP } from '@/app/OTPGenerator';
|
||||||
|
|
||||||
const bankOptions = [
|
const bankOptions = [
|
||||||
{ value: 'KCCB', label: 'KCCB - The Kangra Central Co-Operative Bank' },
|
{ value: 'KCCB', label: 'KCCB - The Kangra Central Co-Operative Bank' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const AddBeneficiary: React.FC = () => {
|
const AddBeneficiary: React.FC = () => {
|
||||||
|
const router = useRouter();
|
||||||
const [bankName, setBankName] = useState('');
|
const [bankName, setBankName] = useState('');
|
||||||
|
const [authorized, setAuthorized] = useState<boolean | null>(null);
|
||||||
const [bankType, setBankType] = useState('own');
|
const [bankType, setBankType] = useState('own');
|
||||||
const [accountNo, setAccountNo] = useState('');
|
const [accountNo, setAccountNo] = useState('');
|
||||||
const [confirmAccountNo, setConfirmAccountNo] = useState('');
|
const [confirmAccountNo, setConfirmAccountNo] = useState('');
|
||||||
@@ -37,11 +30,20 @@ const AddBeneficiary: React.FC = () => {
|
|||||||
const getFullMaskedAccount = (acc: string) => { return "X".repeat(acc.length); };
|
const getFullMaskedAccount = (acc: string) => { return "X".repeat(acc.length); };
|
||||||
|
|
||||||
const handleGenerateOtp = async () => {
|
const handleGenerateOtp = async () => {
|
||||||
|
// const value = await generateOTP(6);
|
||||||
const value = "123456"; // Or generate a random OTP
|
const value = "123456"; // Or generate a random OTP
|
||||||
setGeneratedOtp(value);
|
setGeneratedOtp(value);
|
||||||
return 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 isValidBankName = (name: string) => {
|
||||||
// const regex = /^[A-Za-z\s]{3,5}$/;
|
// const regex = /^[A-Za-z\s]{3,5}$/;
|
||||||
// return regex.test(name.trim());
|
// return regex.test(name.trim());
|
||||||
@@ -51,8 +53,6 @@ const AddBeneficiary: React.FC = () => {
|
|||||||
// return /^[A-Z]{4}0[0-9]{6}$/.test(code);
|
// return /^[A-Z]{4}0[0-9]{6}$/.test(code);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const validateAndSendOtp = async () => {
|
const validateAndSendOtp = async () => {
|
||||||
if (!bankName || !accountNo || !confirmAccountNo) {
|
if (!bankName || !accountNo || !confirmAccountNo) {
|
||||||
notifications.show({
|
notifications.show({
|
||||||
@@ -86,10 +86,6 @@ const AddBeneficiary: React.FC = () => {
|
|||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (accountNo.length < 10 || accountNo.length > 17) {
|
if (accountNo.length < 10 || accountNo.length > 17) {
|
||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
@@ -101,9 +97,6 @@ const AddBeneficiary: React.FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (accountNo !== confirmAccountNo) {
|
if (accountNo !== confirmAccountNo) {
|
||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
@@ -193,6 +186,7 @@ const AddBeneficiary: React.FC = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!authorized) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper shadow="sm" radius="md" p="md" withBorder h={400}>
|
<Paper shadow="sm" radius="md" p="md" withBorder h={400}>
|
||||||
@@ -254,9 +248,9 @@ const AddBeneficiary: React.FC = () => {
|
|||||||
// disabled={isVisibilityLocked}
|
// disabled={isVisibilityLocked}
|
||||||
readOnly={isVisibilityLocked}
|
readOnly={isVisibilityLocked}
|
||||||
required
|
required
|
||||||
onCopy={(e) => e.preventDefault()}
|
onCopy={(e) => e.preventDefault()}
|
||||||
onPaste={(e) => e.preventDefault()}
|
onPaste={(e) => e.preventDefault()}
|
||||||
onCut={(e) => e.preventDefault()}
|
onCut={(e) => e.preventDefault()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{validationStatus === "error" && (
|
{validationStatus === "error" && (
|
||||||
|
@@ -38,7 +38,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack style={{ background: '#228be6', height: '10%', alignItems: 'center' }}>
|
<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
|
Send Money
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@@ -6,6 +6,7 @@ import { notifications } from "@mantine/notifications";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { generateOTP } from '@/app/OTPGenerator';
|
import { generateOTP } from '@/app/OTPGenerator';
|
||||||
import OutsideQuickPay from "./outside_quick_pay";
|
import OutsideQuickPay from "./outside_quick_pay";
|
||||||
|
import { IconRefresh } from "@tabler/icons-react";
|
||||||
|
|
||||||
interface accountData {
|
interface accountData {
|
||||||
stAccountNo: string;
|
stAccountNo: string;
|
||||||
@@ -34,6 +35,8 @@ export default function QuickPay() {
|
|||||||
const [validationStatus, setValidationStatus] = useState<"success" | "error" | null>(null);
|
const [validationStatus, setValidationStatus] = useState<"success" | "error" | null>(null);
|
||||||
const [beneficiaryName, setBeneficiaryName] = useState<string | null>(null);
|
const [beneficiaryName, setBeneficiaryName] = useState<string | null>(null);
|
||||||
const [showOtpField, setShowOtpField] = useState(false);
|
const [showOtpField, setShowOtpField] = useState(false);
|
||||||
|
const [countdown, setCountdown] = useState(60);
|
||||||
|
const [timerActive, setTimerActive] = useState(false);
|
||||||
const [otp, setOtp] = useState("");
|
const [otp, setOtp] = useState("");
|
||||||
const [generateOtp, setGenerateOtp] = useState("");
|
const [generateOtp, setGenerateOtp] = useState("");
|
||||||
|
|
||||||
@@ -41,6 +44,8 @@ export default function QuickPay() {
|
|||||||
// const value = await generateOTP(6);
|
// const value = await generateOTP(6);
|
||||||
const value = "123456";
|
const value = "123456";
|
||||||
setGenerateOtp(value);
|
setGenerateOtp(value);
|
||||||
|
setCountdown(60);
|
||||||
|
setTimerActive(true);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +99,22 @@ export default function QuickPay() {
|
|||||||
}
|
}
|
||||||
}, [authorized]);
|
}, [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() {
|
async function handleValidate() {
|
||||||
if (!selectedAccNo || !beneficiaryAcc ||
|
if (!selectedAccNo || !beneficiaryAcc ||
|
||||||
!confirmBeneficiaryAcc
|
!confirmBeneficiaryAcc
|
||||||
@@ -257,6 +278,7 @@ export default function QuickPay() {
|
|||||||
color: "red",
|
color: "red",
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
|
setValidationStatus(null);
|
||||||
setSelectedAccNo(null);
|
setSelectedAccNo(null);
|
||||||
setBeneficiaryAcc('');
|
setBeneficiaryAcc('');
|
||||||
setBeneficiaryName('');
|
setBeneficiaryName('');
|
||||||
@@ -313,142 +335,161 @@ export default function QuickPay() {
|
|||||||
{/* main content */}
|
{/* main content */}
|
||||||
<Paper shadow="sm" radius="md" p="md" withBorder h={400}>
|
<Paper shadow="sm" radius="md" p="md" withBorder h={400}>
|
||||||
<Title order={3} mb="md">
|
<Title order={3} mb="md">
|
||||||
Quick Pay
|
Quick Pay - Own Bank
|
||||||
</Title>
|
</Title>
|
||||||
|
|
||||||
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
|
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
|
||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
<Group grow>
|
<Group grow>
|
||||||
<Select
|
<Select
|
||||||
label="Select Debit Account Number"
|
label="Select Debit Account Number"
|
||||||
placeholder="Choose account number"
|
placeholder="Choose account number"
|
||||||
data={accountOptions}
|
data={accountOptions}
|
||||||
value={selectedAccNo}
|
value={selectedAccNo}
|
||||||
onChange={setSelectedAccNo}
|
onChange={setSelectedAccNo}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
readOnly={isVisibilityLocked}
|
readOnly={isVisibilityLocked}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Payee Account No"
|
label="Payee Account No"
|
||||||
value={showPayeeAcc ? beneficiaryAcc : getFullMaskedAccount(beneficiaryAcc)}
|
value={showPayeeAcc ? beneficiaryAcc : getFullMaskedAccount(beneficiaryAcc)}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = e.currentTarget.value;
|
const value = e.currentTarget.value;
|
||||||
if (/^\d*$/.test(value)) {
|
if (/^\d*$/.test(value)) {
|
||||||
setBeneficiaryAcc(value);
|
setBeneficiaryAcc(value);
|
||||||
setShowPayeeAcc(true);
|
setShowPayeeAcc(true);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onBlur={() => setShowPayeeAcc(false)}
|
onBlur={() => setShowPayeeAcc(false)}
|
||||||
onFocus={() => setShowPayeeAcc(true)}
|
onFocus={() => setShowPayeeAcc(true)}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
readOnly={isVisibilityLocked}
|
readOnly={isVisibilityLocked}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Confirm Payee Account No"
|
label="Confirm Payee Account No"
|
||||||
value={confirmBeneficiaryAcc}
|
value={confirmBeneficiaryAcc}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = e.currentTarget.value;
|
const value = e.currentTarget.value;
|
||||||
if (/^\d*$/.test(value)) {
|
if (/^\d*$/.test(value)) {
|
||||||
setConfirmBeneficiaryAcc(value);
|
setConfirmBeneficiaryAcc(value);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onCopy={(e) => e.preventDefault()}
|
onCopy={(e) => e.preventDefault()}
|
||||||
onPaste={(e) => e.preventDefault()}
|
onPaste={(e) => e.preventDefault()}
|
||||||
onCut={(e) => e.preventDefault()}
|
onCut={(e) => e.preventDefault()}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
readOnly={isVisibilityLocked}
|
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>
|
||||||
<Group justify="space-between" >
|
</Group>
|
||||||
<Text size="xs" c="green" style={{ visibility: selectedAccount ? "visible" : "hidden" }}>Available Balance :
|
<Group grow>
|
||||||
{selectedAccount ? selectedAccount.stAvailableBalance : 0}
|
<TextInput
|
||||||
</Text>
|
label="Payee Name"
|
||||||
<Group justify="center">
|
value={validationStatus === "success" && beneficiaryName ? beneficiaryName : ""}
|
||||||
{validationStatus === "error" && <Text size="sm" fw={700} ta="right" c="red">{beneficiaryName}</Text>}
|
disabled
|
||||||
</Group>
|
readOnly
|
||||||
</Group>
|
withAsterisk
|
||||||
<Group grow>
|
/>
|
||||||
<TextInput
|
|
||||||
label="Payee Name"
|
|
||||||
value={validationStatus === "success" && beneficiaryName ? beneficiaryName : ""}
|
|
||||||
disabled
|
|
||||||
readOnly
|
|
||||||
withAsterisk
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
label="Payee Account Type"
|
label="Payee Account Type"
|
||||||
placeholder="Select type"
|
placeholder="Select type"
|
||||||
data={["Savings", "Current"]}
|
data={["Savings", "Current"]}
|
||||||
value={beneficiaryType}
|
value={beneficiaryType}
|
||||||
onChange={setBeneficiaryType}
|
onChange={setBeneficiaryType}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
readOnly={showOtpField}
|
readOnly={showOtpField}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Amount"
|
label="Amount"
|
||||||
type="number"
|
type="number"
|
||||||
value={amount}
|
value={amount}
|
||||||
onChange={(e) => setAmount(e.currentTarget.value)}
|
onChange={(e) => setAmount(e.currentTarget.value)}
|
||||||
error={
|
error={
|
||||||
selectedAccount && Number(amount) > Number(selectedAccount.stAvailableBalance) ?
|
selectedAccount && Number(amount) > Number(selectedAccount.stAvailableBalance) ?
|
||||||
"Amount exceeds available balance" : false}
|
"Amount exceeds available balance" : false}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
readOnly={showOtpField}
|
readOnly={showOtpField}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Remarks"
|
label="Remarks"
|
||||||
placeholder="Enter remarks"
|
placeholder="Enter remarks"
|
||||||
value={remarks}
|
value={remarks}
|
||||||
onChange={(e) => setRemarks(e.currentTarget.value)}
|
onChange={(e) => setRemarks(e.currentTarget.value)}
|
||||||
// withAsterisk
|
// withAsterisk
|
||||||
readOnly={showOtpField}
|
readOnly={showOtpField}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group grow>
|
<Group grow>
|
||||||
{showOtpField && (
|
{showOtpField && (
|
||||||
|
<>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label="OTP"
|
label="OTP"
|
||||||
placeholder="Enter OTP"
|
placeholder="Enter OTP"
|
||||||
type="otp"
|
type="otp"
|
||||||
value={otp}
|
value={otp}
|
||||||
|
maxLength={6}
|
||||||
onChange={(e) => setOtp(e.currentTarget.value)}
|
onChange={(e) => setOtp(e.currentTarget.value)}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
disabled={showTxnPassword}
|
disabled={showTxnPassword}
|
||||||
/>
|
/>
|
||||||
)}
|
{!showTxnPassword && (
|
||||||
{showTxnPassword && (
|
timerActive ? (
|
||||||
<TextInput
|
<Text size="xs" c="dimmed">
|
||||||
label="Transaction Password"
|
Resend OTP will be enabled in 00:{countdown < 10 ? `0${countdown}` : countdown} min
|
||||||
placeholder="Enter transaction password"
|
</Text>
|
||||||
type="password"
|
) : (
|
||||||
value={txnPassword}
|
<Button
|
||||||
onChange={(e) => setTxnPassword(e.currentTarget.value)}
|
variant="subtle"
|
||||||
withAsterisk
|
px={8}
|
||||||
/>
|
onClick={handleGenerateOtp}
|
||||||
)}
|
leftSection={<IconRefresh size={16} />}
|
||||||
</Group>
|
>
|
||||||
|
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">
|
<Group justify="flex-start">
|
||||||
<Button variant="filled" color="blue" onClick={handleValidate} disabled={validationStatus === "success"}>
|
<Button variant="filled" color="blue" onClick={handleValidate} disabled={validationStatus === "success"}>
|
||||||
Validate
|
Validate
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="filled"
|
variant="filled"
|
||||||
color="blue"
|
color="blue"
|
||||||
onClick={handleProceed}
|
onClick={handleProceed}
|
||||||
loading={isSubmitting}
|
loading={isSubmitting}
|
||||||
disabled={validationStatus !== "success"}
|
disabled={validationStatus !== "success"}
|
||||||
>
|
>
|
||||||
{!showTxnPassword && showOtpField ? "Validate the OTP" : showTxnPassword ? "Proceed to Pay" : "Proceed"}
|
{!showTxnPassword && showOtpField ? "Validate the OTP" : showTxnPassword ? "Proceed to Pay" : "Proceed"}
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</div>
|
</div>
|
||||||
{/* ) : (
|
{/* ) : (
|
||||||
<div>
|
<div>
|
||||||
<OutsideQuickPay />
|
<OutsideQuickPay />
|
||||||
|
@@ -143,7 +143,7 @@ export default function Home() {
|
|||||||
|
|
||||||
{/* Loan Account Card */}
|
{/* Loan Account Card */}
|
||||||
<Paper p="md" radius="md" style={{
|
<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'
|
flexDirection: 'column', justifyContent: 'space-between'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@@ -5,7 +5,7 @@ import { IconBook, IconCurrencyRupee, IconHome, IconLogout, IconPhoneFilled, Ico
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter, usePathname } from "next/navigation";
|
import { useRouter, usePathname } from "next/navigation";
|
||||||
import { Providers } from '../providers';
|
import { Providers } from '../providers';
|
||||||
import logo from '@/app/image/logo.jpg';
|
import logo from '@/app/image/logo1.jpg';
|
||||||
import NextImage from 'next/image';
|
import NextImage from 'next/image';
|
||||||
import { notifications } from '@mantine/notifications';
|
import { notifications } from '@mantine/notifications';
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|||||||
async function handleFetchUserName() {
|
async function handleFetchUserName() {
|
||||||
try {
|
try {
|
||||||
const token = localStorage.getItem("access_token");
|
const token = localStorage.getItem("access_token");
|
||||||
const response = await fetch('api/customer', {
|
const response = await fetch('/api/customer', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -67,7 +67,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|||||||
async function handleFetchUserDetails(e: React.FormEvent) {
|
async function handleFetchUserDetails(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const token = localStorage.getItem("access_token");
|
const token = localStorage.getItem("access_token");
|
||||||
const response = await fetch('api/auth/user_details', {
|
const response = await fetch('/api/auth/user_details', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -124,7 +124,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "flex-start",
|
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
|
<Image
|
||||||
@@ -134,6 +134,19 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|||||||
alt="ebanking"
|
alt="ebanking"
|
||||||
style={{ width: "100%", height: "100%" }}
|
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
|
<Text
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -173,7 +186,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|||||||
<Link key={item.href} href={item.href}>
|
<Link key={item.href} href={item.href}>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<Icon size={20} />}
|
leftSection={<Icon size={20} />}
|
||||||
variant={isActive ? "light" : "subtle"}
|
variant={isActive ? "dark" : "subtle"}
|
||||||
color={isActive ? "blue" : undefined}
|
color={isActive ? "blue" : undefined}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
@@ -213,7 +226,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text c="dimmed" size="xs">
|
<Text c="dimmed" size="xs">
|
||||||
© 2025 Kangra Central Co-Operative Bank
|
© 2025 The Kangra Central Co-Operative Bank
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -14,7 +14,7 @@ import {
|
|||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { notifications } from "@mantine/notifications";
|
import { notifications } from "@mantine/notifications";
|
||||||
import { IconEye, IconEyeOff, IconLock } from "@tabler/icons-react";
|
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";
|
import { generateCaptcha } from "@/app/captcha";
|
||||||
|
|
||||||
const ChangePassword: React.FC = () => {
|
const ChangePassword: React.FC = () => {
|
||||||
@@ -193,7 +193,7 @@ const ChangePassword: React.FC = () => {
|
|||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 5 }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 5 }}>
|
||||||
{/* CAPTCHA Image */}
|
{/* CAPTCHA Image */}
|
||||||
<div style={{ display: 'flex', alignItems: 'center', height: 30 }}>
|
<div style={{ display: 'flex', alignItems: 'center', height: 30 }}>
|
||||||
<CaptchaImage text={captcha} />
|
{/* <CaptchaImage text={captcha} /> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Refresh Button */}
|
{/* Refresh Button */}
|
||||||
|
@@ -38,7 +38,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack style={{ background: '#228be6', height: '10%', alignItems: 'center' }}>
|
<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
|
Settings
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</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";
|
"use client";
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image } from "@mantine/core";
|
import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image, Group } from "@mantine/core";
|
||||||
import { notifications } from "@mantine/notifications";
|
import { notifications } from "@mantine/notifications";
|
||||||
import { Providers } from "@/app/providers";
|
import { Providers } from "@/app/providers";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import NextImage from "next/image";
|
import NextImage from "next/image";
|
||||||
import logo from '@/app/image/logo.jpg';
|
import logo from '@/app/image/logo1.jpg';
|
||||||
import changePwdImage from '@/app/image/changepw.png';
|
import changePwdImage from '@/app/image/set_log_pass.jpg';
|
||||||
import CaptchaImage from './CaptchaImage';
|
import { IconLock, IconLogout, IconRefresh } from '@tabler/icons-react';
|
||||||
import { IconEye, IconEyeOff, IconLock, IconLogout } from '@tabler/icons-react';
|
import { generateCaptcha } from '@/app/captcha';
|
||||||
|
import { generateOTP } from "../OTPGenerator";
|
||||||
|
|
||||||
export default function SetLoginPwd() {
|
export default function SetLoginPwd() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -16,33 +17,35 @@ export default function SetLoginPwd() {
|
|||||||
const [captcha, setCaptcha] = useState("");
|
const [captcha, setCaptcha] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [confirmPassword, setConfirmPassword] = useState("");
|
const [confirmPassword, setConfirmPassword] = useState("");
|
||||||
const [captchaInput, setCaptchaInput] = useState('');
|
const [captchaInput, setCaptchaInput] = useState("");
|
||||||
const [captchaError, setCaptchaError] = useState('');
|
const [captchaValidate, setCaptchaValidate] = useState(false);
|
||||||
const [confirmVisible, setConfirmVisible] = useState(false);
|
const [otp, setOtp] = useState("");
|
||||||
const toggleConfirmVisibility = () => setConfirmVisible((v) => !v);
|
const [countdown, setCountdown] = useState(60);
|
||||||
|
const [timerActive, setTimerActive] = useState(false);
|
||||||
const icon = <IconLock size={18} stroke={1.5} />;
|
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) {
|
async function handleLogout(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
localStorage.removeItem("access_token");
|
localStorage.removeItem("access_token");
|
||||||
router.push("/login")
|
router.push("/login")
|
||||||
}
|
}
|
||||||
|
const regenerateCaptcha = () => {
|
||||||
useEffect(() => {
|
const loadCaptcha = async () => {
|
||||||
generateCaptcha();
|
const newCaptcha = await generateCaptcha();
|
||||||
}, []);
|
setCaptcha(newCaptcha);
|
||||||
|
};
|
||||||
const generateCaptcha = () => {
|
loadCaptcha();
|
||||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
setCaptchaInput("");
|
||||||
let result = '';
|
|
||||||
for (let i = 0; i < 6; i++) {
|
|
||||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
||||||
}
|
|
||||||
setCaptcha(result);
|
|
||||||
setCaptchaInput('');
|
|
||||||
setCaptchaError('');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleSetLoginPassword(e: React.FormEvent) {
|
async function handleSetLoginPassword(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
|
const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
|
||||||
@@ -50,36 +53,72 @@ export default function SetLoginPwd() {
|
|||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
color: "red",
|
color: "red",
|
||||||
title: "Both password fields are required.",
|
title: "Field Required",
|
||||||
message: "Both password fields are required.",
|
message: "Password and Confirm Password Both fields are required.",
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
// alert("Both password fields are required.");
|
}
|
||||||
} else if (password !== confirmPassword) {
|
if (!captchaInput) {
|
||||||
// alert("Passwords do not match.");
|
|
||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
color: "red",
|
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.",
|
message: "Passwords do not match.",
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!pwdRegex.test(password)) {
|
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.");
|
|
||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
color: "red",
|
color: "red",
|
||||||
title: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.",
|
title: "Invalid Password",
|
||||||
message: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.",
|
message: "Password must contain at least one capital letter, one number, one special character, and be 8-15 characters long.",
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (captchaInput !== captcha) {
|
if (captchaInput !== captcha) {
|
||||||
setCaptchaError("Incorrect 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;
|
return;
|
||||||
}
|
}
|
||||||
const token = localStorage.getItem("access_token");
|
const token = localStorage.getItem("access_token");
|
||||||
@@ -116,6 +155,29 @@ export default function SetLoginPwd() {
|
|||||||
router.push("/login");
|
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(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem("access_token");
|
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,
|
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "flex-start",
|
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
|
<Image
|
||||||
// radius="md"
|
|
||||||
fit="cover"
|
fit="cover"
|
||||||
src={logo}
|
src={logo}
|
||||||
component={NextImage}
|
component={NextImage}
|
||||||
alt="ebanking"
|
alt="ebanking"
|
||||||
style={{ width: "100%", height: "100%" }}
|
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={{
|
<Button style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '50%',
|
top: '50%',
|
||||||
@@ -157,80 +231,101 @@ export default function SetLoginPwd() {
|
|||||||
leftSection={<IconLogout color='white' />} variant="subtle" onClick={handleLogout}>Logout</Button>
|
leftSection={<IconLogout color='white' />} variant="subtle" onClick={handleLogout}>Logout</Button>
|
||||||
</Box>
|
</Box>
|
||||||
<div>
|
<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" />
|
<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" }}>
|
<Box h="100%" style={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
|
||||||
<Card p="xl" w="40vw" h='82vh'>
|
<Card p="xl" w="40vw" h='85vh'>
|
||||||
<Title order={3}
|
<Title order={4}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
align="center" mb="md">Set Login Password</Title>
|
align="center" mb="md">Set Login Password</Title>
|
||||||
|
|
||||||
<form onSubmit={handleSetLoginPassword}>
|
<form onSubmit={handleSetLoginPassword}>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label="Login Password"
|
label="Login Password"
|
||||||
placeholder="Enter your password"
|
placeholder="Enter your password"
|
||||||
required
|
withAsterisk
|
||||||
id="loginPassword"
|
id="loginPassword"
|
||||||
value={password}
|
value={password}
|
||||||
|
minLength={8}
|
||||||
|
maxLength={15}
|
||||||
onChange={(e) => setPassword(e.currentTarget.value)}
|
onChange={(e) => setPassword(e.currentTarget.value)}
|
||||||
onCopy={(e) => e.preventDefault()}
|
onCopy={(e) => e.preventDefault()}
|
||||||
onPaste={(e) => e.preventDefault()}
|
onPaste={(e) => e.preventDefault()}
|
||||||
onCut={(e) => e.preventDefault()}
|
onCut={(e) => e.preventDefault()}
|
||||||
|
readOnly={captchaValidate}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label="Confirm Login Password"
|
label="Confirm Login Password"
|
||||||
placeholder="Enter your password"
|
placeholder="Enter your password"
|
||||||
required
|
withAsterisk
|
||||||
rightSection={icon}
|
rightSection={icon}
|
||||||
id="confirmPassword"
|
id="confirmPassword"
|
||||||
value={confirmPassword}
|
value={confirmPassword}
|
||||||
onChange={(e) => setConfirmPassword(e.currentTarget.value)}
|
onChange={(e) => setConfirmPassword(e.currentTarget.value)}
|
||||||
type={confirmVisible ? 'text' : 'password'}
|
|
||||||
|
|
||||||
onCopy={(e) => e.preventDefault()}
|
onCopy={(e) => e.preventDefault()}
|
||||||
onPaste={(e) => e.preventDefault()}
|
onPaste={(e) => e.preventDefault()}
|
||||||
onCut={(e) => e.preventDefault()}
|
onCut={(e) => e.preventDefault()}
|
||||||
|
readOnly={captchaValidate}
|
||||||
/>
|
/>
|
||||||
|
<Group mt="sm" align="center">
|
||||||
{/* CAPTCHA */}
|
<Box style={{ backgroundColor: "#fff", fontSize: "18px", textDecoration: "line-through", padding: "4px 8px", fontFamily: "cursive" }}>{captcha}</Box>
|
||||||
<div style={{ marginTop: 20 }}>
|
<Button size="xs" variant="light" onClick={regenerateCaptcha}>Refresh</Button>
|
||||||
<label style={{ fontWeight: 600 }}>Enter CAPTCHA *</label>
|
</Group>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 5 }}>
|
<TextInput
|
||||||
<CaptchaImage text={captcha} />
|
label="Enter CAPTCHA"
|
||||||
<Button size="xs" variant="outline" onClick={generateCaptcha}>Refresh</Button>
|
placeholder="Enter above text"
|
||||||
</div>
|
value={captchaInput}
|
||||||
<TextInput
|
onChange={(e) => setCaptchaInput(e.currentTarget.value)}
|
||||||
placeholder="Enter above text"
|
withAsterisk
|
||||||
value={captchaInput}
|
readOnly={captchaValidate}
|
||||||
onChange={(e) => setCaptchaInput(e.currentTarget.value)}
|
/>
|
||||||
required
|
<Box style={{ height: 60 }}>
|
||||||
/>
|
{captchaValidate && (
|
||||||
{captchaError && <p style={{ color: 'red', fontSize: '12px' }}>{captchaError}</p>}
|
<Group gap="xs" align="flex-end">
|
||||||
</div>
|
<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
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
fullWidth
|
fullWidth
|
||||||
mt="sm"
|
mt="sm"
|
||||||
color="blue"
|
|
||||||
>
|
>
|
||||||
Set
|
{!captchaValidate ? "Validate" : "Set"}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
<br></br>
|
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
borderLeft: '1px solid #ccc',
|
borderLeft: '1px solid #ccc',
|
||||||
paddingLeft: 16,
|
paddingLeft: 16,
|
||||||
minHeight: 90,
|
minHeight: 80,
|
||||||
|
gap: "sm"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text size="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>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -247,7 +342,7 @@ export default function SetLoginPwd() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text c="dimmed" size="xs">
|
<Text c="dimmed" size="xs">
|
||||||
© 2025 Kangra Central Co-Operative Bank
|
© 2025 The Kangra Central Co-Operative Bank
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</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";
|
"use client";
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image } from "@mantine/core";
|
import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image, Group } from "@mantine/core";
|
||||||
import { notifications } from "@mantine/notifications";
|
import { notifications } from "@mantine/notifications";
|
||||||
import { Providers } from "@/app/providers";
|
import { Providers } from "@/app/providers";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import NextImage from "next/image";
|
import NextImage from "next/image";
|
||||||
import logo from '@/app/image/logo.jpg';
|
import logo from '@/app/image/logo1.jpg';
|
||||||
import changePwdImage from '@/app/image/changepw.png';
|
import changePwdImage from '@/app/image/set_tran_pass.jpg';
|
||||||
import CaptchaImage from './CaptchaImage';
|
import { generateCaptcha } from '@/app/captcha';
|
||||||
import { IconEye, IconEyeOff, IconLock, IconLogout } from '@tabler/icons-react';
|
import { IconLock, IconLogout, IconRefresh } from '@tabler/icons-react';
|
||||||
|
|
||||||
export default function SetTransactionPwd() {
|
export default function SetTransactionPwd() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -16,32 +16,59 @@ export default function SetTransactionPwd() {
|
|||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [confirmPassword, setConfirmPassword] = useState("");
|
const [confirmPassword, setConfirmPassword] = useState("");
|
||||||
const [captcha, setCaptcha] = useState("");
|
const [captcha, setCaptcha] = useState("");
|
||||||
const [captchaInput, setCaptchaInput] = useState('');
|
const [captchaInput, setCaptchaInput] = useState("");
|
||||||
const [captchaError, setCaptchaError] = useState('');
|
const [captchaValidate, setCaptchaValidate] = useState(false);
|
||||||
const [confirmVisible, setConfirmVisible] = useState(false);
|
const [otp, setOtp] = useState("");
|
||||||
const toggleConfirmVisibility = () => setConfirmVisible((v) => !v);
|
const [countdown, setCountdown] = useState(60);
|
||||||
|
const [timerActive, setTimerActive] = useState(false);
|
||||||
const icon = <IconLock size={18} stroke={1.5} />;
|
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) {
|
async function handleLogout(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
localStorage.removeItem("access_token");
|
localStorage.removeItem("access_token");
|
||||||
router.push("/login")
|
router.push("/login")
|
||||||
}
|
}
|
||||||
|
const regenerateCaptcha = () => {
|
||||||
|
const loadCaptcha = async () => {
|
||||||
|
const newCaptcha = await generateCaptcha();
|
||||||
|
setCaptcha(newCaptcha);
|
||||||
|
};
|
||||||
|
loadCaptcha();
|
||||||
|
setCaptchaInput("");
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
generateCaptcha();
|
const loadCaptcha = async () => {
|
||||||
|
const newCaptcha = await generateCaptcha();
|
||||||
|
setCaptcha(newCaptcha);
|
||||||
|
};
|
||||||
|
loadCaptcha();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const generateCaptcha = () => {
|
useEffect(() => {
|
||||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
let interval: number | undefined;
|
||||||
let result = '';
|
if (timerActive && countdown > 0) {
|
||||||
for (let i = 0; i < 6; i++) {
|
interval = window.setInterval(() => {
|
||||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
setCountdown((prev) => prev - 1);
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
setCaptcha(result);
|
if (countdown === 0) {
|
||||||
setCaptchaInput('');
|
if (interval) clearInterval(interval);
|
||||||
setCaptchaError('');
|
setTimerActive(false);
|
||||||
};
|
}
|
||||||
|
return () => {
|
||||||
|
if (interval) clearInterval(interval);
|
||||||
|
};
|
||||||
|
}, [timerActive, countdown]);
|
||||||
|
|
||||||
async function handleSetTransactionPassword(e: React.FormEvent) {
|
async function handleSetTransactionPassword(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -50,36 +77,72 @@ export default function SetTransactionPwd() {
|
|||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
color: "red",
|
color: "red",
|
||||||
title: "Both password fields are required.",
|
title: "Field Required",
|
||||||
message: "Both password fields are required.",
|
message: "Both password fields are required.",
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
// alert("Both password fields are required.");
|
}
|
||||||
} else if (password !== confirmPassword) {
|
if (!captchaInput) {
|
||||||
// alert("Passwords do not match.");
|
|
||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
color: "red",
|
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.",
|
message: "Passwords do not match.",
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!pwdRegex.test(password)) {
|
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.");
|
|
||||||
notifications.show({
|
notifications.show({
|
||||||
withBorder: true,
|
withBorder: true,
|
||||||
color: "red",
|
color: "red",
|
||||||
title: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.",
|
title: "Invalid Password",
|
||||||
message: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.",
|
message: "Password must contain at least one capital letter, one number, one special character, and be 8-15 characters long.",
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (captchaInput !== captcha) {
|
if (captchaInput !== captcha) {
|
||||||
setCaptchaError("Incorrect 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;
|
return;
|
||||||
}
|
}
|
||||||
const token = localStorage.getItem("access_token");
|
const token = localStorage.getItem("access_token");
|
||||||
@@ -116,7 +179,6 @@ export default function SetTransactionPwd() {
|
|||||||
router.push("/login");
|
router.push("/login");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem("access_token");
|
const token = localStorage.getItem("access_token");
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@@ -136,16 +198,28 @@ export default function SetTransactionPwd() {
|
|||||||
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
|
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "flex-start",
|
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
|
<Image
|
||||||
// radius="md"
|
|
||||||
fit="cover"
|
fit="cover"
|
||||||
src={logo}
|
src={logo}
|
||||||
component={NextImage}
|
component={NextImage}
|
||||||
alt="ebanking"
|
alt="ebanking"
|
||||||
style={{ width: "100%", height: "100%" }}
|
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={{
|
<Button style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '50%',
|
top: '50%',
|
||||||
@@ -158,15 +232,15 @@ export default function SetTransactionPwd() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
<div>
|
<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" />
|
<Image h="85vh" fit="contain" component={NextImage} src={changePwdImage} alt="Change Password Image" />
|
||||||
<Box h="100%" style={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
|
<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")}
|
<Text onClick={() => router.push("/login")}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute', top: '1rem', right: '2rem', cursor: 'pointer', fontWeight: 500, color: '#7091ecff',textDecoration:'underline'
|
position: 'absolute', top: '1rem', right: '2rem', cursor: 'pointer', fontWeight: 500, color: '#7091ecff', textDecoration: 'underline'
|
||||||
}}> Skip now</Text>
|
}}> Skip now</Text>
|
||||||
|
|
||||||
<Title order={3}
|
<Title order={3}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
align="center" mb="md">Set Transaction Password</Title>
|
align="center" mb="md">Set Transaction Password</Title>
|
||||||
@@ -174,52 +248,71 @@ export default function SetTransactionPwd() {
|
|||||||
<PasswordInput
|
<PasswordInput
|
||||||
label="Transaction Password"
|
label="Transaction Password"
|
||||||
placeholder="Enter your Transaction password"
|
placeholder="Enter your Transaction password"
|
||||||
required
|
withAsterisk
|
||||||
id="loginPassword"
|
id="loginPassword"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.currentTarget.value)}
|
onChange={(e) => setPassword(e.currentTarget.value)}
|
||||||
onCopy={(e) => e.preventDefault()}
|
onCopy={(e) => e.preventDefault()}
|
||||||
onPaste={(e) => e.preventDefault()}
|
onPaste={(e) => e.preventDefault()}
|
||||||
onCut={(e) => e.preventDefault()}
|
onCut={(e) => e.preventDefault()}
|
||||||
|
readOnly={captchaValidate}
|
||||||
/>
|
/>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label="Confirm Transaction Password"
|
label="Confirm Transaction Password"
|
||||||
placeholder="Re-enter your Transaction password"
|
placeholder="Re-enter your Transaction password"
|
||||||
required
|
withAsterisk
|
||||||
id="confirmPassword"
|
id="confirmPassword"
|
||||||
rightSection={icon}
|
rightSection={icon}
|
||||||
value={confirmPassword}
|
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)}
|
onChange={(e) => setConfirmPassword(e.currentTarget.value)}
|
||||||
onCopy={(e) => e.preventDefault()}
|
onCopy={(e) => e.preventDefault()}
|
||||||
onPaste={(e) => e.preventDefault()}
|
onPaste={(e) => e.preventDefault()}
|
||||||
onCut={(e) => e.preventDefault()}
|
onCut={(e) => e.preventDefault()}
|
||||||
|
readOnly={captchaValidate}
|
||||||
/>
|
/>
|
||||||
{/* CAPTCHA */}
|
{/* CAPTCHA */}
|
||||||
<div style={{ marginTop: 20 }}>
|
<Group mt="sm" align="center">
|
||||||
<label style={{ fontWeight: 600 }}>Enter CAPTCHA *</label>
|
<Box style={{ backgroundColor: "#fff", fontSize: "18px", textDecoration: "line-through", padding: "4px 8px", fontFamily: "cursive" }}>{captcha}</Box>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 5 }}>
|
<Button size="xs" variant="light" onClick={regenerateCaptcha}>Refresh</Button>
|
||||||
<CaptchaImage text={captcha} />
|
</Group>
|
||||||
<Button size="xs" variant="outline" onClick={generateCaptcha}>Refresh</Button>
|
<TextInput
|
||||||
</div>
|
label="Enter CAPTCHA"
|
||||||
<TextInput
|
placeholder="Enter above text"
|
||||||
placeholder="Enter above text"
|
value={captchaInput}
|
||||||
value={captchaInput}
|
onChange={(e) => setCaptchaInput(e.currentTarget.value)}
|
||||||
onChange={(e) => setCaptchaInput(e.currentTarget.value)}
|
withAsterisk
|
||||||
required
|
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
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -228,10 +321,7 @@ export default function SetTransactionPwd() {
|
|||||||
>
|
>
|
||||||
Set
|
Set
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<br></br>
|
<br></br>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
@@ -243,7 +333,7 @@ export default function SetTransactionPwd() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text size="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>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</Card>
|
</Card>
|
||||||
|
@@ -12,6 +12,23 @@ export const KccbTheme = createTheme({
|
|||||||
primaryColor: 'kccb-colors',
|
primaryColor: 'kccb-colors',
|
||||||
colors: {
|
colors: {
|
||||||
'kccb-colors': KccbColors
|
'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]);
|
}, [currentIndex]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box style={{ position: 'relative', width: '83%', overflow: 'hidden',backgroundColor:"white" }}>
|
<Box style={{ position: 'relative', width: '90%', overflow: 'hidden',backgroundColor:"white" }}>
|
||||||
{/* Scrollable container */}
|
{/* Scrollable container */}
|
||||||
<Box
|
<Box
|
||||||
ref={scrollRef}
|
ref={scrollRef}
|
||||||
|
@@ -1,24 +1,25 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect, memo, useRef } from "react";
|
||||||
import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Flex, Box, Image, Anchor, Stack, Popover, ActionIcon } from "@mantine/core";
|
import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Flex, Box, Image, Anchor, Tooltip } from "@mantine/core";
|
||||||
import { notifications } from "@mantine/notifications";
|
import { notifications } from "@mantine/notifications";
|
||||||
import { Providers } from "@/app/providers";
|
import { Providers } from "@/app/providers";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import NextImage from "next/image";
|
import NextImage from "next/image";
|
||||||
import logo from '@/app/image/logo.jpg';
|
import logo from '@/app/image/logo1.jpg';
|
||||||
import frontPage from '@/app/image/ib_front.jpg';
|
import frontPage from '@/app/image/ib_front.jpg';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { generateCaptcha } from '@/app/captcha';
|
import { generateCaptcha } from '@/app/captcha';
|
||||||
|
import { IconShieldLockFilled } from "@tabler/icons-react";
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
const [CIF, SetCIF] = useState("");
|
const [CIF, SetCIF] = useState("");
|
||||||
const [psw, SetPsw] = useState("");
|
const [psw, SetPsw] = useState("");
|
||||||
const [captcha, setCaptcha] = useState("");
|
const [captcha, setCaptcha] = useState("");
|
||||||
const [inputCaptcha, setInputCaptcha] = useState("");
|
const [inputCaptcha, setInputCaptcha] = useState("");
|
||||||
const [isLogging, setIsLogging] = useState(false);
|
const [isLogging, setIsLogging] = useState(false);
|
||||||
const ClientCarousel = dynamic(() => import('./clientCarousel'), { ssr: false });
|
const ClientCarousel = dynamic(() => import('./clientCarousel'), { ssr: false });
|
||||||
|
const headerRef = useRef<HTMLHeadingElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadCaptcha = async () => {
|
const loadCaptcha = async () => {
|
||||||
@@ -42,7 +43,25 @@ export default function Login() {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const onlyDigit = /^\d{11}$/;
|
const onlyDigit = /^\d{11}$/;
|
||||||
if (!onlyDigit.test(CIF)) {
|
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) {
|
if (inputCaptcha !== captcha) {
|
||||||
notifications.show({
|
notifications.show({
|
||||||
@@ -55,6 +74,16 @@ export default function Login() {
|
|||||||
regenerateCaptcha();
|
regenerateCaptcha();
|
||||||
return;
|
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', {
|
const response = await fetch('api/auth/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
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 (
|
return (
|
||||||
<Providers>
|
<Providers>
|
||||||
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}>
|
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Box style={{
|
<Box
|
||||||
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
|
style={{
|
||||||
display: "flex",
|
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
|
||||||
justifyContent: "flex-start",
|
display: "flex",
|
||||||
background: "linear-gradient(15deg,rgba(2, 163, 85, 1) 55%, rgba(101, 101, 184, 1) 100%)",
|
justifyContent: "flex-start",
|
||||||
// border: "1px solid black"
|
background: "linear-gradient(15deg,rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
|
||||||
}}>
|
}}>
|
||||||
<Image
|
<Image
|
||||||
fit="cover"
|
|
||||||
src={logo}
|
src={logo}
|
||||||
component={NextImage}
|
component={NextImage}
|
||||||
|
fit="contain"
|
||||||
alt="ebanking"
|
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={{
|
style={{
|
||||||
|
fontFamily: 'Roboto',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '50%',
|
top: '30%',
|
||||||
left: '64%',
|
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',
|
color: 'white',
|
||||||
textShadow: '1px 1px 2px blue',
|
textShadow: '1px 1px 2px blue',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* <IconBuildingBank/> */}
|
Head Office : Dharmshala, District: Kangra(H.P), Pin: 176215
|
||||||
Head Office : Dharmshala, District: Kangra(H.P), Pincode: 176215
|
|
||||||
</Text>
|
</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>
|
</Box>
|
||||||
|
|
||||||
<div style={{ marginTop: '10px' }}>
|
<div style={{ marginTop: '10px' }}>
|
||||||
{/* Movable text */}
|
{/* Movable text */}
|
||||||
<Box
|
<Box
|
||||||
@@ -148,7 +214,7 @@ export default function Login() {
|
|||||||
⚠️ KCC Bank never asks for User Id,Passwords and Pins through email or phone.
|
⚠️ 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.
|
⚠️ 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.
|
⚠️ 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.
|
⚠️ Inform the Bank/branch in which your account is maintained for resetting your password.
|
||||||
</Text>
|
</Text>
|
||||||
<style>
|
<style>
|
||||||
@@ -164,8 +230,7 @@ export default function Login() {
|
|||||||
<div style={{
|
<div style={{
|
||||||
display: "flex", height: "75vh", overflow: "hidden", position: "relative",
|
display: "flex", height: "75vh", overflow: "hidden", position: "relative",
|
||||||
// background: 'linear-gradient(to right, #02081eff, #0a3d91)'
|
// background: 'linear-gradient(to right, #02081eff, #0a3d91)'
|
||||||
background:'linear-gradient(179deg,rgba(1, 13, 18, 1) 49%, rgba(181, 196, 187, 1) 87%)'
|
background: 'linear-gradient(179deg,rgba(1, 13, 18, 1) 49%, rgba(77, 82, 79, 1) 87%)'
|
||||||
// background:'linear-gradient(179deg,rgba(1, 7, 10, 1) 48%, rgba(87, 94, 89, 1) 87%)'
|
|
||||||
}}>
|
}}>
|
||||||
<div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
|
<div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
|
||||||
<Image
|
<Image
|
||||||
@@ -176,8 +241,8 @@ export default function Login() {
|
|||||||
style={{ width: "100%", height: "100%" }}
|
style={{ width: "100%", height: "100%" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Box w={{ base: "100%", md: "50%" }} p="lg">
|
<Box w={{ base: "100%", md: "45%" }} p="lg">
|
||||||
<Card shadow="md" padding="xl" radius="md" style={{ maxWidth: 400, margin: "0 auto", height: '68vh' }}>
|
<Card shadow="md" padding="xl" radius="md" style={{ maxWidth: 550, margin: "0 auto", height: '68vh' }}>
|
||||||
<form onSubmit={handleLogin}>
|
<form onSubmit={handleLogin}>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="User ID"
|
label="User ID"
|
||||||
@@ -187,21 +252,20 @@ export default function Login() {
|
|||||||
const input = e.currentTarget.value.replace(/\D/g, "");
|
const input = e.currentTarget.value.replace(/\D/g, "");
|
||||||
if (input.length <= 11) SetCIF(input);
|
if (input.length <= 11) SetCIF(input);
|
||||||
}}
|
}}
|
||||||
error={error}
|
withAsterisk
|
||||||
required
|
|
||||||
/>
|
/>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label="Password"
|
label="Password"
|
||||||
placeholder="Enter your password"
|
placeholder="Enter your password"
|
||||||
value={psw}
|
value={psw}
|
||||||
onChange={(e) => SetPsw(e.currentTarget.value)}
|
onChange={(e) => SetPsw(e.currentTarget.value)}
|
||||||
required
|
withAsterisk
|
||||||
mt="sm"
|
mt="sm"
|
||||||
/>
|
/>
|
||||||
<Box style={{ textAlign: "right"}}>
|
<Box style={{ textAlign: "right" }}>
|
||||||
<Anchor
|
<Anchor
|
||||||
style={{ fontSize: "14px", color: "#1c7ed6", cursor: "pointer" }}
|
style={{ fontSize: "14px", color: "#1c7ed6", cursor: "pointer" }}
|
||||||
onClick={() => router.push("/ValidateUser")}
|
onClick={() => router.push("/ValidateUser")}
|
||||||
>
|
>
|
||||||
Forgot Password?
|
Forgot Password?
|
||||||
</Anchor>
|
</Anchor>
|
||||||
@@ -209,14 +273,13 @@ export default function Login() {
|
|||||||
<Group mt="sm" align="center">
|
<Group mt="sm" align="center">
|
||||||
<Box style={{ backgroundColor: "#fff", fontSize: "18px", textDecoration: "line-through", padding: "4px 8px", fontFamily: "cursive" }}>{captcha}</Box>
|
<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>
|
<Button size="xs" variant="light" onClick={regenerateCaptcha}>Refresh</Button>
|
||||||
|
|
||||||
</Group>
|
</Group>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Enter CAPTCHA"
|
label="Enter CAPTCHA"
|
||||||
placeholder="Enter above text"
|
placeholder="Enter above text"
|
||||||
value={inputCaptcha}
|
value={inputCaptcha}
|
||||||
onChange={(e) => setInputCaptcha(e.currentTarget.value)}
|
onChange={(e) => setInputCaptcha(e.currentTarget.value)}
|
||||||
required
|
withAsterisk
|
||||||
mt="sm"
|
mt="sm"
|
||||||
/>
|
/>
|
||||||
<Button type="submit" fullWidth mt="md" disabled={isLogging}>
|
<Button type="submit" fullWidth mt="md" disabled={isLogging}>
|
||||||
@@ -227,12 +290,12 @@ export default function Login() {
|
|||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
{/* Carousel and Notes */}
|
{/* Carousel and Notes */}
|
||||||
<Flex direction={{ base: "column", md: "row" }} mt="lg" p="lg">
|
<Flex direction={{ base: "column", md: "row" }} mt="md" px="md" py="sm" gap="sm">
|
||||||
<Box w={{ base: "100%", md: "60%" }}>
|
<Box w={{ base: "100%", md: "85%" }}>
|
||||||
<ClientCarousel />
|
<ClientCarousel />
|
||||||
</Box>
|
</Box>
|
||||||
<Box w={{ base: "100%", md: "40%" }} p="md" style={{ textAlign: "center" }}>
|
<Box w={{ base: "100%", md: "25%" }} p="md" style={{ textAlign: "center", border: '1px solid #5c5c3d' }}>
|
||||||
<Title order={2}>Security Notes :</Title>
|
<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" 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>
|
<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>
|
<Anchor href="http://www.kccb.in/"> http://www.kccb.in/</Anchor>
|
||||||
|
Reference in New Issue
Block a user