Fix balance rerender (#994)
* remove confirm toast message on send pages * use balance refs to avoid logic reredners * remove await on submit
This commit is contained in:
@@ -87,6 +87,22 @@ export default function ConfirmSplitPayment(props) {
|
||||
const { t } = useTranslation();
|
||||
const { bitcoinBalance, dollarBalanceSat, dollarBalanceToken } =
|
||||
useUserBalanceContext();
|
||||
|
||||
// Latest-value ref for balances. The can-pay memo and swap-fee effect read
|
||||
// balance through this ref instead of the reactive context values so balance
|
||||
// is dropped from their dependency arrays. A burst of incoming payments then
|
||||
// can't recompute payment viability or refire simulateSwap mid-send; the
|
||||
// effect still reads the current balance whenever it legitimately re-runs.
|
||||
// The actual send validates live balance at send time.
|
||||
const balanceRef = useRef({
|
||||
bitcoinBalance,
|
||||
dollarBalanceSat,
|
||||
dollarBalanceToken,
|
||||
});
|
||||
balanceRef.current.bitcoinBalance = bitcoinBalance;
|
||||
balanceRef.current.dollarBalanceSat = dollarBalanceSat;
|
||||
balanceRef.current.dollarBalanceToken = dollarBalanceToken;
|
||||
|
||||
const { currentWalletMnemoinc } = useActiveCustodyAccount();
|
||||
const { contactsPrivateKey } = useKeysContext();
|
||||
const { sparkInformation } = useSparkWallet();
|
||||
@@ -186,6 +202,8 @@ export default function ConfirmSplitPayment(props) {
|
||||
// ── Balance validation ──────────────────────────────────────────────────────
|
||||
|
||||
const { canPayBTC, canPayUSD } = useMemo(() => {
|
||||
// eslint-disable-next-line no-shadow -- read frozen balance, decoupled from live deps
|
||||
const { bitcoinBalance, dollarBalanceSat } = balanceRef.current;
|
||||
const price = poolInfoRef.currentPriceAInB;
|
||||
return validateSplitPayment({
|
||||
totalSats: totalSplitSats,
|
||||
@@ -202,8 +220,6 @@ export default function ConfirmSplitPayment(props) {
|
||||
}, [
|
||||
totalSplitSats,
|
||||
paymentCurrency,
|
||||
bitcoinBalance,
|
||||
dollarBalanceSat,
|
||||
swapLimits,
|
||||
masterInfoObject,
|
||||
swapUSDPriceDollars,
|
||||
@@ -270,6 +286,8 @@ export default function ConfirmSplitPayment(props) {
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
// eslint-disable-next-line no-shadow -- read frozen balance, decoupled from live deps
|
||||
const { bitcoinBalance, dollarBalanceSat } = balanceRef.current;
|
||||
|
||||
const clearSwapFee = () => {
|
||||
swapFeeKeyRef.current = null;
|
||||
@@ -405,8 +423,6 @@ export default function ConfirmSplitPayment(props) {
|
||||
poolInfoRef,
|
||||
totalSplitSats,
|
||||
totalSplitDollars,
|
||||
bitcoinBalance,
|
||||
dollarBalanceSat,
|
||||
min_usd_swap_amount,
|
||||
swapLimits.bitcoin,
|
||||
currentWalletMnemoinc,
|
||||
|
||||
@@ -116,6 +116,21 @@ export default function SendPaymentScreen(props) {
|
||||
const { t } = useTranslation();
|
||||
const { bitcoinBalance, dollarBalanceSat, dollarBalanceToken } =
|
||||
useUserBalanceContext();
|
||||
|
||||
// Latest-value ref for balances (same pattern as stablecoinSendScreen). The
|
||||
// send-decision memos/effects read balance through this ref instead of the
|
||||
// reactive context values, so balance is dropped from their dependency
|
||||
// arrays. A burst of incoming payments then can't recompute the payment
|
||||
// method, flip uiState, or refire fee estimation mid-send. The actual send
|
||||
// still validates against live balance via sparkInfoRef.current.
|
||||
const balanceRef = useRef({
|
||||
bitcoinBalance,
|
||||
dollarBalanceSat,
|
||||
dollarBalanceToken,
|
||||
});
|
||||
balanceRef.current.bitcoinBalance = bitcoinBalance;
|
||||
balanceRef.current.dollarBalanceSat = dollarBalanceSat;
|
||||
balanceRef.current.dollarBalanceToken = dollarBalanceToken;
|
||||
const { sendWebViewRequest } = useWebView();
|
||||
const { currentWalletMnemoinc } = useActiveCustodyAccount();
|
||||
const { accountMnemoinc, contactsPrivateKey, publicKey } = useKeysContext();
|
||||
@@ -264,6 +279,9 @@ export default function SendPaymentScreen(props) {
|
||||
(isLightningPayment && paymentInfo?.usingZeroAmountInvoice);
|
||||
|
||||
const resolvedPaymentMethod = useMemo(() => {
|
||||
// eslint-disable-next-line no-shadow -- read frozen balance, decoupled from live deps
|
||||
const { bitcoinBalance, dollarBalanceSat, dollarBalanceToken } =
|
||||
balanceRef.current;
|
||||
if (!paymentInfo || !Object.keys(paymentInfo || {}).length)
|
||||
return undefined;
|
||||
|
||||
@@ -328,9 +346,6 @@ export default function SendPaymentScreen(props) {
|
||||
enteredPaymentInfo?.inputCurrency,
|
||||
userPaymentMethod,
|
||||
paymentInfo,
|
||||
dollarBalanceSat,
|
||||
dollarBalanceToken,
|
||||
bitcoinBalance,
|
||||
isBitcoinPayment,
|
||||
isUsingLRC20,
|
||||
isSparkPayment,
|
||||
@@ -449,6 +464,8 @@ export default function SendPaymentScreen(props) {
|
||||
);
|
||||
|
||||
const requiresUserMethodSelection = useMemo(() => {
|
||||
// eslint-disable-next-line no-shadow -- read frozen balance, decoupled from live deps
|
||||
const { bitcoinBalance, dollarBalanceSat } = balanceRef.current;
|
||||
if (resolvedPaymentMethod === undefined) return false;
|
||||
if (
|
||||
!!preSelectedPaymentMethod ||
|
||||
@@ -492,8 +509,6 @@ export default function SendPaymentScreen(props) {
|
||||
didSelectPaymentMethod,
|
||||
sparkInformation?.didConnectToFlashnet,
|
||||
paymentInfo?.data?.expectedReceive,
|
||||
bitcoinBalance,
|
||||
dollarBalanceSat,
|
||||
amountViableForSwap,
|
||||
resolvedPaymentMethod,
|
||||
receiverExpectsCurrency,
|
||||
@@ -522,6 +537,9 @@ export default function SendPaymentScreen(props) {
|
||||
|
||||
const estimateLightningFee = useCallback(
|
||||
async (amount, id) => {
|
||||
// eslint-disable-next-line no-shadow -- read frozen balance, decoupled from live deps
|
||||
const { bitcoinBalance, dollarBalanceSat, dollarBalanceToken } =
|
||||
balanceRef.current;
|
||||
if (!amount || !isLightningPayment || !canEditAmount) {
|
||||
setIsEstimatingFee(false);
|
||||
return;
|
||||
@@ -667,9 +685,6 @@ export default function SendPaymentScreen(props) {
|
||||
isLightningPayment,
|
||||
canEditAmount,
|
||||
resolvedPaymentMethod,
|
||||
dollarBalanceToken,
|
||||
dollarBalanceSat,
|
||||
bitcoinBalance,
|
||||
paymentInfo,
|
||||
currentWalletMnemoinc,
|
||||
masterInfoObject,
|
||||
|
||||
@@ -460,7 +460,7 @@ export default function StablecoinSendScreen() {
|
||||
|
||||
await bulkUpdateSparkTransactions([pendingTx], 'fullUpdate');
|
||||
|
||||
await fetchBackend(
|
||||
fetchBackend(
|
||||
'submitFlashnetStablecoinOrder',
|
||||
{
|
||||
quoteId: quote.quoteId,
|
||||
|
||||
@@ -129,6 +129,23 @@ const SKIP_CONFIRM_NAV_UPDATE_TYPES = new Set([
|
||||
'incrementalRestore',
|
||||
]);
|
||||
|
||||
// Send screens where an incoming-payment toast would obscure the send UI. Keyed
|
||||
// by the route names registered in navigation/screens.js.
|
||||
const BLOCKED_TOAST_ROUTE_NAMES = new Set([
|
||||
'ConfirmPaymentScreen', // sendPaymentScreen.js
|
||||
'ConfirmSplitPayment', // confirmSplitPayment.js
|
||||
'StablecoinSendScreen', // stablecoinSendScreen.js
|
||||
]);
|
||||
|
||||
function isOnSendScreen() {
|
||||
try {
|
||||
if (!navigationRef.isReady()) return false;
|
||||
return BLOCKED_TOAST_ROUTE_NAMES.has(navigationRef.getCurrentRoute()?.name);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Initiate context
|
||||
const SparkWalletManager = createContext(null);
|
||||
|
||||
@@ -743,6 +760,11 @@ const SparkWalletProvider = ({ children }) => {
|
||||
}
|
||||
handledNavigatedTxs.current.add(parsedTx.sparkID);
|
||||
|
||||
if (isOnSendScreen()) {
|
||||
console.log('On a send screen — suppressing incoming payment toast');
|
||||
return;
|
||||
}
|
||||
|
||||
// const isOnReceivePage =
|
||||
// navigationRef
|
||||
// .getRootState()
|
||||
@@ -1857,11 +1879,13 @@ const SparkWalletProvider = ({ children }) => {
|
||||
if (updatedTx.details) {
|
||||
if (handledNavigatedTxs.current.has(updatedTx.id)) continue;
|
||||
handledNavigatedTxs.current.add(updatedTx.id);
|
||||
showToast({
|
||||
amount: updatedTx.details.amount,
|
||||
duration: 7000,
|
||||
type: 'confirmTx',
|
||||
});
|
||||
if (!isOnSendScreen()) {
|
||||
showToast({
|
||||
amount: updatedTx.details.amount,
|
||||
duration: 7000,
|
||||
type: 'confirmTx',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user