"use client"; import React, { useEffect, useState } from "react"; import { TextInput, Button, Title, Paper, Group, Text, } from "@mantine/core"; import { notifications } from "@mantine/notifications"; import { IconRefresh, IconCurrencyRupee } from "@tabler/icons-react"; import { generateCaptcha } from "@/app/captcha"; import { useRouter } from "next/navigation"; import { sendOtp, verifyOtp } from "@/app/_util/otp"; import { getDailyLimit } from "@/app/_util/transactionLimit"; export default function SetTransactionLimit() { const [limit, setLimit] = useState(""); const [captcha, setCaptcha] = useState(""); const [captchaInput, setCaptchaInput] = useState(""); const [otp, setOtp] = useState(""); const [otpValidated, setOtpValidated] = useState(false); const [countdown, setCountdown] = useState(180); const [timerActive, setTimerActive] = useState(false); const [step, setStep] = useState<"form" | "otp" | "final">("form"); const [dailyLimit, setDailyLimit] = useState(null); const router = useRouter(); const icon = ; const FetchDailyLimit = async () => { try { const token = localStorage.getItem("access_token"); if (!token) return; const data = await getDailyLimit(token); if (data) { setDailyLimit(data.dailyLimit); } else { setDailyLimit(null); } } catch { setDailyLimit(null); } }; async function handleSendOtp() { const mobileNumber = localStorage.getItem("remitter_mobile_no"); if (!mobileNumber) { notifications.show({ title: "Error", message: "Mobile number not found. Contact administrator.", color: "red", }); return; } try { await sendOtp({ type: "TLIMIT" }); setCountdown(180); setTimerActive(true); notifications.show({ title: "OTP Sent", message: "An OTP has been sent to your registered mobile.", color: "blue", }); } catch (err: any) { console.error("Send OTP failed", err); notifications.show({ title: "Error", message: err.message || "Send OTP failed. Try again later.", color: "red", }); } } async function handleVerifyOtp() { try { await verifyOtp(otp); return true; } catch { return false; } } const regenerateCaptcha = async () => { const newCaptcha = await generateCaptcha(); setCaptcha(newCaptcha); setCaptchaInput(""); }; 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]); useEffect(() => { regenerateCaptcha(); FetchDailyLimit(); }, []); const handleSubmit = async () => { if (step === "form") { if (!limit || !captchaInput) { notifications.show({ title: "Missing Field", message: "Please fill all mandatory fields.", color: "red", }); return; } if (isNaN(Number(limit)) || Number(limit) <= 0) { notifications.show({ title: "Invalid Limit", message: "Please enter a valid positive numeric transaction limit.", color: "red", }); return; } if (captchaInput !== captcha) { notifications.show({ title: "Invalid Captcha", message: "Please enter correct Captcha", color: "red", }); regenerateCaptcha(); return; } await handleSendOtp(); setStep("otp"); return; } if (step === "otp") { const verified = await handleVerifyOtp(); if (!verified) { notifications.show({ title: "Invalid OTP", message: "The OTP entered does not match.", color: "red", }); return; } setOtpValidated(true); setStep("final"); notifications.show({ title: "OTP Verified", message: "OTP has been successfully verified.", color: "green", }); return; } if (step === "final") { const token = localStorage.getItem("access_token"); if (!token) { router.push("/login"); return; } try { const response = await fetch("/api/customer/daily-limit", { method: "POST", headers: { "Content-Type": "application/json", "X-Login-Type": "IB", Authorization: `Bearer ${token}`, }, body: JSON.stringify({ amount: Number(limit), }), }); const result = await response.json(); if (!response.ok) { throw new Error(result.message || "Failed to set transaction limit"); } notifications.show({ title: "Success", message: `Transaction limit set successfully to ₹${limit}.`, color: "green", }); resetForm(); await FetchDailyLimit(); //refresh const otp_sended = await sendOtp({ type: "TLIMIT_SET", amount: Number(limit) }); } catch (err: any) { notifications.show({ title: "Error", message: err.message || "Server error, please try again later", color: "red", }); } } }; const resetForm = () => { setLimit(""); setCaptchaInput(""); setOtp(""); setOtpValidated(false); setStep("form"); regenerateCaptcha(); }; return ( Set Transaction Limit
{ const val = e.currentTarget.value; // Allow only digits AND max value 500000 if (/^\d*$/.test(val)) { const num = Number(val); if (num <= 500000) { setLimit(val); } } }} leftSection={icon} withAsterisk mb="sm" readOnly={step !== "form"} /> {dailyLimit !== null ? ( Your transaction limit per day is Rs. {dailyLimit.toFixed(2)} ) : ( • No daily limit set for this user )} {/* CAPTCHA */}
{captcha}
setCaptchaInput(e.currentTarget.value)} withAsterisk style={{ flexGrow: 1 }} readOnly={step !== "form"} />
{step !== "form" && ( setOtp(e.currentTarget.value)} withAsterisk disabled={otpValidated} style={{ flex: 1 }} /> {!otpValidated && (timerActive ? ( Resend OTP will be enabled in{" "} {String(Math.floor(countdown / 60)).padStart(2, "0")}: {String(countdown % 60).padStart(2, "0")} ) : ( ))} )}
Note :{" "} Please enter your desired transaction limit. OTP verification is required to confirm changes.
); }