Wip: update the login page,

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

View File

@@ -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 />