diff --git a/components/brave_wallet/browser/brave_wallet_constants.h b/components/brave_wallet/browser/brave_wallet_constants.h index 41e130e88b848..0c897547aac62 100644 --- a/components/brave_wallet/browser/brave_wallet_constants.h +++ b/components/brave_wallet/browser/brave_wallet_constants.h @@ -942,6 +942,7 @@ constexpr webui::LocalizedString kLocalizedStrings[] = { {"braveWalletHelpCenter", IDS_BRAVE_WALLET_HELP_CENTER}, {"braveWalletBuyTapBuyNotSupportedMessage", IDS_BRAVE_WALLET_BUY_TAB_BUY_NOT_SUPPORTED_MESSAGE}, + {"braveWalletSearchingForDomain", IDS_BRAVE_WALLET_SEARCHING_FOR_DOMAIN}, {"braveWalletPortfolioTokenDetailsMenuLabel", IDS_BRAVE_WALLET_PORTFOLIO_TOKEN_DETAILS_MENU_LABEL}, {"braveWalletPortfolioViewOnExplorerMenuLabel", diff --git a/components/brave_wallet_ui/common/hooks/send.ts b/components/brave_wallet_ui/common/hooks/send.ts index deeb2c25488a7..64b8615e82f2a 100644 --- a/components/brave_wallet_ui/common/hooks/send.ts +++ b/components/brave_wallet_ui/common/hooks/send.ts @@ -53,7 +53,8 @@ export default function useSend (isSendTab?: boolean) { toAddress, toAddressOrUrl, showEnsOffchainLookupOptions, - ensOffchainLookupOptions + ensOffchainLookupOptions, + searchingForDomain } = useSelector((state: { sendCrypto: PendingCryptoSendState }) => state.sendCrypto) // custom hooks @@ -88,6 +89,9 @@ export default function useSend (isSendTab?: boolean) { const setToAddressOrUrl = (payload?: string | undefined) => { dispatch(SendCryptoActions.setToAddressOrUrl(payload)) } + const setSearchingForDomain = (payload: boolean) => { + dispatch(SendCryptoActions.setSearchingForDomain(payload)) + } const selectSendAsset = (asset: BraveWallet.BlockchainToken | undefined) => { if (asset?.isErc721 || asset?.isNft) { @@ -102,44 +106,50 @@ export default function useSend (isSendTab?: boolean) { setAddressError(getLocale('braveWalletNotDomain').replace('$1', url)) } + const handleDomainLookupResponse = React.useCallback((address: string, error: BraveWallet.ProviderError, requireOffchainConsent: boolean) => { + if (address && error === BraveWallet.ProviderError.kSuccess) { + setAddressError('') + setAddressWarning('') + setToAddress(address) + setShowEnsOffchainLookupOptions(requireOffchainConsent) + // If found UD address is the same as the selectedAccounts Wallet Address + if (address.toLowerCase() === selectedAccount?.address?.toLowerCase()) { + setAddressError(getLocale('braveWalletSameAddressError')) + } + setSearchingForDomain(false) + return + } + setShowEnsOffchainLookupOptions(false) + setNotRegisteredError(toAddressOrUrl) + setSearchingForDomain(false) + }, [selectedAccount?.address, toAddressOrUrl]) + + const handleUDAddressLookUp = React.useCallback(() => { + setSearchingForDomain(true) + setToAddress('') + findUnstoppableDomainAddress(toAddressOrUrl, selectedSendAsset ?? null).then((value: GetUnstoppableDomainsWalletAddrReturnInfo) => { + handleDomainLookupResponse(value.address, value.error, false) + }).catch(e => console.log(e)) + }, [findUnstoppableDomainAddress, handleDomainLookupResponse, findSNSAddress, findENSAddress, toAddressOrUrl, selectedSendAsset, selectedAccount?.coin]) + const processEthereumAddress = React.useCallback((toAddressOrUrl: string) => { const valueToLowerCase = toAddressOrUrl.toLowerCase() + // If value ends with a supported ENS extension, will call findENSAddress. // If success true, will set toAddress else will return error message. if (endsWithAny(supportedENSExtensions, valueToLowerCase)) { + setSearchingForDomain(true) + setToAddress('') findENSAddress(toAddressOrUrl, ensOffchainLookupOptions).then((value: GetEthAddrReturnInfo) => { - if (value.error === BraveWallet.ProviderError.kSuccess) { - setAddressError('') - setAddressWarning('') - setToAddress(value.address) - setShowEnsOffchainLookupOptions(value.requireOffchainConsent) - // If found ENS address is the same as the selectedAccounts Wallet Address - if (value.address.toLowerCase() === selectedAccount?.address?.toLowerCase()) { - setAddressError(getLocale('braveWalletSameAddressError')) - } - return - } - setShowEnsOffchainLookupOptions(false) - setNotRegisteredError(valueToLowerCase) + handleDomainLookupResponse(value.address, value.error, value.requireOffchainConsent) }).catch(e => console.log(e)) return } + // If value ends with a supported UD extension, will call findUnstoppableDomainAddress. // If success true, will set toAddress else will return error message. if (endsWithAny(supportedUDExtensions, valueToLowerCase)) { - findUnstoppableDomainAddress(toAddressOrUrl, selectedSendAsset ?? null).then((value: GetUnstoppableDomainsWalletAddrReturnInfo) => { - if (value.address && value.error === BraveWallet.ProviderError.kSuccess) { - setAddressError('') - setAddressWarning('') - setToAddress(value.address) - // If found UD address is the same as the selectedAccounts Wallet Address - if (value.address.toLowerCase() === selectedAccount?.address?.toLowerCase()) { - setAddressError(getLocale('braveWalletSameAddressError')) - } - return - } - setNotRegisteredError(valueToLowerCase) - }).catch(e => console.log(e)) + handleUDAddressLookUp() return } @@ -198,7 +208,7 @@ export default function useSend (isSendTab?: boolean) { // Fallback error state setAddressWarning('') setAddressError(getLocale('braveWalletNotValidAddress')) - }, [selectedAccount?.address, selectedSendAsset, ensOffchainLookupOptions]) + }, [selectedAccount?.address, ensOffchainLookupOptions, handleUDAddressLookUp, handleDomainLookupResponse]) const processFilecoinAddress = React.useCallback((toAddressOrUrl: string) => { const valueToLowerCase = toAddressOrUrl.toLowerCase() @@ -206,15 +216,7 @@ export default function useSend (isSendTab?: boolean) { // If value ends with a supported UD extension, will call findUnstoppableDomainAddress. // If success true, will set toAddress else will return error message. if (endsWithAny(supportedUDExtensions, valueToLowerCase)) { - findUnstoppableDomainAddress(toAddressOrUrl, selectedSendAsset ?? null).then((value: GetUnstoppableDomainsWalletAddrReturnInfo) => { - if (value.address && value.error === BraveWallet.ProviderError.kSuccess) { - setAddressError('') - setAddressWarning('') - setToAddress(value.address) - return - } - setNotRegisteredError(valueToLowerCase) - }).catch(e => console.log(e)) + handleUDAddressLookUp() return } @@ -243,7 +245,7 @@ export default function useSend (isSendTab?: boolean) { // Reset error and warning state back to normal setAddressWarning('') setAddressError('') - }, [selectedSendAsset, selectedAccount?.address]) + }, [selectedAccount?.address, handleUDAddressLookUp]) const processSolanaAddress = React.useCallback((toAddressOrUrl: string) => { const valueToLowerCase = toAddressOrUrl.toLowerCase() @@ -251,35 +253,17 @@ export default function useSend (isSendTab?: boolean) { // If value ends with a supported UD extension, will call findUnstoppableDomainAddress. // If success true, will set toAddress else will return error message. if (endsWithAny(supportedUDExtensions, valueToLowerCase)) { - findUnstoppableDomainAddress(toAddressOrUrl, selectedSendAsset ?? null).then((value: GetUnstoppableDomainsWalletAddrReturnInfo) => { - if (value.address && value.error === BraveWallet.ProviderError.kSuccess) { - setAddressError('') - setAddressWarning('') - setToAddress(value.address) - // If found UD address is the same as the selectedAccounts Wallet Address - if (value.address.toLowerCase() === selectedAccount?.address?.toLowerCase()) { - setAddressError(getLocale('braveWalletSameAddressError')) - } - return - } - setNotRegisteredError(valueToLowerCase) - }).catch(e => console.log(e)) + handleUDAddressLookUp() return } + // If value ends with a supported SNS extension, will call findENSAddress. + // If success true, will set toAddress else will return error message. if (endsWithAny(supportedSNSExtensions, valueToLowerCase)) { + setSearchingForDomain(true) + setToAddress('') findSNSAddress(toAddressOrUrl).then((value: GetSolAddrReturnInfo) => { - if (value.error === BraveWallet.ProviderError.kSuccess) { - setAddressError('') - setAddressWarning('') - setToAddress(value.address) - // If found SNS address is the same as the selectedAccounts Wallet Address - if (value.address.toLowerCase() === selectedAccount?.address?.toLowerCase()) { - setAddressError(getLocale('braveWalletSameAddressError')) - } - return - } - setNotRegisteredError(valueToLowerCase) + handleDomainLookupResponse(value.address, value.error, false) }).catch(e => console.log(e)) return } @@ -325,7 +309,7 @@ export default function useSend (isSendTab?: boolean) { setAddressWarning('') setAddressError('') }) - }, [selectedAccount?.address, selectedSendAsset, fullTokenList]) + }, [selectedAccount?.address, fullTokenList, handleUDAddressLookUp, handleDomainLookupResponse]) const resetSendFields = React.useCallback((reselectSendAsset?: boolean) => { if (isSendTab) { @@ -490,6 +474,7 @@ export default function useSend (isSendTab?: boolean) { sendAmountValidationError, showEnsOffchainLookupOptions, ensOffchainLookupOptions, - setEnsOffchainLookupOptions + setEnsOffchainLookupOptions, + searchingForDomain } } diff --git a/components/brave_wallet_ui/common/reducers/send_crypto_reducer.ts b/components/brave_wallet_ui/common/reducers/send_crypto_reducer.ts index 633db09e57389..7246b4975681d 100644 --- a/components/brave_wallet_ui/common/reducers/send_crypto_reducer.ts +++ b/components/brave_wallet_ui/common/reducers/send_crypto_reducer.ts @@ -15,6 +15,7 @@ export interface PendingCryptoSendState { sendAmount: string showEnsOffchainLookupOptions: boolean ensOffchainLookupOptions?: BraveWallet.EnsOffchainLookupOptions + searchingForDomain: boolean } const defaultState: PendingCryptoSendState = { @@ -25,7 +26,8 @@ const defaultState: PendingCryptoSendState = { selectedSendAsset: undefined, toAddressOrUrl: '', showEnsOffchainLookupOptions: false, - ensOffchainLookupOptions: undefined + ensOffchainLookupOptions: undefined, + searchingForDomain: false } export const SendCryptoActions = { @@ -36,7 +38,8 @@ export const SendCryptoActions = { setShowEnsOffchainLookupOptions: createAction('setShowEnsOffchainLookupOptions'), setEnsOffchainLookupOptions: createAction('setEnsOffchainLookupOptions'), setAddressWarning: createAction('setAddressWarning'), - selectSendAsset: createAction('selectSendAsset') + selectSendAsset: createAction('selectSendAsset'), + setSearchingForDomain: createAction('setSearchingForDomain') } export const createSendCryptoReducer = (initialState: PendingCryptoSendState) => { @@ -122,6 +125,16 @@ export const createSendCryptoReducer = (initialState: PendingCryptoSendState) => } }) + reducer.on(SendCryptoActions.setSearchingForDomain, ( + state: PendingCryptoSendState, + payload: boolean + ): PendingCryptoSendState => { + return { + ...state, + searchingForDomain: payload + } + }) + return reducer } diff --git a/components/brave_wallet_ui/page/screens/send/components/standard-button/standard-button.style.ts b/components/brave_wallet_ui/page/screens/send/components/standard-button/standard-button.style.ts index e8bc8e4ebae9e..32961a6bcfc82 100644 --- a/components/brave_wallet_ui/page/screens/send/components/standard-button/standard-button.style.ts +++ b/components/brave_wallet_ui/page/screens/send/components/standard-button/standard-button.style.ts @@ -5,6 +5,9 @@ import styled from 'styled-components' +// Assets +import { LoaderIcon } from 'brave-ui/components/icons' + // Shared Styles import { StyledButton, Icon } from '../../shared.styles' @@ -78,3 +81,11 @@ export const ErrorIcon = styled(Icon)` background-color: ${(p) => p.theme.color.errorBorder}; margin-right: 12px; ` + +export const LoadIcon = styled(LoaderIcon)` + color: ${p => p.theme.color.white}; + height: 25px; + width: 25px; + opacity: .4; + margin-right: 10px; +` diff --git a/components/brave_wallet_ui/page/screens/send/components/standard-button/standard-button.tsx b/components/brave_wallet_ui/page/screens/send/components/standard-button/standard-button.tsx index eafcc6da338d4..adb62bd8ef26f 100644 --- a/components/brave_wallet_ui/page/screens/send/components/standard-button/standard-button.tsx +++ b/components/brave_wallet_ui/page/screens/send/components/standard-button/standard-button.tsx @@ -9,10 +9,11 @@ import * as React from 'react' import InfoIcon from '../../../../../assets/svg-icons/info-icon.svg' // Styled Components -import { Button, ErrorIcon, StandardButtonStyleProps } from './standard-button.style' +import { Button, ErrorIcon, StandardButtonStyleProps, LoadIcon } from './standard-button.style' interface Props extends StandardButtonStyleProps { buttonText: string + isLoading: boolean onClick: () => void } @@ -24,6 +25,7 @@ export const StandardButton = (props: Props) => { disabled, marginRight, hasError, + isLoading, onClick } = props @@ -39,6 +41,9 @@ export const StandardButton = (props: Props) => { {hasError && } + {isLoading && + + } {buttonText} ) diff --git a/components/brave_wallet_ui/page/screens/send/send/send.tsx b/components/brave_wallet_ui/page/screens/send/send/send.tsx index 106d9343ae05f..376fba8950b23 100644 --- a/components/brave_wallet_ui/page/screens/send/send/send.tsx +++ b/components/brave_wallet_ui/page/screens/send/send/send.tsx @@ -79,7 +79,8 @@ export const Send = (props: Props) => { setSendAmount, setToAddressOrUrl, submitSend, - selectSendAsset + selectSendAsset, + searchingForDomain } = useSend(true) // Hooks @@ -176,25 +177,28 @@ export const Send = (props: Props) => { }, [spotPrices, selectedSendAsset, sendAmount, defaultCurrencies.fiat, sendAssetBalance, selectedSendOption]) const reviewButtonText = React.useMemo(() => { - return sendAmountValidationError - ? getLocale('braveWalletDecimalPlacesError') - : insufficientFundsError - ? getLocale('braveWalletNotEnoughFunds') - : (addressError !== undefined && addressError !== '') - ? addressError - : (addressWarning !== undefined && addressWarning !== '') - ? addressWarning - : getLocale('braveWalletReviewOrder') - }, [insufficientFundsError, addressError, addressWarning, sendAmountValidationError]) + return searchingForDomain + ? getLocale('braveWalletSearchingForDomain') + : sendAmountValidationError + ? getLocale('braveWalletDecimalPlacesError') + : insufficientFundsError + ? getLocale('braveWalletNotEnoughFunds') + : (addressError !== undefined && addressError !== '') + ? addressError + : (addressWarning !== undefined && addressWarning !== '') + ? addressWarning + : getLocale('braveWalletReviewOrder') + }, [insufficientFundsError, addressError, addressWarning, sendAmountValidationError, searchingForDomain]) const isReviewButtonDisabled = React.useMemo(() => { - return toAddressOrUrl === '' || + return searchingForDomain || + toAddressOrUrl === '' || parseFloat(sendAmount) === 0 || sendAmount === '' || insufficientFundsError || (addressError !== undefined && addressError !== '') || sendAmountValidationError !== undefined - }, [toAddressOrUrl, sendAmount, insufficientFundsError, addressError, sendAmountValidationError]) + }, [toAddressOrUrl, sendAmount, insufficientFundsError, addressError, sendAmountValidationError, searchingForDomain]) const selectedTokensNetwork = React.useMemo(() => { if (selectedSendAsset) { @@ -347,8 +351,9 @@ export const Send = (props: Props) => { {toAddressOrUrl} { onClick={submitSend} buttonType='primary' buttonWidth='full' + isLoading={searchingForDomain} disabled={isReviewButtonDisabled} - hasError={ - insufficientFundsError || - (addressError !== undefined && addressError !== '') - } + hasError={searchingForDomain + ? false + : insufficientFundsError || + (addressError !== undefined && addressError !== '')} /> Search NFT by name, id Buy support is not available for Binance Smart Chain$1 Buy not supported for selected network + Searching for Domain... Swap support is not available for Binance Smart Chain$1 Transaction may be frontrun Slippage tolerance