diff --git a/src/app/(main)/accounts/account_statement/accountStatement.tsx b/src/app/(main)/accounts/account_statement/accountStatement.tsx index 50a9fed..49a715e 100644 --- a/src/app/(main)/accounts/account_statement/accountStatement.tsx +++ b/src/app/(main)/accounts/account_statement/accountStatement.tsx @@ -96,12 +96,12 @@ export default function AccountStatementPage() { }); return; } - if (end.diff(start, "day") > 60) { + if (end.diff(start, "day") > 90) { notifications.show({ withBorder: true, color: "red", title: "Invalid Date range", - message: "End date must be within 60 days from start date", + message: "End date must be within 90 days from start date", autoClose: 4000, }); return; diff --git a/src/app/(main)/funds_transfer/page.tsx b/src/app/(main)/funds_transfer/page.tsx index 025e1bc..f8f6da3 100644 --- a/src/app/(main)/funds_transfer/page.tsx +++ b/src/app/(main)/funds_transfer/page.tsx @@ -1,110 +1,392 @@ "use client"; +import React, { useEffect, useState } from "react"; import { - Box, Button, - Flex, Group, + Paper, Radio, + ScrollArea, Select, + Stack, Text, TextInput, Title, } from "@mantine/core"; -import { useState } from "react"; +import { notifications } from "@mantine/notifications"; +import { useRouter } from "next/navigation"; -export default function FundTransferForm() { - const [paymentMethod, setPaymentMethod] = useState("imps"); +interface accountData { + stAccountNo: string; + stAccountType: string; + stAvailableBalance: string; + custname: string; +} + +export default function QuickPay() { + const router = useRouter(); + const [bankType, setBankType] = useState("own"); + const [authorized, setAuthorized] = useState(null); + const [accountData, setAccountData] = useState([]); + const [selectedAccNo, setSelectedAccNo] = useState(null); + const [beneficiaryAcc, setBeneficiaryAcc] = useState(""); + const [confirmBeneficiaryAcc, setConfirmBeneficiaryAcc] = useState(""); + const [beneficiaryType, setBeneficiaryType] = useState(null); + const [isVisibilityLocked, setIsVisibilityLocked] = useState(false); + const [amount, setAmount] = useState(""); + const [remarks, setRemarks] = useState(""); + const [showTxnPassword, setShowTxnPassword] = useState(false); + const [txnPassword, setTxnPassword] = useState(""); + const [isSubmitting, setIsSubmitting] = useState(false); + const [validationStatus, setValidationStatus] = useState<"success" | "error" | null>(null); + const [beneficiaryName, setBeneficiaryName] = useState(null); + const [showOtpField, setShowOtpField] = useState(false); + const [otp, setOtp] = useState(""); + + const accountOptions = accountData.map((acc) => ({ + value: acc.stAccountNo, + label: `${acc.stAccountNo} (${acc.stAccountType})`, + })); + + const FetchAccountDetails = async () => { + try { + const token = localStorage.getItem("access_token"); + const response = await fetch("/api/customer", { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + const data = await response.json(); + if (response.ok && Array.isArray(data)) { + const filterSAaccount =data.filter((acc)=>acc.stAccountType==='SA'); + setAccountData(filterSAaccount); + } + } catch { + notifications.show({ + withBorder: true, + color: "red", + title: "Please try again later", + message: "Unable to Fetch, Please try again later", + autoClose: 5000, + }); + } + }; + + useEffect(() => { + const token = localStorage.getItem("access_token"); + if (!token) { + setAuthorized(false); + router.push("/login"); + } else { + setAuthorized(true); + } + }, []); + + useEffect(() => { + if (authorized) { + FetchAccountDetails(); + } + }, [authorized]); + + const isValidTxnPassword = (password: string) => + /[A-Z]/i.test(password) && /[0-9]/.test(password) && /[^a-zA-Z0-9]/.test(password); + + const handleValidate = async () => { + if (!selectedAccNo || !beneficiaryAcc || + !confirmBeneficiaryAcc + ) { + notifications.show({ + title: "Validation Error", + message: "Please fill debit account, beneficiary account number and confirm beneficiary account number", + color: "red", + }); + return; + } + if (beneficiaryAcc.length < 10 || beneficiaryAcc.length > 17) { + notifications.show({ + title: "Invalid Account Number", + message: "Please Enter valid account Number", + color: "red", + }); + return; + } + if (beneficiaryAcc !== confirmBeneficiaryAcc) { + notifications.show({ + title: "Mismatch", + message: "Beneficiary account numbers do not match", + color: "red", + }); + return; + } + + try { + const token = localStorage.getItem("access_token"); + const response = await fetch(`/api/beneficiary/validate/within-bank?accountNumber=${beneficiaryAcc}`, { + 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); + } else { + setBeneficiaryName("Invalid account number"); + setValidationStatus("error"); + } + } catch { + setBeneficiaryName("Invalid account number"); + setValidationStatus("error"); + } + }; + + const handleProceed = async () => { + if (!selectedAccNo || !beneficiaryAcc || !confirmBeneficiaryAcc || !beneficiaryType || !amount || !remarks) { + notifications.show({ + title: "Validation Error", + message: "Please fill all required fields", + color: "red", + }); + return; + } + + if (validationStatus !== "success") { + notifications.show({ + title: "Validation Required", + message: "Please validate beneficiary before proceeding", + color: "red", + }); + return; + } + + if (!showTxnPassword) { + setShowTxnPassword(true); + return; + } + + if (!txnPassword || !isValidTxnPassword(txnPassword)) { + notifications.show({ + title: "Weak Password", + message: "Password must contain letter, number, and special character", + color: "red", + }); + return; + } + + if (!showOtpField) { + setShowOtpField(true); + notifications.show({ + title: "OTP Sent", + message: "Check your registered device for OTP", + color: "green", + }); + return; + } + + if (!otp) { + notifications.show({ + title: "Enter OTP", + message: "Please enter the OTP", + color: "red", + }); + return; + } + + try { + setIsSubmitting(true); + const token = localStorage.getItem("access_token"); + + const res = await fetch("/api/payment/transfer", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + fromAccount: selectedAccNo, + toAccount: beneficiaryAcc, + toAccountType: beneficiaryType, + amount, + narration: remarks, + txnPassword, + otp, + }), + }); + + const result = await res.json(); + + if (res.ok) { + notifications.show({ + title: "Success", + message: "Transaction successful", + color: "green", + }); + + // Reset + setShowTxnPassword(false); + setTxnPassword(""); + setShowOtpField(false); + setOtp(""); + setValidationStatus(null); + setBeneficiaryName(null); + } else { + notifications.show({ + title: "Error", + message: result?.message || "Transaction failed", + color: "red", + }); + } + } catch { + notifications.show({ + title: "Error", + message: "Something went wrong", + color: "red", + }); + } finally { + setIsSubmitting(false); + } + }; + + if (!authorized) return null; return ( - - - - Enter Transaction Details + <Paper shadow="sm" radius="md" p="md" withBorder h={400}> + <Title order={3} mb="md"> + Quick Pay + + + + + + - {/* Transfer From */} -
- - Transfer from + {bankType === "own" ? ( + +
+ + + + + setAmount(e.currentTarget.value)} + withAsterisk + /> + + setRemarks(e.currentTarget.value)} + withAsterisk + /> + + + {showTxnPassword && ( + setTxnPassword(e.currentTarget.value)} + withAsterisk + /> + )} + + {showOtpField && ( + setOtp(e.currentTarget.value)} + withAsterisk + /> + )} + + + + + +
+
+ ) : ( + + hii -