"use client"; import React, { useEffect, useRef, useState } from "react"; import { Button, Group, Modal, Paper, PasswordInput, Radio, ScrollArea, Select, Stack, Text, TextInput, Title } from "@mantine/core"; import { notifications } from "@mantine/notifications"; import { useRouter } from "next/navigation"; 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"; import { getDailyLimit } from "@/app/_util/transactionLimit"; interface accountData { stAccountNo: string; stAccountType: string; stAvailableBalance: string; custname: string; } export default function QuickPay() { const router = useRouter(); const [authorized, setAuthorized] = useState(null); const [accountData, setAccountData] = useState([]); const [selectedAccNo, setSelectedAccNo] = useState(null); const [beneficiaryAcc, setBeneficiaryAcc] = useState(""); const [showPayeeAcc, setShowPayeeAcc] = useState(true); const [confirmBeneficiaryAcc, setConfirmBeneficiaryAcc] = useState(""); const [beneficiaryType, setBeneficiaryType] = useState(null); const [isVisibilityLocked, setIsVisibilityLocked] = useState(false); const [amount, setAmount] = useState(""); const [remarks, setRemarks] = useState(""); const [showConfirmModel, setConfirmModel] = useState(false); 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 [countdown, setCountdown] = useState(180); const [timerActive, setTimerActive] = useState(false); const [otp, setOtp] = useState(""); const [dailyLimit, setDailyLimit] = useState(null); const [usedLimit, setUsedLimit] = useState(null); const FetchDailyLimit = async () => { try { const token = localStorage.getItem("access_token"); if (!token) return; const data = await getDailyLimit(token); if (data) { setDailyLimit(data.dailyLimit); setUsedLimit(data.usedLimit); } else { setDailyLimit(null); setUsedLimit(null); } } catch { setDailyLimit(null); setUsedLimit(null); } }; 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' }); 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); }; 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", "X-Login-Type": "IB", Authorization: `Bearer ${token}`, }, }); const data = await response.json(); if (response.ok && Array.isArray(data)) { const filterSAaccount = data.filter((acc) => ['SA', 'SB'].includes(acc.stAccountType)); 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(); FetchDailyLimit(); } }, [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 ) { 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", "X-Login-Type": "IB", 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"); setBeneficiaryAcc(""); setConfirmBeneficiaryAcc(""); } } catch { setBeneficiaryName("Invalid account number"); setValidationStatus("error"); } }; async function handleProceed() { 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 (parseInt(amount) <= 0) { notifications.show({ title: "Invalid amount", message: "Amount Can not be less than Zero", color: "red", }); return; } if (!showOtpField && !showTxnPassword && !showConfirmModel) { setConfirmModel(true); return; } if (!otp) { notifications.show({ title: "Enter OTP", message: "Please enter the OTP", color: "red", }); return; } const verified = await handleVerifyOtp(); if (!verified) { notifications.show({ title: "Invalid OTP", message: "The OTP entered does not match", color: "red", }); return; } if (!showTxnPassword) { setShowTxnPassword(true); return; } if (!txnPassword) { notifications.show({ title: "Missing field", message: "Please Enter Transaction Password Before Proceed", 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", "X-Login-Type": "IB", Authorization: `Bearer ${token}`, }, body: JSON.stringify({ fromAccount: selectedAccNo, toAccount: beneficiaryAcc, toAccountType: beneficiaryType, amount: amount, remarks: remarks, tpassword: txnPassword, }), }); const result = await res.json(); if (res.ok) { notifications.show({ title: "Success", message: "Transaction successful", color: "green", }); await FetchDailyLimit(); return; } else { notifications.show({ title: "Error", message: result?.error || "Transaction failed", color: "red", }); return; } } catch { notifications.show({ title: "Error", message: "Something went wrong", color: "red", }); } finally { setValidationStatus(null); setSelectedAccNo(null); setBeneficiaryAcc(''); setBeneficiaryName(''); setConfirmBeneficiaryAcc(''); setBeneficiaryType(null); setTxnPassword(""); setOtp(""); setAmount(''); setRemarks(''); setIsVisibilityLocked(false); setIsSubmitting(false); setShowTxnPassword(false); setShowOtpField(false); setIsSubmitting(false); setTimerActive(false); setCountdown(180); } }; if (!authorized) return null; return ( <> setConfirmModel(false)} // title="Confirm Transaction" centered > KCC Bank Logo Confirm Transaction Debit Account: {selectedAccNo} Payee Account: {beneficiaryAcc} Payee Name: {beneficiaryName} Amount: ₹ {amount} Remarks: {remarks} {/* main content */} Quick Pay - Own Bank
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} /> setRemarks(e.currentTarget.value)} onChange={(e) => { let input = e.currentTarget.value; input = input.replace(/[^a-zA-Z0-9 ]/g, ""); setRemarks(input) }} readOnly={showOtpField} withAsterisk /> {showOtpField && ( <> setOtp(e.currentTarget.value)} withAsterisk disabled={showTxnPassword} style={{ flex: 1 }} /> {!showTxnPassword && ( timerActive ? ( Resend OTP will be enabled in{" "} {String(Math.floor(countdown / 60)).padStart(2, "0")}: {String(countdown % 60).padStart(2, "0")} ) : ( ) )} )} {showTxnPassword && ( setTxnPassword(e.currentTarget.value)} withAsterisk /> )} • Minimum Transfer Amount on this Day is Rs. 1.00 {dailyLimit !== null ? ( <> • Maximum Transfer Limit per Day is Rs. {dailyLimit.toFixed(2)} • Available Transfer Amount on this Day is Rs.{" "} {usedLimit?.toFixed(2)} ) : ( • No daily limit set for this user )}
); }