feat(nft-bag): wrong-network-cta (#5056)
* pull warning out into its own component * add wrong network cta * simplify sufficient balance logic * consolidate warning and button text logic
This commit is contained in:
parent
d400b9094d
commit
d575c72127
@ -1,7 +1,6 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { formatEther } from '@ethersproject/units'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { parseEther } from 'ethers/lib/utils'
|
||||
import { BagFooter } from 'nft/components/bag/BagFooter'
|
||||
import ListingModal from 'nft/components/bag/profile/ListingModal'
|
||||
import { Box } from 'nft/components/Box'
|
||||
@ -16,7 +15,6 @@ import {
|
||||
useSellAsset,
|
||||
useSendTransaction,
|
||||
useTransactionResponse,
|
||||
useWalletBalance,
|
||||
} from 'nft/hooks'
|
||||
import { fetchRoute } from 'nft/queries'
|
||||
import { BagItemStatus, BagStatus, ProfilePageStateType, RouteResponse, TxStateType } from 'nft/types'
|
||||
@ -57,7 +55,8 @@ const ScrollingIndicator = ({ top, show }: SeparatorProps) => (
|
||||
)
|
||||
|
||||
const Bag = () => {
|
||||
const { account } = useWeb3React()
|
||||
const { account, provider } = useWeb3React()
|
||||
|
||||
const bagStatus = useBag((s) => s.bagStatus)
|
||||
const setBagStatus = useBag((s) => s.setBagStatus)
|
||||
const didOpenUnavailableAssets = useBag((s) => s.didOpenUnavailableAssets)
|
||||
@ -76,9 +75,6 @@ const Bag = () => {
|
||||
const setTotalEthPrice = useBag((s) => s.setTotalEthPrice)
|
||||
const setTotalUsdPrice = useBag((s) => s.setTotalUsdPrice)
|
||||
|
||||
const { address, balance: balanceInEth, provider } = useWalletBalance()
|
||||
const isConnected = !!provider && !!address
|
||||
|
||||
const { pathname } = useLocation()
|
||||
const isProfilePage = pathname.startsWith('/profile')
|
||||
const isNFTPage = pathname.startsWith('/nfts')
|
||||
@ -126,11 +122,6 @@ const Bag = () => {
|
||||
return { totalEthPrice, totalUsdPrice }
|
||||
}, [itemsInBag, fetchedPriceData])
|
||||
|
||||
const sufficientBalance = useMemo(() => {
|
||||
const balance = parseEther(balanceInEth.toString())
|
||||
return isConnected ? BigNumber.from(balance).gte(totalEthPrice) : true
|
||||
}, [balanceInEth, totalEthPrice, isConnected])
|
||||
|
||||
const purchaseAssets = async (routingData: RouteResponse) => {
|
||||
if (!provider || !routingData) return
|
||||
const purchaseResponse = await sendTransaction(
|
||||
@ -279,13 +270,10 @@ const Bag = () => {
|
||||
<ScrollingIndicator show={userCanScroll && scrollProgress < 100} />
|
||||
{hasAssetsToShow && !isProfilePage && (
|
||||
<BagFooter
|
||||
sufficientBalance={sufficientBalance}
|
||||
isConnected={isConnected}
|
||||
totalEthPrice={totalEthPrice}
|
||||
totalUsdPrice={totalUsdPrice}
|
||||
bagStatus={bagStatus}
|
||||
fetchAssets={fetchAssets}
|
||||
assetsAreInReview={itemsInBag.some((item) => item.status === BagItemStatus.REVIEWING_PRICE_CHANGE)}
|
||||
eventProperties={{
|
||||
usd_value: totalUsdPrice,
|
||||
...formatAssetEventProperties(itemsInBag.map((item) => item.asset)),
|
||||
|
@ -1,18 +1,24 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { parseEther } from '@ethersproject/units'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { ElementName, Event, EventName } from 'analytics/constants'
|
||||
import { TraceEvent } from 'analytics/TraceEvent'
|
||||
import Loader from 'components/Loader'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Column, Row } from 'nft/components/Flex'
|
||||
import { bodySmall } from 'nft/css/common.css'
|
||||
import { useWalletBalance } from 'nft/hooks/useWalletBalance'
|
||||
import { BagStatus } from 'nft/types'
|
||||
import { ethNumberStandardFormatter, formatWeiToDecimal } from 'nft/utils'
|
||||
import { PropsWithChildren, useCallback, useMemo } from 'react'
|
||||
import { AlertTriangle } from 'react-feather'
|
||||
import { useModalIsOpen, useToggleWalletModal } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
import { switchChain } from 'utils/switchChain'
|
||||
|
||||
import * as styles from './BagFooter.css'
|
||||
|
||||
@ -42,14 +48,36 @@ const WarningText = styled(ThemedText.BodyPrimary)`
|
||||
text-align: center;
|
||||
`
|
||||
|
||||
interface ActionButtonProps {
|
||||
disabled?: boolean
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
const ActionButton = ({ disabled, children, onClick }: PropsWithChildren<ActionButtonProps>) => {
|
||||
return (
|
||||
<Row as="button" color="explicitWhite" className={styles.payButton} disabled={disabled} onClick={onClick}>
|
||||
{children}
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
const Warning = ({ children }: PropsWithChildren<unknown>) => {
|
||||
if (!children) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<WarningText fontSize="14px" lineHeight="20px">
|
||||
<WarningIcon />
|
||||
{children}
|
||||
</WarningText>
|
||||
)
|
||||
}
|
||||
|
||||
interface BagFooterProps {
|
||||
isConnected: boolean
|
||||
sufficientBalance: boolean
|
||||
totalEthPrice: BigNumber
|
||||
totalUsdPrice: number | undefined
|
||||
bagStatus: BagStatus
|
||||
fetchAssets: () => void
|
||||
assetsAreInReview: boolean
|
||||
eventProperties: Record<string, unknown>
|
||||
}
|
||||
|
||||
@ -61,26 +89,72 @@ const PENDING_BAG_STATUSES = [
|
||||
]
|
||||
|
||||
export const BagFooter = ({
|
||||
isConnected,
|
||||
sufficientBalance,
|
||||
totalEthPrice,
|
||||
totalUsdPrice,
|
||||
bagStatus,
|
||||
fetchAssets,
|
||||
assetsAreInReview,
|
||||
eventProperties,
|
||||
}: BagFooterProps) => {
|
||||
const toggleWalletModal = useToggleWalletModal()
|
||||
const walletModalIsOpen = useModalIsOpen(ApplicationModal.WALLET)
|
||||
const { account, chainId, connector } = useWeb3React()
|
||||
const connected = Boolean(account && chainId)
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (!connected) {
|
||||
toggleWalletModal()
|
||||
} else if (connected && chainId !== SupportedChainId.MAINNET) {
|
||||
switchChain(connector, SupportedChainId.MAINNET)
|
||||
} else {
|
||||
fetchAssets()
|
||||
}
|
||||
}, [connected, chainId, toggleWalletModal, connector, fetchAssets])
|
||||
|
||||
const { balance: balanceInEth } = useWalletBalance()
|
||||
const sufficientBalance = useMemo(() => {
|
||||
if (!connected || chainId !== SupportedChainId.MAINNET) {
|
||||
return undefined
|
||||
}
|
||||
return parseEther(balanceInEth).gte(totalEthPrice)
|
||||
}, [connected, chainId, balanceInEth, totalEthPrice])
|
||||
|
||||
const { buttonText, disabled, warningText } = useMemo(() => {
|
||||
let buttonText = <Trans>Something went wrong</Trans>
|
||||
let disabled = true
|
||||
let warningText = null
|
||||
|
||||
if (connected && chainId !== SupportedChainId.MAINNET) {
|
||||
buttonText = <Trans>Switch networks</Trans>
|
||||
disabled = false
|
||||
warningText = <Trans>Wrong network</Trans>
|
||||
} else if (sufficientBalance === false) {
|
||||
buttonText = <Trans>Pay</Trans>
|
||||
disabled = true
|
||||
warningText = <Trans>Insufficient funds</Trans>
|
||||
} else if (bagStatus === BagStatus.WARNING) {
|
||||
warningText = <Trans>Something went wrong. Please try again.</Trans>
|
||||
} else if (!connected || walletModalIsOpen) {
|
||||
disabled = false
|
||||
buttonText = <Trans>Connect wallet</Trans>
|
||||
} else if (bagStatus === BagStatus.FETCHING_FINAL_ROUTE || bagStatus === BagStatus.CONFIRMING_IN_WALLET) {
|
||||
disabled = true
|
||||
buttonText = <Trans>Proceed in wallet</Trans>
|
||||
} else if (bagStatus === BagStatus.PROCESSING_TRANSACTION) {
|
||||
disabled = true
|
||||
buttonText = <Trans>Transaction pending</Trans>
|
||||
} else if (sufficientBalance === true) {
|
||||
disabled = false
|
||||
buttonText = <Trans>Pay</Trans>
|
||||
}
|
||||
|
||||
return { buttonText, disabled, warningText }
|
||||
}, [bagStatus, chainId, connected, sufficientBalance, walletModalIsOpen])
|
||||
|
||||
const isPending = PENDING_BAG_STATUSES.includes(bagStatus) || walletModalIsOpen
|
||||
const isDisabled = isConnected && (isPending || !sufficientBalance || assetsAreInReview)
|
||||
|
||||
const showWarning = isConnected && (!sufficientBalance || bagStatus === BagStatus.WARNING)
|
||||
|
||||
return (
|
||||
<Column className={styles.footerContainer}>
|
||||
<Footer $showWarning={showWarning}>
|
||||
<Footer $showWarning={bagStatus === BagStatus.WARNING}>
|
||||
<Column gap="4" paddingTop="8" paddingBottom="20">
|
||||
<Row justifyContent="space-between">
|
||||
<Box>
|
||||
@ -96,45 +170,18 @@ export const BagFooter = ({
|
||||
{`${ethNumberStandardFormatter(totalUsdPrice, true)}`}
|
||||
</Row>
|
||||
</Column>
|
||||
{showWarning && (
|
||||
<WarningText fontSize="14px" lineHeight="20px">
|
||||
<WarningIcon />
|
||||
{!sufficientBalance ? (
|
||||
<Trans>Insufficient funds</Trans>
|
||||
) : (
|
||||
<Trans>Something went wrong. Please try again.</Trans>
|
||||
)}
|
||||
</WarningText>
|
||||
)}
|
||||
<TraceEvent
|
||||
events={[Event.onClick]}
|
||||
name={EventName.NFT_BUY_BAG_PAY}
|
||||
element={ElementName.NFT_BUY_BAG_PAY_BUTTON}
|
||||
properties={{ ...eventProperties }}
|
||||
shouldLogImpression={isConnected && !isDisabled}
|
||||
shouldLogImpression={connected && !disabled}
|
||||
>
|
||||
<Row
|
||||
as="button"
|
||||
color="explicitWhite"
|
||||
className={styles.payButton}
|
||||
disabled={isDisabled}
|
||||
onClick={() => {
|
||||
if (!isConnected) {
|
||||
toggleWalletModal()
|
||||
} else {
|
||||
fetchAssets()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Warning>{warningText}</Warning>
|
||||
<ActionButton onClick={handleClick} disabled={disabled}>
|
||||
{isPending && <Loader size="20px" stroke="white" />}
|
||||
{!isConnected || walletModalIsOpen
|
||||
? 'Connect wallet'
|
||||
: bagStatus === BagStatus.FETCHING_FINAL_ROUTE || bagStatus === BagStatus.CONFIRMING_IN_WALLET
|
||||
? 'Proceed in wallet'
|
||||
: bagStatus === BagStatus.PROCESSING_TRANSACTION
|
||||
? 'Transaction pending'
|
||||
: 'Pay'}
|
||||
</Row>
|
||||
{buttonText}
|
||||
</ActionButton>
|
||||
</TraceEvent>
|
||||
</Footer>
|
||||
</Column>
|
||||
|
Loading…
Reference in New Issue
Block a user