diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx index 08926094e..6a0bf6e5e 100644 --- a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx @@ -1,8 +1,9 @@ -import React, { useCallback } from "react" +import React, { useCallback, useRef } from "react" import { useActionFlowPause, useActionFlowTokenAmount, useAppDispatch, + useCancelPromise, useDepositBTCTransaction, useInvalidateQueries, useStakeFlowContext, @@ -28,6 +29,12 @@ export default function DepositBTCModal() { queryKey: userKeys.balance(), }) + const sessionId = useRef(Math.random()) + const { cancel, resolve, sessionIdToPromise } = useCancelPromise( + sessionId.current, + "Deposit cancelled", + ) + const onStakeBTCSuccess = useCallback(() => { handleBitcoinBalanceInvalidation() dispatch(setStatus(PROCESS_STATUSES.SUCCEEDED)) @@ -58,13 +65,15 @@ export default function DepositBTCModal() { const onDepositBTCError = useCallback( (error: unknown) => { + if (!sessionIdToPromise[sessionId.current].shouldOpenErrorModal) return + if (eip1193.didUserRejectRequest(error)) { handlePause() } else { onError(error) } }, - [onError, handlePause], + [sessionIdToPromise, handlePause, onError], ) const { mutate: sendBitcoinTransaction, status } = useDepositBTCTransaction({ @@ -79,6 +88,8 @@ export default function DepositBTCModal() { btcAddress, ) + await resolve() + if (verificationStatus === "valid") { sendBitcoinTransaction({ recipient: btcAddress, @@ -92,6 +103,7 @@ export default function DepositBTCModal() { btcAddress, depositReceipt, verifyDepositAddress, + resolve, sendBitcoinTransaction, onError, ]) @@ -105,5 +117,5 @@ export default function DepositBTCModal() { if (status === "pending" || status === "success") return - return + return } diff --git a/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx b/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx index 915a9436a..877f83264 100644 --- a/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx @@ -1,8 +1,9 @@ -import React, { useCallback, useEffect, useRef, useState } from "react" +import React, { useCallback, useRef, useState } from "react" import { useActionFlowPause, useActionFlowTokenAmount, useAppDispatch, + useCancelPromise, useInvalidateQueries, useModal, useTimeout, @@ -22,15 +23,6 @@ const { userKeys } = queryKeysFactory type WithdrawalStatus = "building-data" | "built-data" | "signature" -const sessionIdToPromise: Record< - number, - { - promise: Promise - cancel: (reason: Error) => void - shouldOpenErrorModal: boolean - } -> = {} - export default function SignMessageModal() { const [status, setWaitingStatus] = useState("building-data") @@ -44,24 +36,15 @@ export default function SignMessageModal() { queryKey: userKeys.position(), }) const sessionId = useRef(Math.random()) + const { cancel, resolve, sessionIdToPromise } = useCancelPromise( + sessionId.current, + "Withdrawal cancelled", + ) const { transactionFee } = useTransactionDetails( amount, ACTION_FLOW_TYPES.UNSTAKE, ) - useEffect(() => { - let cancel = (_: Error) => {} - const promise: Promise = new Promise((_, reject) => { - cancel = reject - }) - - sessionIdToPromise[sessionId.current] = { - cancel, - promise, - shouldOpenErrorModal: true, - } - }, []) - const dataBuiltStepCallback = useCallback(() => { setWaitingStatus("built-data") return Promise.resolve() @@ -69,11 +52,8 @@ export default function SignMessageModal() { const onSignMessageCallback = useCallback(async () => { setWaitingStatus("signature") - return Promise.race([ - sessionIdToPromise[sessionId.current].promise, - Promise.resolve(), - ]) - }, []) + return resolve() + }, [resolve]) const onSignMessageSuccess = useCallback(() => { handleBitcoinPositionInvalidation() @@ -98,7 +78,7 @@ export default function SignMessageModal() { onSignMessageError(error) } }, - [onSignMessageError, handlePause], + [sessionIdToPromise, handlePause, onSignMessageError], ) const { mutate: handleSignMessage } = useMutation({ @@ -151,16 +131,7 @@ export default function SignMessageModal() { }) const onClose = () => { - const currentSessionId = sessionId.current - const sessionData = sessionIdToPromise[currentSessionId] - sessionIdToPromise[currentSessionId] = { - ...sessionData, - shouldOpenErrorModal: false, - } - - sessionIdToPromise[currentSessionId].cancel( - new Error("Withdrawal cancelled"), - ) + cancel() closeModal() } diff --git a/dapp/src/components/TransactionModal/WalletInteractionModal.tsx b/dapp/src/components/TransactionModal/WalletInteractionModal.tsx index 8011648f6..8c3926d1f 100644 --- a/dapp/src/components/TransactionModal/WalletInteractionModal.tsx +++ b/dapp/src/components/TransactionModal/WalletInteractionModal.tsx @@ -50,8 +50,10 @@ const DATA: Record< export default function WalletInteractionModal({ step, + onClose, }: { step: WalletInteractionStep + onClose?: () => void }) { const actionType = useActionFlowType() const connector = useConnector() @@ -60,7 +62,7 @@ export default function WalletInteractionModal({ return ( <> - {step === "opening-wallet" && } + {step === "opening-wallet" && } {header} diff --git a/dapp/src/hooks/index.ts b/dapp/src/hooks/index.ts index 28bc42703..db36d2455 100644 --- a/dapp/src/hooks/index.ts +++ b/dapp/src/hooks/index.ts @@ -38,3 +38,4 @@ export { default as useScrollbarVisibility } from "./useScrollbarVisibility" export { default as useAccessCode } from "./useAccessCode" export { default as useFormField } from "./useFormField" export { default as useDepositBTCTransaction } from "./useDepositBTCTransaction" +export { default as useCancelPromise } from "./useCancelPromise" diff --git a/dapp/src/hooks/useCancelPromise.ts b/dapp/src/hooks/useCancelPromise.ts new file mode 100644 index 000000000..a6bb1666b --- /dev/null +++ b/dapp/src/hooks/useCancelPromise.ts @@ -0,0 +1,50 @@ +import { useCallback, useEffect } from "react" + +const sessionIdToPromise: Record< + number, + { + promise: Promise + cancel: (reason: Error) => void + shouldOpenErrorModal: boolean + } +> = {} + +export default function useCancelPromise( + sessionId: number, + errorMsgText: string, +) { + useEffect(() => { + let cancel = (_: Error) => {} + const promise: Promise = new Promise((_, reject) => { + cancel = reject + }) + + sessionIdToPromise[sessionId] = { + cancel, + promise, + shouldOpenErrorModal: true, + } + }, [sessionId]) + + const cancel = useCallback(() => { + const sessionData = sessionIdToPromise[sessionId] + sessionIdToPromise[sessionId] = { + ...sessionData, + shouldOpenErrorModal: false, + } + + sessionIdToPromise[sessionId].cancel(new Error(errorMsgText)) + }, [errorMsgText, sessionId]) + + const resolve = useCallback( + () => + Promise.race([sessionIdToPromise[sessionId].promise, Promise.resolve()]), + [sessionId], + ) + + return { + cancel, + resolve, + sessionIdToPromise, + } +} diff --git a/dapp/src/hooks/useTransactionModal.ts b/dapp/src/hooks/useTransactionModal.ts index e052ed131..7e4b9d0be 100644 --- a/dapp/src/hooks/useTransactionModal.ts +++ b/dapp/src/hooks/useTransactionModal.ts @@ -1,4 +1,4 @@ -import { ACTION_FLOW_TYPES, ActionFlowType, MODAL_TYPES } from "#/types" +import { ActionFlowType, MODAL_TYPES } from "#/types" import { useCallback } from "react" import { useModal } from "./useModal" @@ -8,7 +8,7 @@ export function useTransactionModal(type: ActionFlowType) { return useCallback(() => { openModal(MODAL_TYPES[type], { type, - closeOnEsc: type !== ACTION_FLOW_TYPES.UNSTAKE, + closeOnEsc: false, }) }, [openModal, type]) }