From cd72f9bd7841c65e8d8c45613616bc5ef8577b8c Mon Sep 17 00:00:00 2001 From: Randy Schott <1815175+schottra@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:06:47 -0500 Subject: [PATCH] [PAY-2238] Improve balance display with recovery process (#7322) --- packages/common/src/hooks/useUSDCBalance.ts | 11 ++++- packages/common/src/store/buy-usdc/sagas.ts | 28 +++++++++++ .../hooks/usePurchaseContentFormState.ts | 16 ++----- .../usdc-balance-pill/USDCBalancePill.tsx | 7 +-- .../hooks/usePurchaseContentFormState.ts | 14 +----- .../usdc-balance-pill/USDCBalancePill.tsx | 5 +- .../components/TransferSuccessful.tsx | 2 +- .../pages/dashboard-page/DashboardPage.tsx | 20 +------- .../pay-and-earn-page/PayAndEarnPage.tsx | 10 +--- .../components/USDCCard.module.css | 4 +- .../pay-and-earn-page/components/USDCCard.tsx | 48 +++++++++++-------- .../desktop/PayAndEarnPage.tsx | 13 ++--- .../mobile/PayAndEarnPage.tsx | 13 ++--- 13 files changed, 88 insertions(+), 103 deletions(-) diff --git a/packages/common/src/hooks/useUSDCBalance.ts b/packages/common/src/hooks/useUSDCBalance.ts index a58c5bc0afb..1d58c38b995 100644 --- a/packages/common/src/hooks/useUSDCBalance.ts +++ b/packages/common/src/hooks/useUSDCBalance.ts @@ -55,6 +55,7 @@ export const useUSDCBalance = ({ } }, [audiusBackend, setData]) + // Refresh balance on mount useEffect(() => { refresh() }, [refresh]) @@ -69,5 +70,13 @@ export const useUSDCBalance = ({ clearInterval(id) }, [id]) - return { balanceStatus, recoveryStatus, data, refresh, cancelPolling } + // If we haven't loaded the balance yet for the first time or we're + // actively recovering, then we will be in loading state. + const status = + balanceStatus === Status.IDLE || + (balanceStatus === Status.LOADING && data === null) || + recoveryStatus === Status.LOADING + ? Status.LOADING + : balanceStatus + return { status, data, refresh, cancelPolling } } diff --git a/packages/common/src/store/buy-usdc/sagas.ts b/packages/common/src/store/buy-usdc/sagas.ts index 3ba790fc3d0..8218bae91ce 100644 --- a/packages/common/src/store/buy-usdc/sagas.ts +++ b/packages/common/src/store/buy-usdc/sagas.ts @@ -46,6 +46,8 @@ import { } from './slice' import { BuyUSDCError, BuyUSDCErrorCode } from './types' import { getBuyUSDCRemoteConfig, getUSDCUserBank } from './utils' +import { setUSDCBalance } from 'store/wallet/slice' +import { StringUSDC } from 'models/Wallet' type PurchaseStepParams = { desiredAmount: number @@ -424,6 +426,17 @@ function* recoverPurchaseIfNecessary() { return } + const userBankAccountInfo = yield* call( + getTokenAccountInfo, + audiusBackendInstance, + { + tokenAccount: userBank, + mint: 'usdc' + } + ) + + const userBankInitialBalance = userBankAccountInfo?.amount ?? BigInt(0) + const userBankAddress = userBank.toBase58() // Transfer all USDC from the from the root wallet to the user bank @@ -480,6 +493,21 @@ function* recoverPurchaseIfNecessary() { } ) + const updatedBalance = yield* call( + pollForTokenBalanceChange, + audiusBackendInstance, + { + tokenAccount: userBank, + mint: 'usdc', + initialBalance: userBankInitialBalance, + maxRetryCount: TRANSACTION_RETRY_COUNT + } + ) + + yield* put( + setUSDCBalance({ amount: updatedBalance.toString() as StringUSDC }) + ) + yield* put(recoveryStatusChanged({ status: Status.SUCCESS })) yield* call( track, diff --git a/packages/mobile/src/components/premium-track-purchase-drawer/hooks/usePurchaseContentFormState.ts b/packages/mobile/src/components/premium-track-purchase-drawer/hooks/usePurchaseContentFormState.ts index 362db120c31..90f2bc1ed40 100644 --- a/packages/mobile/src/components/premium-track-purchase-drawer/hooks/usePurchaseContentFormState.ts +++ b/packages/mobile/src/components/premium-track-purchase-drawer/hooks/usePurchaseContentFormState.ts @@ -1,10 +1,7 @@ -import { useEffect } from 'react' - import { - purchaseContentSelectors, isContentPurchaseInProgress, - useUSDCBalance, - Status + purchaseContentSelectors, + useUSDCBalance } from '@audius/common' import { useSelector } from 'react-redux' @@ -22,14 +19,7 @@ export const usePurchaseContentFormState = ({ price }: { price: number }) => { const error = useSelector(getPurchaseContentError) const isUnlocking = !error && isContentPurchaseInProgress(stage) - const { data: currentBalance, recoveryStatus, refresh } = useUSDCBalance() - - // Refresh balance on successful recovery - useEffect(() => { - if (recoveryStatus === Status.SUCCESS) { - refresh() - } - }, [recoveryStatus, refresh]) + const { data: currentBalance } = useUSDCBalance() const purchaseSummaryValues = usePurchaseSummaryValues({ price, diff --git a/packages/mobile/src/components/usdc-balance-pill/USDCBalancePill.tsx b/packages/mobile/src/components/usdc-balance-pill/USDCBalancePill.tsx index c21d5c45bbc..c4b42228d60 100644 --- a/packages/mobile/src/components/usdc-balance-pill/USDCBalancePill.tsx +++ b/packages/mobile/src/components/usdc-balance-pill/USDCBalancePill.tsx @@ -33,10 +33,7 @@ const useStyles = makeStyles(({ spacing, palette }) => ({ export const USDCBalancePill = () => { const styles = useStyles() - const { data: usdcBalance, balanceStatus: usdcBalanceStatus } = - useUSDCBalance() - const isUsdcBalanceLoading = - usdcBalance === null || usdcBalanceStatus === Status.LOADING + const { data: usdcBalance, status: usdcBalanceStatus } = useUSDCBalance() const balanceCents = formatUSDCWeiToFloorCentsNumber( (usdcBalance ?? new BN(0)) as BNUSDC ) @@ -44,7 +41,7 @@ export const USDCBalancePill = () => { return ( - {isUsdcBalanceLoading ? ( + {usdcBalanceStatus === Status.LOADING ? ( { const error = useSelector(getPurchaseContentError) const isUnlocking = !error && isContentPurchaseInProgress(stage) - const { data: currentBalance, recoveryStatus, refresh } = useUSDCBalance() - - // Refresh balance on successful recovery - useEffect(() => { - if (recoveryStatus === Status.SUCCESS) { - refresh() - } - }, [recoveryStatus, refresh]) + const { data: currentBalance } = useUSDCBalance() const purchaseSummaryValues = usePurchaseSummaryValues({ price, diff --git a/packages/web/src/components/usdc-balance-pill/USDCBalancePill.tsx b/packages/web/src/components/usdc-balance-pill/USDCBalancePill.tsx index 0b7dfec7b83..c5e881615e6 100644 --- a/packages/web/src/components/usdc-balance-pill/USDCBalancePill.tsx +++ b/packages/web/src/components/usdc-balance-pill/USDCBalancePill.tsx @@ -19,8 +19,7 @@ type USDCPillProps = { } export const USDCBalancePill = ({ className }: USDCPillProps) => { - const { data: balance, balanceStatus: usdcBalanceStatus } = useUSDCBalance() - const isLoading = balance === null || usdcBalanceStatus === Status.LOADING + const { data: balance, status: usdcBalanceStatus } = useUSDCBalance() const balanceCents = formatUSDCWeiToFloorCentsNumber( (balance ?? new BN(0)) as BNUSDC ) @@ -29,7 +28,7 @@ export const USDCBalancePill = ({ className }: USDCPillProps) => { return (
- {isLoading ? ( + {usdcBalanceStatus === Status.LOADING ? ( ) : ( ${balanceFormatted} diff --git a/packages/web/src/components/withdraw-usdc-modal/components/TransferSuccessful.tsx b/packages/web/src/components/withdraw-usdc-modal/components/TransferSuccessful.tsx index 377c42b3b6d..09df53ec7bf 100644 --- a/packages/web/src/components/withdraw-usdc-modal/components/TransferSuccessful.tsx +++ b/packages/web/src/components/withdraw-usdc-modal/components/TransferSuccessful.tsx @@ -60,7 +60,7 @@ export const TransferSuccessful = ({ priorBalanceCents: number onClickDone: () => void }) => { - const { data: balance, balanceStatus } = useUSDCBalance() + const { data: balance, status: balanceStatus } = useUSDCBalance() const signature = useSelector(getWithdrawTransaction) const balanceNumber = formatUSDCWeiToFloorCentsNumber( (balance ?? new BN(0)) as BNUSDC diff --git a/packages/web/src/pages/dashboard-page/DashboardPage.tsx b/packages/web/src/pages/dashboard-page/DashboardPage.tsx index 8695c0882b0..7bad31e0941 100644 --- a/packages/web/src/pages/dashboard-page/DashboardPage.tsx +++ b/packages/web/src/pages/dashboard-page/DashboardPage.tsx @@ -1,13 +1,6 @@ import { useState, Suspense, ReactNode, useEffect, useCallback } from 'react' -import { - Status, - Track, - formatCount, - themeSelectors, - combineStatuses, - useUSDCBalance -} from '@audius/common' +import { Status, Track, formatCount, themeSelectors } from '@audius/common' import cn from 'classnames' import { each } from 'lodash' import moment, { Moment } from 'moment' @@ -77,12 +70,6 @@ export const DashboardPage = () => { const listenData = useSelector(getDashboardListenData) const dashboardStatus = useSelector(getDashboardStatus) const theme = useSelector(getTheme) - const { data: balance, balanceStatus } = useUSDCBalance() - const statuses = [dashboardStatus] - if (balance === null) { - statuses.push(balanceStatus) - } - const status = combineStatuses(statuses) const header =
@@ -187,10 +174,7 @@ export const DashboardPage = () => { contentClassName={styles.pageContainer} header={header} > - {!account || - balance === null || - !listenData || - status === Status.LOADING ? ( + {!account || !listenData || dashboardStatus === Status.LOADING ? ( ) : ( <> diff --git a/packages/web/src/pages/pay-and-earn-page/PayAndEarnPage.tsx b/packages/web/src/pages/pay-and-earn-page/PayAndEarnPage.tsx index c2805c9be34..5deab191da6 100644 --- a/packages/web/src/pages/pay-and-earn-page/PayAndEarnPage.tsx +++ b/packages/web/src/pages/pay-and-earn-page/PayAndEarnPage.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react' -import { Status, buyUSDCActions, useUSDCBalance } from '@audius/common' +import { buyUSDCActions } from '@audius/common' import { useDispatch } from 'react-redux' import { useIsMobile } from 'utils/clientUtil' @@ -12,14 +12,6 @@ import { PayAndEarnPageProps } from './types' export const PayAndEarnPage = (props: PayAndEarnPageProps) => { const isMobile = useIsMobile() const dispatch = useDispatch() - const { recoveryStatus, refresh } = useUSDCBalance() - - // Refresh balance on successful recovery - useEffect(() => { - if (recoveryStatus === Status.SUCCESS) { - refresh() - } - }, [recoveryStatus, refresh]) // Always check for recoverable USDC on page load useEffect(() => { diff --git a/packages/web/src/pages/pay-and-earn-page/components/USDCCard.module.css b/packages/web/src/pages/pay-and-earn-page/components/USDCCard.module.css index 39fab796fb2..93fdf499c2e 100644 --- a/packages/web/src/pages/pay-and-earn-page/components/USDCCard.module.css +++ b/packages/web/src/pages/pay-and-earn-page/components/USDCCard.module.css @@ -48,8 +48,8 @@ } .spinner { - height: var(--unit-5); - width: var(--unit-5); + height: var(--unit-8); + width: var(--unit-8); align-self: center; } diff --git a/packages/web/src/pages/pay-and-earn-page/components/USDCCard.tsx b/packages/web/src/pages/pay-and-earn-page/components/USDCCard.tsx index eef22f97f3b..70489398904 100644 --- a/packages/web/src/pages/pay-and-earn-page/components/USDCCard.tsx +++ b/packages/web/src/pages/pay-and-earn-page/components/USDCCard.tsx @@ -7,7 +7,9 @@ import { formatCurrencyBalance, formatUSDCWeiToFloorCentsNumber, useWithdrawUSDCModal, - useAddFundsModal + useAddFundsModal, + useUSDCBalance, + Status } from '@audius/common' import { Button, PlainButton, IconQuestionCircle, Flex } from '@audius/harmony' import { LogoUSDC } from '@audius/stems' @@ -34,15 +36,10 @@ const messages = { withdrawalHistory: 'Withdrawal History' } -export const USDCCard = ({ - balance, - refreshing = false -}: { - balance: BNUSDC - refreshing?: boolean -}) => { +export const USDCCard = () => { const { onOpen: openWithdrawUSDCModal } = useWithdrawUSDCModal() const { onOpen: openAddFundsModal } = useAddFundsModal() + const { data: balance, status: balanceStatus } = useUSDCBalance() const balanceCents = formatUSDCWeiToFloorCentsNumber( (balance ?? new BN(0)) as BNUSDC @@ -93,15 +90,18 @@ export const USDCCard = ({
- {refreshing && } - - ${balanceFormatted} - + {balanceStatus === Status.LOADING ? ( + + ) : ( + + ${balanceFormatted} + + )}
@@ -117,12 +117,22 @@ export const USDCCard = ({
-
-
diff --git a/packages/web/src/pages/pay-and-earn-page/desktop/PayAndEarnPage.tsx b/packages/web/src/pages/pay-and-earn-page/desktop/PayAndEarnPage.tsx index 10518f28355..267f535ef05 100644 --- a/packages/web/src/pages/pay-and-earn-page/desktop/PayAndEarnPage.tsx +++ b/packages/web/src/pages/pay-and-earn-page/desktop/PayAndEarnPage.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useState } from 'react' -import { useUSDCBalance, accountSelectors, Status } from '@audius/common' +import { accountSelectors } from '@audius/common' import { Button, Flex, @@ -42,7 +42,6 @@ type TableMetadata = { export const PayAndEarnPage = ({ tableView }: PayAndEarnPageProps) => { const dispatch = useDispatch() - const { data: balance, balanceStatus, recoveryStatus } = useUSDCBalance() const accountHasTracks = useSelector(getAccountHasTracks) const [tableOptions, setTableOptions] = useState(null) @@ -135,17 +134,11 @@ export const PayAndEarnPage = ({ tableView }: PayAndEarnPageProps) => { contentClassName={styles.pageContainer} header={header} > - {!tableOptions || !selectedTable || balance === null ? ( + {!tableOptions || !selectedTable ? ( ) : ( <> - + { const dispatch = useDispatch() - const { data: balance, balanceStatus, recoveryStatus } = useUSDCBalance() const accountHasTracks = useSelector(getAccountHasTracks) const [tableOptions, setTableOptions] = useState(null) @@ -134,17 +133,11 @@ export const PayAndEarnPage = ({ tableView }: PayAndEarnPageProps) => { description={messages.description} containerClassName={styles.mobilePageContainer} > - {!tableOptions || !selectedTable || balance === null ? ( + {!tableOptions || !selectedTable ? ( ) : ( <> - +