From eda57aae71c8c75c4571ec9d69fd286efb65e96c Mon Sep 17 00:00:00 2001 From: "tomosa.sarkar" Date: Wed, 27 Aug 2025 11:35:15 +0530 Subject: [PATCH] refactor: api integrate for NEFT,RTGS.IMPS and account statement --- .../account_statement/accountStatement.tsx | 45 +++--- .../add_beneficiary/addBeneficiaryOthers.tsx | 1 + src/app/(main)/funds_transfer/page.tsx | 16 ++- .../funds_transfer/send_beneficiary/page.tsx | 16 ++- .../sendBeneficiaryOthers.tsx | 130 ++++++++++-------- .../funds_transfer/view_beneficiary/page.tsx | 4 +- src/app/(main)/layout.tsx | 3 + src/app/image/bank_logo/kccb.jpg | Bin 0 -> 6109 bytes src/app/login/page.tsx | 2 + 9 files changed, 137 insertions(+), 80 deletions(-) create mode 100644 src/app/image/bank_logo/kccb.jpg diff --git a/src/app/(main)/accounts/account_statement/accountStatement.tsx b/src/app/(main)/accounts/account_statement/accountStatement.tsx index 19bf314..b00c6b0 100644 --- a/src/app/(main)/accounts/account_statement/accountStatement.tsx +++ b/src/app/(main)/accounts/account_statement/accountStatement.tsx @@ -1,5 +1,5 @@ "use client"; -import { Paper, Select, Title, Button, Text, Grid, ScrollArea, Table, Divider } from "@mantine/core"; +import { Paper, Select, Title, Button, Text, Grid, ScrollArea, Table, Divider, Center, Loader, Stack } from "@mantine/core"; import { DateInput } from '@mantine/dates'; import { useEffect, useState } from "react"; import { useSearchParams } from "next/navigation"; @@ -20,6 +20,7 @@ export default function AccountStatementPage() { const [transactions, setTransactions] = useState([]); const searchParams = useSearchParams(); const passedAccNo = searchParams.get("accNo"); + const [loading, setLoading] = useState(false); useEffect(() => { const saved = sessionStorage.getItem("accountData"); @@ -34,6 +35,7 @@ export default function AccountStatementPage() { setSelectedAccNo(passedAccNo); //Automatically fetch last 5 transactions if accNo is passed const token = localStorage.getItem("access_token"); + setLoading(true); fetch(`/api/transactions/account/${passedAccNo}`, { method: "GET", headers: { @@ -44,7 +46,7 @@ export default function AccountStatementPage() { .then(res => res.json()) .then(data => { if (Array.isArray(data)) { - const last5 = data.slice(0,5); + const last5 = data.slice(0, 5); setTransactions(last5); } }) @@ -56,7 +58,8 @@ export default function AccountStatementPage() { message: "Could not load recent transactions.", autoClose: 5000, }); - }); + }) + .finally(() => setLoading(false)); } } }, [passedAccNo]); @@ -107,20 +110,18 @@ export default function AccountStatementPage() { } try { const token = localStorage.getItem("access_token"); - const response = await fetch(`/api/transactions/account/${selectedAccNo}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - }); + setLoading(true); + const response = await fetch(`/api/transactions/account/${selectedAccNo}?fromDate=${dayjs(start).format('DDMMYYYY')}&toDate=${dayjs(end).format('DDMMYYYY')}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); const data = await response.json(); if (response.ok && Array.isArray(data)) { - const filterData = data.filter((txn: any) => { - const txnDate = dayjs(txn.date, 'DD/MM/YYYY'); - return txnDate.isSameOrAfter(start) && txnDate.isSameOrBefore(end); - }); - setTransactions(filterData); + setTransactions(data.reverse()); } } catch { notifications.show({ @@ -131,6 +132,9 @@ export default function AccountStatementPage() { autoClose: 5000, }); } + finally { + setLoading(false); + } }; const cellStyle = { border: "1px solid #ccc", @@ -176,7 +180,14 @@ export default function AccountStatementPage() { Account No : {selectedAccNo} - {transactions.length === 0 ? ( + {loading ? ( +
+ + + Please wait, details are being fetched ..... + +
+ ) : transactions.length === 0 ? (

No transactions found.

) : ( <> @@ -203,7 +214,7 @@ export default function AccountStatementPage() { {parseFloat(txn.amount).toLocaleString("en-IN", { minimumFractionDigits: 2, - })} {txn.type==="DR"?"Dr.":"Cr."} + })} {txn.type === "DR" ? "Dr." : "Cr."} ))} diff --git a/src/app/(main)/funds_transfer/add_beneficiary/addBeneficiaryOthers.tsx b/src/app/(main)/funds_transfer/add_beneficiary/addBeneficiaryOthers.tsx index 408f42a..a8e6aaa 100644 --- a/src/app/(main)/funds_transfer/add_beneficiary/addBeneficiaryOthers.tsx +++ b/src/app/(main)/funds_transfer/add_beneficiary/addBeneficiaryOthers.tsx @@ -399,6 +399,7 @@ export default function AddBeneficiaryOthers() { onChange={(e) => setOtp(e.currentTarget.value)} maxLength={6} disabled={otpVerified} //Disable after verified + withAsterisk /> diff --git a/src/app/(main)/funds_transfer/page.tsx b/src/app/(main)/funds_transfer/page.tsx index 8305ecb..94d68d2 100644 --- a/src/app/(main)/funds_transfer/page.tsx +++ b/src/app/(main)/funds_transfer/page.tsx @@ -413,11 +413,17 @@ export default function QuickPay() { label="Amount" type="number" value={amount} - onChange={(e) => setAmount(e.currentTarget.value)} + // onChange={(e) => setAmount(e.currentTarget.value)} + onChange={(e) => { + let input = e.currentTarget.value; + if (/^\d*\.?\d{0,2}$/.test(input)) + setAmount(input); + }} error={ selectedAccount && Number(amount) > Number(selectedAccount.stAvailableBalance) ? "Amount exceeds available balance" : false} withAsterisk + leftSection ="₹" readOnly={showOtpField} /> @@ -425,8 +431,12 @@ export default function QuickPay() { label="Remarks" placeholder="Enter remarks" value={remarks} - onChange={(e) => setRemarks(e.currentTarget.value)} - // withAsterisk + // onChange={(e) => setRemarks(e.currentTarget.value)} + onChange={(e) => { + let input = e.currentTarget.value; + input = input.replace(/[^a-zA-Z0-9 ]/g, ""); + setRemarks(input) + }} readOnly={showOtpField} withAsterisk /> diff --git a/src/app/(main)/funds_transfer/send_beneficiary/page.tsx b/src/app/(main)/funds_transfer/send_beneficiary/page.tsx index 20853d8..4461afc 100644 --- a/src/app/(main)/funds_transfer/send_beneficiary/page.tsx +++ b/src/app/(main)/funds_transfer/send_beneficiary/page.tsx @@ -362,11 +362,17 @@ export default function SendToBeneficiaryOwn() { label="Amount" type="number" value={amount} - onChange={(e) => setAmount(e.currentTarget.value)} + // onChange={(e) => setAmount(e.currentTarget.value)} + onChange={(e) => { + let input = e.currentTarget.value; + if (/^\d*\.?\d{0,2}$/.test(input)) + setAmount(input); + }} error={ selectedAccount && Number(amount) > Number(selectedAccount.stAvailableBalance) ? "Amount exceeds available balance" : false} withAsterisk + leftSection ="₹" readOnly={showOtpField} /> @@ -374,7 +380,13 @@ export default function SendToBeneficiaryOwn() { label="Remarks" placeholder="Enter remarks" value={remarks} - onChange={(e) => setRemarks(e.currentTarget.value)} + // onChange={(e) => setRemarks(e.currentTarget.value)} + onChange={(e) => { + let input = e.currentTarget.value; + input = input.replace(/[^a-zA-Z0-9 ]/g, ""); + setRemarks(input) + }} + maxLength={70} withAsterisk readOnly={showOtpField} /> diff --git a/src/app/(main)/funds_transfer/send_beneficiary/sendBeneficiaryOthers.tsx b/src/app/(main)/funds_transfer/send_beneficiary/sendBeneficiaryOthers.tsx index c4eec71..7d7cdb2 100644 --- a/src/app/(main)/funds_transfer/send_beneficiary/sendBeneficiaryOthers.tsx +++ b/src/app/(main)/funds_transfer/send_beneficiary/sendBeneficiaryOthers.tsx @@ -12,37 +12,6 @@ interface accountData { stAvailableBalance: string; custname: string; } -const MockBeneficiaryData = - [ - { - 'stBankName': 'Kangra Central Co-operative Bank', - 'stBenAccountNo': '50077736845', - 'stBenName': 'RAJAT MAHARANA', - }, - { - 'stBankName': 'Kangra Central Co-operative Bank', - 'stBenAccountNo': '50077742351', - 'stBenName': 'RAJAT MAHARANA', - }, - { - 'stBankName': 'Kangra Central Co-operative Bank', - 'stBenAccountNo': '20002076570', - 'stBenName': 'Mr. PUSHKAR . SHARMA', - }, - { - 'stBankName': 'State Bank of India', - 'stBenAccountNo': '50077742361', - 'stIFSC': 'SBIN0004567', - 'stBenName': 'Sachin Sharma', - }, - { - 'stBankName': 'ICICI', - 'stBenAccountNo': '90088842361', - 'stIFSC': 'ICICI0004567', - 'stBenName': 'Eshika Paul', - }, - ] - export default function SendToBeneficiaryOthers() { const router = useRouter(); const [authorized, setAuthorized] = useState(null); @@ -70,6 +39,24 @@ export default function SendToBeneficiaryOthers() { setGenerateOtp(value); return value; } + const getAmountError = () => { + if (!amount || !selectedAccount) return null; + const amt = Number(amount); + const balance = Number(selectedAccount.stAvailableBalance); + if (paymentMode === "IMPS") { + if (amt > 200000) return "IMPS limit is ₹2,00,000"; + if (amt > balance) return "Amount exceeds available balance"; + } + if (paymentMode === "RTGS") { + if (amt < 200000) return "RTGS requires minimum ₹2,00,000"; + if (amt > balance) return "Amount exceeds available balance"; + } + if (paymentMode === "NEFT") { + if (amt > balance) return "Amount exceeds available balance"; + } + if (amt <= 0) return "Amount cannot be less than or equal to zero"; + return null; + }; const FetchBeneficiaryDetails = async () => { try { @@ -129,7 +116,6 @@ export default function SendToBeneficiaryOthers() { } } } - const FetchAccountDetails = async () => { try { const token = localStorage.getItem("access_token"); @@ -191,7 +177,14 @@ export default function SendToBeneficiaryOthers() { }); return; } - + if (getAmountError()) { + notifications.show({ + title: "Invalid amount", + message: getAmountError()!, + color: "red", + }); + return; + } if (!showOtpField && !showTxnPassword && !showConfirmModel) { setConfirmModel(true); setIsVisibilityLocked(true); @@ -231,8 +224,16 @@ export default function SendToBeneficiaryOthers() { try { setIsSubmitting(true); const token = localStorage.getItem("access_token"); - // Need to change the API - const res = await fetch("/api/payment/transfer", { + const remitter_name = localStorage.getItem("remitter_name"); + let url = ""; + if (paymentMode === "NEFT") + url = "/api/payment/neft"; + if (paymentMode === "RTGS") + url = "/api/payment/rtgs" + if (paymentMode === "IMPS") + url = "/api/payment/imps"; + + const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", @@ -241,17 +242,18 @@ export default function SendToBeneficiaryOthers() { body: JSON.stringify({ fromAccount: selectedAccNo, toAccount: beneficiaryAcc, - // toAccountType: beneficiaryType, + ifscCode: beneficiaryIFSC, amount: amount, - narration: remarks, - tpassword: txnPassword, + beneficiaryName: beneficiaryName, + remitterName: remitter_name, + tpassword: txnPassword }), }); const result = await res.json(); if (res.ok) { notifications.show({ title: "Success", - message: "Transaction successful", + message: result?.utr ? `Transaction successful - UTR =${result.utr}` : "Transaction successful", color: "green", }); setShowTxnPassword(false); @@ -259,13 +261,15 @@ export default function SendToBeneficiaryOthers() { setShowOtpField(false); setOtp(""); setBeneficiaryName(''); - } else { + } + else { notifications.show({ title: "Error", message: result?.error || "Transaction failed", color: "red", }); } + } catch { notifications.show({ title: "Error", @@ -327,8 +331,8 @@ export default function SendToBeneficiaryOthers() { {/* main content */}
- - + +