Files
IB/src/app/(main)/funds_transfer/add_beneficiary/page.tsx

280 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, { useState } from 'react';
import {
TextInput,
Button,
Select,
Title,
Paper,
Grid,
Group,
Radio,
Text,
} from '@mantine/core';
import { notifications } from '@mantine/notifications';
const bankOptions = [
{ value: 'KCCB', label: 'KCCB - The Kangra Central Co-Operative Bank' },
];
const AddBeneficiary: React.FC = () => {
const [bankName, setBankName] = useState('');
const [bankType, setBankType] = useState('own');
const [accountNo, setAccountNo] = useState('');
const [confirmAccountNo, setConfirmAccountNo] = useState('');
const [payeeName, setPayeeName] = useState('');
const [nickName, setNickName] = useState('');
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 [beneficiaryName, setBeneficiaryName] = useState<string | null>(null);
const [isVisibilityLocked, setIsVisibilityLocked] = useState(false);
const [showPayeeAcc, setShowPayeeAcc] = useState(true);
const getFullMaskedAccount = (acc: string) => { return "X".repeat(acc.length); };
const handleGenerateOtp = async () => {
const value = "123456"; // Or generate a random OTP
setGeneratedOtp(value);
return value;
};
const validateAndSendOtp = async () => {
if (!bankName || !accountNo || !confirmAccountNo) {
notifications.show({
withBorder: true,
color: "red",
title: "Missing Field",
message: "All fields must be completed.",
autoClose: 5000,
});
return;
}
if (accountNo.length < 10 || accountNo.length > 17) {
notifications.show({
withBorder: true,
color: "red",
title: "Invalid Account Number",
message: "Enter a valid account number (1017 digits).",
autoClose: 5000,
});
return;
}
if (accountNo !== confirmAccountNo) {
notifications.show({
withBorder: true,
color: "red",
title: "Mismatch",
message: "Account numbers do not match.",
autoClose: 5000,
});
return;
}
try {
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 = () => {
if (otp === generatedOtp) {
setOtpVerified(true);
notifications.show({
withBorder: true,
color: "green",
title: "OTP Verified",
message: "OTP validated successfully.",
autoClose: 5000,
});
} else {
notifications.show({
withBorder: true,
color: "red",
title: "OTP Error",
message: "OTP does not match.",
autoClose: 5000,
});
}
};
return (
<Paper shadow="sm" radius="md" p="md" withBorder>
<Title order={3} mb="md">Add Beneficiary</Title>
<Radio.Group value={bankType} onChange={setBankType} name="bankType" withAsterisk mb="md">
<Group justify="center">
<Radio value="own" label="Own Bank" />
<Radio value="outside" label="Outside Bank" />
</Group>
</Radio.Group>
{bankType === "own" ? (
<Grid gutter="md">
<Grid.Col span={4}>
<Select
label="Bank Name"
placeholder="Select bank"
data={bankOptions}
value={bankName}
onChange={(value) => setBankName(value || '')}
required
/>
</Grid.Col>
<Grid.Col span={4}>
<TextInput
label="Beneficiary Account Number"
placeholder="Enter account number"
value={showPayeeAcc ? accountNo : getFullMaskedAccount(accountNo)}
onChange={(e) => {
const value = e.currentTarget.value;
if (/^\d*$/.test(value) && value.length <= 17) {
setAccountNo(value);
setShowPayeeAcc(true);
}
}}
onBlur={() => setShowPayeeAcc(false)}
onFocus={() => setShowPayeeAcc(true)}
readOnly={isVisibilityLocked}
maxLength={17}
// disabled={isVisibilityLocked}
required
/>
</Grid.Col>
<Grid.Col span={4}>
<TextInput
label="Confirm Beneficiary Account Number"
placeholder="Re-enter account number"
value={confirmAccountNo}
onChange={(e) => {
const value = e.currentTarget.value;
if (/^\d*$/.test(value) && value.length <= 17) {
setConfirmAccountNo(value);
}
}}
maxLength={17}
// disabled={isVisibilityLocked}
readOnly={isVisibilityLocked}
required
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onCut={(e) => e.preventDefault()}
/>
{validationStatus === "error" && (
<Text c="red" size="sm" style={{ marginLeft: '1rem', whiteSpace: 'nowrap' }}>
{beneficiaryName}
</Text>
)}
</Grid.Col>
<Grid.Col span={6}>
<TextInput
label="Nick Name (Optional)"
placeholder="Enter nickname (optional)"
value={nickName}
onChange={(e) => setNickName(e.currentTarget.value)}
/>
</Grid.Col>
<Grid.Col span={6}>
<TextInput
label="Beneficiary Name"
value={validationStatus === "success" && beneficiaryName ? beneficiaryName : ""}
disabled
maxLength={100}
required
/>
</Grid.Col>
{!otpSent && (
<Grid.Col>
<Button onClick={validateAndSendOtp}>Validate</Button>
</Grid.Col>
)}
{otpSent && (
<>
<Grid.Col span={3}>
<TextInput
label="Enter OTP"
placeholder="Enter OTP"
value={otp}
onChange={(e) => setOtp(e.currentTarget.value)}
maxLength={6}
disabled={otpVerified} // ✅ Disable after verified
/>
</Grid.Col >
<Grid.Col >
{!otpVerified ? (
<Button onClick={verifyOtp}>Validate OTP</Button>
) : (
<Button color="blue" size="sm" onClick={() => { /* handle add here */ }}>
Add
</Button>
)}
</Grid.Col>
</>
)}
</Grid>
) : (
<Text size="lg" mt="md">
Outside Bank feature coming soon.
</Text>
)}
</Paper>
);
};
export default AddBeneficiary;