diff --git a/src/components/modals/budget-modal.tsx b/src/components/modals/budget-modal.tsx index 2ec4d14..019c1c5 100644 --- a/src/components/modals/budget-modal.tsx +++ b/src/components/modals/budget-modal.tsx @@ -14,7 +14,7 @@ import { Button } from "@/components/ui/button" import { useModalStore } from "@/stores/modal-store" import { useUserStore } from "@/stores/user-store" import { isSphinx, hasWebLN, payInvoice, payL402, topUpLsat, topUpConfirm, fetchTransactionHistory, pollPaymentStatus, fetchBuyLsatChallenge, TransactionRow } from "@/lib/sphinx" -import { getActionDisplayLabel, getActionBadgeColor } from "@/lib/transaction-display" +import { getActionDisplayLabel, getActionBadgeColor, isViewGrantRow } from "@/lib/transaction-display" import { isMocksEnabled, MOCK_TRANSACTIONS } from "@/lib/mock-data" import { cookieStorage } from "@/lib/cookie-storage" import { api } from "@/lib/api" @@ -45,7 +45,7 @@ export function BudgetModal() { const [paymentRequest, setPaymentRequest] = useState("") const [paymentHash, setPaymentHash] = useState("") const [copied, setCopied] = useState(false) - const intervalRef = useRef | null>(null) + const pollAbortRef = useRef(null) // First-purchase state (non-Sphinx, non-WebLN, no existing L402) const [firstPurchaseAmount, setFirstPurchaseAmount] = useState(1000) @@ -63,8 +63,15 @@ export function BudgetModal() { ? budget.toLocaleString() : "--" + const cancelPoll = useCallback(() => { + pollAbortRef.current?.abort() + pollAbortRef.current = null + setLoading(false) + setError("") + }, []) + const resetState = useCallback(() => { - if (intervalRef.current) clearInterval(intervalRef.current) + cancelPoll() setStep("balance") setAmount(null) setPaymentRequest("") @@ -88,7 +95,7 @@ export function BudgetModal() { useEffect(() => { return () => { - if (intervalRef.current) clearInterval(intervalRef.current) + pollAbortRef.current?.abort() } }, []) @@ -199,12 +206,15 @@ export function BudgetModal() { } setError("") setLoading(true) + const controller = new AbortController() + pollAbortRef.current = controller try { const challenge = await fetchBuyLsatChallenge(firstPurchaseAmount) setFirstPurchaseRequest(challenge.invoice) setStep("first-invoice") - const paid = await pollPaymentStatus(challenge.paymentHash) + const paid = await pollPaymentStatus(challenge.paymentHash, 20, 2000, controller.signal) + if (controller.signal.aborted) return if (!paid) { setError("Payment not detected. Try again.") setStep("first-purchase") @@ -281,10 +291,12 @@ export function BudgetModal() { setPaymentHash(result.payment_hash) setStep("invoice") + const manualController = new AbortController() + pollAbortRef.current = manualController let confirming = false - const paid = await pollPaymentStatus(result.payment_hash, 100, 3000) + const paid = await pollPaymentStatus(result.payment_hash, 100, 3000, manualController.signal) + if (manualController.signal.aborted) return if (!paid) { - if (intervalRef.current) clearInterval(intervalRef.current) setError("Payment not detected. Try again.") setStep("amount") return @@ -339,19 +351,22 @@ export function BudgetModal() { {step !== "balance" && (