From 83ae6b055c0be78898c6659ca331d67598ff6046 Mon Sep 17 00:00:00 2001 From: "nabanita.jana" Date: Mon, 13 Oct 2025 11:55:34 +0530 Subject: [PATCH] feat: call the OTP Url in "send money","settings" --- src/app/(main)/funds_transfer/page.tsx | 57 +++++++-- .../funds_transfer/view_beneficiary/page.tsx | 120 ++++++++++++------ .../settings/change_login_password/page.tsx | 58 +++++++-- .../settings/change_txn_password/page.tsx | 57 +++++++-- .../(main)/settings/set_txn_password/page.tsx | 55 ++++++-- src/app/SetPassword/page.tsx | 66 ++++++++-- src/app/_util/otp.ts | 4 +- 7 files changed, 330 insertions(+), 87 deletions(-) diff --git a/src/app/(main)/funds_transfer/page.tsx b/src/app/(main)/funds_transfer/page.tsx index 27d035e..78b6087 100644 --- a/src/app/(main)/funds_transfer/page.tsx +++ b/src/app/(main)/funds_transfer/page.tsx @@ -9,6 +9,7 @@ import OutsideQuickPay from "./outside_quick_pay"; import { IconRefresh } from "@tabler/icons-react"; import Image from "next/image"; import img from '@/app/image/logo1.jpg' +import { sendOtp, verifyOtp } from "@/app/_util/otp"; interface accountData { stAccountNo: string; @@ -42,15 +43,53 @@ export default function QuickPay() { const [otp, setOtp] = useState(""); const [generateOtp, setGenerateOtp] = useState(""); - async function handleGenerateOtp() { - // const value = await generateOTP(6); - const value = "123456"; - setGenerateOtp(value); - setCountdown(180); - setTimerActive(true); - return value; + // async function handleGenerateOtp() { + // // const value = await generateOTP(6); + // const value = "123456"; + // setGenerateOtp(value); + // setCountdown(180); + // setTimerActive(true); + // return value; + // } + + async function handleSendOtp() { + const mobileNumber = localStorage.getItem('remitter_mobile_no'); + if (!mobileNumber) { + notifications.show({ + title: 'Error', + message: 'Mobile number not found.Contact to administrator', + color: 'red', + }); + return; + } + try { + await sendOtp({ type: 'BENEFICIARY_DELETE' }); + setShowOtpField(true); + setCountdown(180); + setTimerActive(true); + } catch (err: any) { + console.error('Send OTP failed', err); + notifications.show({ + title: 'Error', + message: err.message || 'Send OTP failed.Please try again later.', + color: 'red', + }); + } } + async function handleVerifyOtp() { + try { + await verifyOtp(otp); + return true; + } catch { + return false; + } + } + + + + + const selectedAccount = accountData.find((acc) => acc.stAccountNo === selectedAccNo); const getFullMaskedAccount = (acc: string) => { return "X".repeat(acc.length); }; @@ -335,7 +374,7 @@ export default function QuickPay() { color="blue" onClick={async () => { setConfirmModel(false); - const otp = await handleGenerateOtp(); + const otp = await handleSendOtp(); setShowOtpField(true); notifications.show({ title: "OTP Sent", @@ -484,7 +523,7 @@ export default function QuickPay() { ) )} diff --git a/src/app/(main)/funds_transfer/view_beneficiary/page.tsx b/src/app/(main)/funds_transfer/view_beneficiary/page.tsx index 28ddf31..02d1258 100644 --- a/src/app/(main)/funds_transfer/view_beneficiary/page.tsx +++ b/src/app/(main)/funds_transfer/view_beneficiary/page.tsx @@ -6,10 +6,8 @@ import { notifications } from "@mantine/notifications"; import { useRouter } from "next/navigation"; import Image from "next/image"; import { getBankLogo } from "@/app/_util/getBankLogo"; -import { IconTrash } from "@tabler/icons-react"; - - - +import { IconRefresh, IconTrash } from "@tabler/icons-react"; +import { sendOtp, verifyOtp } from "@/app/_util/otp"; interface Beneficiary { @@ -31,6 +29,41 @@ export default function ViewBeneficiary() { const [otpStep, setOtpStep] = useState(false); const [otp, setOtp] = useState(""); const [selectedAccount, setSelectedAccount] = useState(null); + const [countdown, setCountdown] = useState(180); + const [timerActive, setTimerActive] = useState(false); + + async function handleSendOtp() { + const mobileNumber = localStorage.getItem('remitter_mobile_no'); + if (!mobileNumber) { + notifications.show({ + title: 'Error', + message: 'Mobile number not found.Contact to administrator', + color: 'red', + }); + return; + } + try { + await sendOtp({ type: 'IMPS' }); // type will be "BENEFICIARY_DELETE" + setCountdown(180); + setTimerActive(true); + } catch (err: any) { + console.error('Send OTP failed', err); + notifications.show({ + title: 'Error', + message: err.message || 'Send OTP failed.Please try again later.', + color: 'red', + }); + } + } + + async function handleVerifyOtp() { + try { + await verifyOtp(otp); + return true; + } catch { + return false; + } + } const openDeleteModal = (accountNo: string) => { setSelectedAccount(accountNo); @@ -41,30 +74,15 @@ export default function ViewBeneficiary() { const handleModalConfirm = async () => { + if (!selectedAccount) return; + try { - // const token = localStorage.getItem("access_token"); - - // // Generate OTP - // const otpResponse = await fetch("/api/otp/generate", { - // method: "POST", - // headers: { Authorization: `Bearer ${token}` }, - // }); - const otpResponse ="123456"; - - if (otpResponse !== otp) { - notifications.show({ - title: "Error", - message: "Failed to generate OTP.", - color: "red", - }); - return; - } - - setOtpStep(true); // move to OTP input step + await handleSendOtp(); // send OTP to user's mobile + setOtpStep(true); // move modal to OTP input step } catch (err) { notifications.show({ title: "Error", - message: "Something went wrong.", + message: "Failed to send OTP. Please try again.", color: "red", }); } @@ -75,19 +93,8 @@ export default function ViewBeneficiary() { if (!otp || !selectedAccount) return; try { - const token = localStorage.getItem("access_token"); - - // Verify OTP - const verify = await fetch("/api/otp/verify", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - body: JSON.stringify({ otp }), - }); - - if (!verify.ok) { + const isOtpValid = await handleVerifyOtp(); // verify OTP + if (!isOtpValid) { notifications.show({ title: "Invalid OTP", message: "Please enter the correct OTP.", @@ -96,7 +103,8 @@ export default function ViewBeneficiary() { return; } - // Delete beneficiary + // OTP is valid → delete beneficiary + const token = localStorage.getItem("access_token"); const res = await fetch(`/api/beneficiary/${selectedAccount}`, { method: "DELETE", headers: { Authorization: `Bearer ${token}` }, @@ -110,6 +118,8 @@ export default function ViewBeneficiary() { color: "green", }); setOpened(false); + setOtpStep(false); + setOtp(""); } else { notifications.show({ title: "Error", @@ -126,6 +136,7 @@ export default function ViewBeneficiary() { } }; + useEffect(() => { const token = localStorage.getItem("access_token"); if (!token) { @@ -162,6 +173,23 @@ export default function ViewBeneficiary() { fetchBeneficiaries(); }, []); + //new use effect + useEffect(() => { + let interval: NodeJS.Timeout | null = null; + if (timerActive && countdown > 0) { + interval = setInterval(() => { + setCountdown((prev) => prev - 1); + }, 1000); + } else if (countdown === 0) { + setTimerActive(false); + } + return () => { + if (interval) clearInterval(interval); + }; + }, [timerActive, countdown]); + + + if (loading) { return (
@@ -260,6 +288,22 @@ export default function ViewBeneficiary() { onChange={(e) => setOtp(e.currentTarget.value)} placeholder="Enter OTP" /> + + {/* Resend OTP Timer or Icon */} + {timerActive ? ( + + Resend OTP will be enabled in{" "} + {String(Math.floor(countdown / 60)).padStart(2, "0")}: + {String(countdown % 60).padStart(2, "0")} + + ) : ( + + )} +