Skip to content

Commit

Permalink
Merge pull request #27146 from brave/feat-wallet-prompt-select-accoun…
Browse files Browse the repository at this point in the history
…t-when-sending-from-portfolio

feat(wallet): Prompt Select Account when Sending from Portfolio
  • Loading branch information
Douglashdaniel authored Jan 8, 2025
2 parents 023b7e6 + 6c69732 commit d14ca67
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as React from 'react'
import { useHistory } from 'react-router'

// Types
import { BraveWallet, WalletRoutes } from '../../../constants/types'
import { BraveWallet } from '../../../constants/types'

// Queries
import {
Expand Down Expand Up @@ -106,11 +106,7 @@ export const AssetItemMenu = (props: Props) => {
}, [foundMeldBuyToken, history, account, foundAndroidBuyToken, asset])

const onClickSend = React.useCallback(() => {
if (account) {
history.push(makeSendRoute(asset, account))
} else {
history.push(WalletRoutes.Send)
}
history.push(makeSendRoute(asset, account))
}, [account, history, asset])

const onClickSwap = React.useCallback(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import * as React from 'react'
import Icon from '@brave/leo/react/icon'
import { skipToken } from '@reduxjs/toolkit/query/react'
import { useHistory } from 'react-router'

// Selectors
import {
Expand All @@ -19,7 +20,11 @@ import { useSafeUISelector } from '../../../../common/hooks/use-safe-selector'
import { UISelectors } from '../../../../common/selectors'

// Types
import { BraveWallet, SendPageTabHashes } from '../../../../constants/types'
import {
BraveWallet,
SendPageTabHashes,
WalletRoutes
} from '../../../../constants/types'
import {
TokenBalancesRegistry //
} from '../../../../common/slices/entities/token-balance.entity'
Expand Down Expand Up @@ -172,6 +177,7 @@ interface Props {
onSelectSendOption?: (sendOption: SendPageTabHashes) => void
selectedNetwork?: BraveWallet.NetworkInfo
modalType: 'send' | 'swap' | 'bridge'
needsAccount?: boolean
}

export const SelectTokenModal = React.forwardRef<HTMLDivElement, Props>(
Expand All @@ -185,9 +191,13 @@ export const SelectTokenModal = React.forwardRef<HTMLDivElement, Props>(
onSelectAsset,
onSelectSendOption,
selectedNetwork,
modalType
modalType,
needsAccount
} = props

// Routing
const history = useHistory()

// State
const [searchValue, setSearchValue] = React.useState<string>('')
const [selectedNetworkFilter, setSelectedNetworkFilter] =
Expand All @@ -196,13 +206,17 @@ export const SelectTokenModal = React.forwardRef<HTMLDivElement, Props>(
)
const [selectedAccountFilter, setSelectedAccountFilter] =
React.useState<BraveWallet.AccountInfo>(AllAccountsOption)
const [pendingSelectedAsset, setPendingSelectedAsset] = React.useState<
BraveWallet.BlockchainToken | undefined
>(undefined)
const [pendingSelectedAssetState, setPendingSelectedAssetState] =
React.useState<BraveWallet.BlockchainToken | undefined>(undefined)
const [tokenDetails, setTokenDetails] = React.useState<
BraveWallet.BlockchainToken | undefined
>(undefined)

// Computed
const pendingSelectedAsset = needsAccount
? selectedFromToken
: pendingSelectedAssetState

// Selectors
const isPanel = useSafeUISelector(UISelectors.isPanel)

Expand Down Expand Up @@ -502,7 +516,7 @@ export const SelectTokenModal = React.forwardRef<HTMLDivElement, Props>(
return
}

setPendingSelectedAsset(token)
setPendingSelectedAssetState(token)
},
[onSelectAsset, onClose, selectingFromOrTo, modalType]
)
Expand Down Expand Up @@ -618,6 +632,24 @@ export const SelectTokenModal = React.forwardRef<HTMLDivElement, Props>(
[accounts, checkIsAccountOptionDisabled]
)

const handleOnClose = React.useCallback(() => {
// Ensure we clear route params if an account is not selected
// to prevent a broken state.
if (needsAccount && modalType === 'send') {
history.replace(WalletRoutes.Send)
}
onClose()
}, [modalType, needsAccount, history, onClose])

const handleOnBack = React.useCallback(() => {
// Clears route params if an account is not selected
// and user clicks back.
if (needsAccount && modalType === 'send') {
history.replace(WalletRoutes.Send)
}
setPendingSelectedAssetState(undefined)
}, [modalType, needsAccount, history])

// Computed & Memos
const emptyTokensList =
!isLoadingBalances && tokensBySearchValue.length === 0
Expand Down Expand Up @@ -688,8 +720,8 @@ export const SelectTokenModal = React.forwardRef<HTMLDivElement, Props>(
return (
<PopupModal
title=''
onClose={onClose}
onBack={() => setPendingSelectedAsset(undefined)}
onClose={handleOnClose}
onBack={handleOnBack}
width='560px'
showDivider={false}
>
Expand All @@ -715,7 +747,7 @@ export const SelectTokenModal = React.forwardRef<HTMLDivElement, Props>(
return (
<PopupModal
title=''
onClose={onClose}
onClose={handleOnClose}
onBack={() => setTokenDetails(undefined)}
width='560px'
showDivider={false}
Expand All @@ -728,7 +760,7 @@ export const SelectTokenModal = React.forwardRef<HTMLDivElement, Props>(
return (
<>
<PopupModal
onClose={onClose}
onClose={handleOnClose}
title={getLocale(
modalType === 'swap'
? 'braveWalletChooseAssetToSwap'
Expand Down Expand Up @@ -804,7 +836,7 @@ export const SelectTokenModal = React.forwardRef<HTMLDivElement, Props>(
</PopupModal>
{isPanel && (
<BottomSheet
onClose={() => setPendingSelectedAsset(undefined)}
onClose={handleOnBack}
isOpen={pendingSelectedAsset !== undefined}
>
{pendingSelectedAsset && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,20 +107,17 @@ export const SendScreen = React.memo((props: Props) => {
const history = useHistory()
const { hash } = useLocation()
const selectedSendOption = (hash as SendPageTabHashes) || '#token'
const accountIdFromParams = query.get('account') ?? undefined
const chainIdFromParams = query.get('chainId') ?? undefined
const contractOrSymbolFromParams = query.get('token') ?? undefined

const { account: accountFromParams } = useAccountFromAddressQuery(
query.get('account') ?? undefined
)
const { account: accountFromParams } =
useAccountFromAddressQuery(accountIdFromParams)

const { data: networks = [] } = useGetVisibleNetworksQuery()
const networkFromParams = React.useMemo(
() =>
networks.find(
(network) =>
network.chainId === query.get('chainId') &&
network.coin === accountFromParams?.accountId.coin
),
[networks, accountFromParams, query]
() => networks.find((network) => network.chainId === chainIdFromParams),
[networks, chainIdFromParams]
)

// State
Expand Down Expand Up @@ -178,8 +175,7 @@ export const SendScreen = React.memo((props: Props) => {
return
}

const contractOrSymbol = query.get('token')
if (!contractOrSymbol) {
if (!contractOrSymbolFromParams) {
return
}

Expand All @@ -191,18 +187,24 @@ export const SendScreen = React.memo((props: Props) => {
tokenId
? token.chainId === networkFromParams.chainId &&
token.contractAddress.toLowerCase() ===
contractOrSymbol.toLowerCase() &&
contractOrSymbolFromParams.toLowerCase() &&
token.tokenId === tokenId &&
token.isShielded === isShielded
: (token.chainId === networkFromParams.chainId &&
token.contractAddress.toLowerCase() ===
contractOrSymbol.toLowerCase()) ||
contractOrSymbolFromParams.toLowerCase()) ||
(token.chainId === networkFromParams.chainId &&
token.contractAddress === '' &&
token.symbol.toLowerCase() === contractOrSymbol.toLowerCase()) &&
token.isShielded === isShielded
token.symbol.toLowerCase() ===
contractOrSymbolFromParams.toLowerCase() &&
token.isShielded === isShielded)
)
}, [userVisibleTokensInfo, query, networkFromParams])
}, [
userVisibleTokensInfo,
query,
networkFromParams,
contractOrSymbolFromParams
])

const { data: tokenBalancesRegistry, isLoading: isLoadingBalances } =
useScopedBalanceUpdater(
Expand Down Expand Up @@ -258,6 +260,11 @@ export const SendScreen = React.memo((props: Props) => {
return getDominantColorFromImageURL(tokenFromParams?.logo ?? '')
}, [tokenFromParams?.logo])

const needsAccountSelected =
accountIdFromParams === undefined &&
contractOrSymbolFromParams !== undefined &&
chainIdFromParams !== undefined

// Methods
const selectSendAsset = React.useCallback(
(asset: BraveWallet.BlockchainToken, account?: BraveWallet.AccountInfo) => {
Expand Down Expand Up @@ -508,6 +515,13 @@ export const SendScreen = React.memo((props: Props) => {
isModalShown: showSelectAddressModal
} = useModal()

// Effects
React.useEffect(() => {
if (needsAccountSelected) {
openSelectTokenModal()
}
}, [needsAccountSelected, openSelectTokenModal])

// render
return (
<>
Expand Down Expand Up @@ -644,6 +658,8 @@ export const SendScreen = React.memo((props: Props) => {
ref={selectTokenModalRef}
onSelectAsset={selectSendAsset}
onSelectSendOption={onSelectSendOption}
selectedFromToken={needsAccountSelected ? tokenFromParams : undefined}
needsAccount={needsAccountSelected}
selectingFromOrTo='from'
modalType='send'
/>
Expand Down
15 changes: 9 additions & 6 deletions components/brave_wallet_ui/utils/routes-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,22 +226,25 @@ export const makeDepositFundsAccountRoute = (assetId: string) => {

export const makeSendRoute = (
asset: BraveWallet.BlockchainToken,
account: BraveWallet.AccountInfo
account?: BraveWallet.AccountInfo
) => {
const isNftTab = asset.isErc721 || asset.isNft
const baseQueryParams = {
chainId: asset.chainId,
token: asset.contractAddress || asset.symbol.toUpperCase(),
account: account.accountId.uniqueKey
token: asset.contractAddress || asset.symbol.toUpperCase()
}

const tokenIdQueryParams = asset.tokenId
? { ...baseQueryParams, tokenId: asset.tokenId }
const accountIdQueryParams = account
? { ...baseQueryParams, account: account.accountId.uniqueKey }
: baseQueryParams

const tokenIdQueryParams = asset.tokenId
? { ...accountIdQueryParams, tokenId: asset.tokenId }
: accountIdQueryParams

const params = new URLSearchParams(
asset.isShielded
? {...tokenIdQueryParams, isShielded: 'true'}
? { ...tokenIdQueryParams, isShielded: 'true' }
: tokenIdQueryParams
)

Expand Down

0 comments on commit d14ca67

Please sign in to comment.