Commit 3f169adc authored by Jack Short's avatar Jack Short Committed by GitHub

chore: cleaning up buy button states (#6618)

parent 774368f3
This diff is collapsed.
......@@ -40,6 +40,8 @@ import { ThemedText } from 'theme'
import { switchChain } from 'utils/switchChain'
import { shallow } from 'zustand/shallow'
import { BuyButtonStateData, BuyButtonStates, getBuyButtonStateData } from './ButtonStates'
const FooterContainer = styled.div`
padding: 0px 12px;
`
......@@ -98,7 +100,7 @@ const CurrencyInput = styled(Row)`
cursor: pointer;
`
const PayButton = styled.button<{ $backgroundColor: string; $color: string }>`
const ActionButton = styled.button<{ $backgroundColor: string; $color: string }>`
display: flex;
background: ${({ $backgroundColor }) => $backgroundColor};
color: ${({ $color }) => $color};
......@@ -149,27 +151,6 @@ const ValueText = styled(ThemedText.BodyPrimary)`
}
`
interface ActionButtonProps {
disabled?: boolean
onClick: () => void
backgroundColor: string
textColor: string
}
const ActionButton = ({
disabled,
children,
onClick,
backgroundColor,
textColor,
}: PropsWithChildren<ActionButtonProps>) => {
return (
<PayButton disabled={disabled} onClick={onClick} $backgroundColor={backgroundColor} $color={textColor}>
{children}
</PayButton>
)
}
interface HelperTextProps {
color: string
}
......@@ -179,7 +160,7 @@ const Warning = ({ color, children }: PropsWithChildren<HelperTextProps>) => {
return null
}
return (
<WarningText fontSize="14px" lineHeight="20px" $color={color}>
<WarningText data-testid="nft-buy-button-warning" fontSize="14px" lineHeight="20px" $color={color}>
<WarningIcon />
{children}
</WarningText>
......@@ -274,11 +255,6 @@ const FiatValue = ({
)
}
interface BagFooterProps {
setModalIsOpen: (open: boolean) => void
eventProperties: Record<string, unknown>
}
const PENDING_BAG_STATUSES = [
BagStatus.FETCHING_ROUTE,
BagStatus.CONFIRMING_IN_WALLET,
......@@ -286,13 +262,18 @@ const PENDING_BAG_STATUSES = [
BagStatus.PROCESSING_TRANSACTION,
]
interface BagFooterProps {
setModalIsOpen: (open: boolean) => void
eventProperties: Record<string, unknown>
}
export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) => {
const toggleWalletDrawer = useToggleAccountDrawer()
const theme = useTheme()
const { account, chainId, connector } = useWeb3React()
const connected = Boolean(account && chainId)
const totalEthPrice = useBagTotalEthPrice()
const inputCurrency = useTokenInput((state) => state.inputCurrency)
const { inputCurrency } = useTokenInput(({ inputCurrency }) => ({ inputCurrency }), shallow)
const setInputCurrency = useTokenInput((state) => state.setInputCurrency)
const defaultCurrency = useCurrency('ETH')
const inputCurrencyBalance = useTokenBalance(
......@@ -377,105 +358,78 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) =
helperTextColor,
handleClick,
buttonColor,
} = useMemo(() => {
let handleClick: (() => void) | (() => Promise<void>) = fetchAssets
let buttonText = <Trans>Something went wrong</Trans>
let disabled = true
let warningText = undefined
let warningTextColor = theme.accentWarning
let helperText = undefined
let helperTextColor = theme.textSecondary
let buttonColor = theme.accentAction
let buttonTextColor = theme.accentTextLightPrimary
} = useMemo((): BuyButtonStateData => {
if (connected && chainId !== SupportedChainId.MAINNET) {
handleClick = () => switchChain(connector, 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) {
handleClick = () => {
const handleClick = () => switchChain(connector, SupportedChainId.MAINNET)
return getBuyButtonStateData(BuyButtonStates.NOT_SUPPORTED_CHAIN, theme, handleClick)
}
if (sufficientBalance === false) {
return getBuyButtonStateData(BuyButtonStates.INSUFFICIENT_BALANCE, theme)
}
if (bagStatus === BagStatus.WARNING) {
return getBuyButtonStateData(BuyButtonStates.ERROR, theme)
}
if (!connected) {
const handleClick = () => {
toggleWalletDrawer()
setBagExpanded({ bagExpanded: false })
}
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 (usingPayWithAnyToken && tradeState !== TradeState.VALID) {
disabled = true
buttonText = <Trans>Fetching Route</Trans>
return getBuyButtonStateData(BuyButtonStates.WALLET_NOT_CONNECTED, theme, handleClick)
}
if (bagStatus === BagStatus.FETCHING_FINAL_ROUTE || bagStatus === BagStatus.CONFIRMING_IN_WALLET) {
return getBuyButtonStateData(BuyButtonStates.IN_WALLET_CONFIRMATION, theme)
}
if (bagStatus === BagStatus.PROCESSING_TRANSACTION) {
return getBuyButtonStateData(BuyButtonStates.PROCESSING_TRANSACTION, theme)
}
if (usingPayWithAnyToken && tradeState !== TradeState.VALID) {
if (tradeState === TradeState.INVALID) {
buttonText = <Trans>Pay</Trans>
return getBuyButtonStateData(BuyButtonStates.INVALID_TOKEN_ROUTE, theme)
}
if (tradeState === TradeState.NO_ROUTE_FOUND) {
buttonText = <Trans>Insufficient liquidity</Trans>
buttonColor = theme.backgroundInteractive
buttonTextColor = theme.textPrimary
helperText = <Trans>Insufficient pool liquidity to complete transaction</Trans>
return getBuyButtonStateData(BuyButtonStates.NO_TOKEN_ROUTE_FOUND, theme)
}
} else if (allowance.state === AllowanceState.REQUIRED || loadingAllowance) {
handleClick = () => updateAllowance()
disabled = isAllowancePending || isApprovalLoading || loadingAllowance
return getBuyButtonStateData(BuyButtonStates.FETCHING_TOKEN_ROUTE, theme)
}
if (allowance.state === AllowanceState.REQUIRED || loadingAllowance) {
const handleClick = () => updateAllowance()
if (loadingAllowance) {
buttonText = <Trans>Loading Allowance</Trans>
return getBuyButtonStateData(BuyButtonStates.LOADING_ALLOWANCE, theme, handleClick)
} else if (isAllowancePending) {
buttonText = <Trans>Approve in your wallet</Trans>
return getBuyButtonStateData(BuyButtonStates.IN_WALLET_ALLOWANCE_APPROVAL, theme, handleClick)
} else if (isApprovalLoading) {
buttonText = <Trans>Approval pending</Trans>
} else {
helperText = <Trans>An approval is needed to use this token. </Trans>
buttonText = <Trans>Approve</Trans>
return getBuyButtonStateData(BuyButtonStates.PROCESSING_APPROVAL, theme, handleClick)
}
} else if (bagStatus === BagStatus.CONFIRM_QUOTE) {
disabled = false
warningTextColor = theme.accentAction
warningText = <Trans>Price updated</Trans>
buttonText = <Trans>Pay</Trans>
} else if (priceImpact && priceImpact.priceImpactSeverity.type === 'error') {
disabled = false
buttonColor = priceImpact.priceImpactSeverity.color
helperText = <Trans>Price impact warning</Trans>
helperTextColor = priceImpact.priceImpactSeverity.color
buttonText = <Trans>Pay Anyway</Trans>
} else if (sufficientBalance === true) {
disabled = false
buttonText = <Trans>Pay</Trans>
helperText = usingPayWithAnyToken ? <Trans>Refunds for unavailable items will be given in ETH</Trans> : undefined
return getBuyButtonStateData(BuyButtonStates.REQUIRE_APPROVAL, theme, handleClick)
}
return {
buttonText,
buttonTextColor,
disabled,
warningText,
warningTextColor,
helperText,
helperTextColor,
handleClick,
buttonColor,
if (bagStatus === BagStatus.CONFIRM_QUOTE) {
return getBuyButtonStateData(BuyButtonStates.CONFIRM_UPDATED_PRICE, theme, fetchAssets)
}
if (priceImpact && priceImpact.priceImpactSeverity.type === 'error') {
return getBuyButtonStateData(
BuyButtonStates.PRICE_IMPACT_HIGH,
theme,
fetchAssets,
usingPayWithAnyToken,
priceImpact
)
}
return getBuyButtonStateData(BuyButtonStates.PAY, theme, fetchAssets, usingPayWithAnyToken)
}, [
fetchAssets,
theme.accentWarning,
theme.textSecondary,
theme.accentAction,
theme.accentTextLightPrimary,
theme.backgroundInteractive,
theme.textPrimary,
connected,
chainId,
sufficientBalance,
......@@ -485,6 +439,8 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) =
allowance.state,
loadingAllowance,
priceImpact,
theme,
fetchAssets,
connector,
toggleWalletDrawer,
setBagExpanded,
......@@ -553,10 +509,11 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) =
<Warning color={warningTextColor}>{warningText}</Warning>
<Helper color={helperTextColor}>{helperText}</Helper>
<ActionButton
data-testid="nft-buy-button"
onClick={handleClick}
disabled={disabled || isPending}
backgroundColor={buttonColor}
textColor={buttonTextColor}
$backgroundColor={buttonColor}
$color={buttonTextColor}
>
{isPending && <Loader size="20px" stroke="white" />}
{buttonText}
......
import { Trans } from '@lingui/macro'
import { PriceImpact } from 'nft/hooks/usePriceImpact'
import { ReactNode } from 'react'
import { DefaultTheme } from 'styled-components/macro'
export enum BuyButtonStates {
WALLET_NOT_CONNECTED,
NOT_SUPPORTED_CHAIN,
INSUFFICIENT_BALANCE,
ERROR,
IN_WALLET_CONFIRMATION,
PROCESSING_TRANSACTION,
FETCHING_TOKEN_ROUTE,
INVALID_TOKEN_ROUTE,
NO_TOKEN_ROUTE_FOUND,
LOADING_ALLOWANCE,
IN_WALLET_ALLOWANCE_APPROVAL,
PROCESSING_APPROVAL,
REQUIRE_APPROVAL,
CONFIRM_UPDATED_PRICE,
PRICE_IMPACT_HIGH,
PAY,
}
export interface BuyButtonStateData {
handleClick: (() => void) | (() => Promise<void>)
buttonText: ReactNode
disabled: boolean
warningText?: ReactNode
warningTextColor: string
helperText?: ReactNode
helperTextColor: string
buttonColor: string
buttonTextColor: string
}
export function getBuyButtonStateData(
buyButtonState: BuyButtonStates,
theme: DefaultTheme,
handleClickOverride?: (() => void) | (() => Promise<void>),
usingPayWithAnyToken?: boolean,
priceImpact?: PriceImpact
): BuyButtonStateData {
const defaultBuyButtonState: BuyButtonStateData = {
handleClick: () => undefined,
buttonText: <Trans>Something went wrong</Trans>,
disabled: true,
warningText: undefined,
warningTextColor: theme.accentWarning,
helperText: undefined,
helperTextColor: theme.textSecondary,
buttonColor: theme.accentAction,
buttonTextColor: theme.accentTextLightPrimary,
}
const buyButtonStateData: Record<BuyButtonStates, BuyButtonStateData> = {
[BuyButtonStates.WALLET_NOT_CONNECTED]: {
...defaultBuyButtonState,
handleClick: handleClickOverride ?? (() => undefined),
disabled: false,
buttonText: <Trans>Connect wallet</Trans>,
},
[BuyButtonStates.NOT_SUPPORTED_CHAIN]: {
...defaultBuyButtonState,
handleClick: handleClickOverride ?? (() => undefined),
buttonText: <Trans>Switch networks</Trans>,
disabled: false,
warningText: <Trans>Wrong network</Trans>,
},
[BuyButtonStates.INSUFFICIENT_BALANCE]: {
...defaultBuyButtonState,
buttonText: <Trans>Pay</Trans>,
warningText: <Trans>Insufficient funds</Trans>,
},
[BuyButtonStates.ERROR]: {
...defaultBuyButtonState,
warningText: <Trans>Something went wrong. Please try again.</Trans>,
},
[BuyButtonStates.IN_WALLET_CONFIRMATION]: {
...defaultBuyButtonState,
buttonText: <Trans>Proceed in wallet</Trans>,
},
[BuyButtonStates.PROCESSING_TRANSACTION]: {
...defaultBuyButtonState,
buttonText: <Trans>Transaction pending</Trans>,
},
[BuyButtonStates.FETCHING_TOKEN_ROUTE]: {
...defaultBuyButtonState,
buttonText: <Trans>Fetching Route</Trans>,
},
[BuyButtonStates.INVALID_TOKEN_ROUTE]: {
...defaultBuyButtonState,
buttonText: <Trans>Pay</Trans>,
},
[BuyButtonStates.NO_TOKEN_ROUTE_FOUND]: {
...defaultBuyButtonState,
buttonText: <Trans>Insufficient liquidity</Trans>,
buttonColor: theme.backgroundInteractive,
buttonTextColor: theme.textPrimary,
helperText: <Trans>Insufficient pool liquidity to complete transaction</Trans>,
},
[BuyButtonStates.LOADING_ALLOWANCE]: {
...defaultBuyButtonState,
buttonText: <Trans>Loading Allowance</Trans>,
},
[BuyButtonStates.IN_WALLET_ALLOWANCE_APPROVAL]: {
...defaultBuyButtonState,
buttonText: <Trans>Approve in your wallet</Trans>,
},
[BuyButtonStates.PROCESSING_APPROVAL]: {
...defaultBuyButtonState,
buttonText: <Trans>Approval pending</Trans>,
},
[BuyButtonStates.REQUIRE_APPROVAL]: {
...defaultBuyButtonState,
disabled: false,
handleClick: handleClickOverride ?? (() => undefined),
helperText: <Trans>An approval is needed to use this token. </Trans>,
buttonText: <Trans>Approve</Trans>,
},
[BuyButtonStates.CONFIRM_UPDATED_PRICE]: {
...defaultBuyButtonState,
handleClick: handleClickOverride ?? (() => undefined),
disabled: false,
warningTextColor: theme.accentAction,
warningText: <Trans>Price updated</Trans>,
buttonText: <Trans>Pay</Trans>,
},
[BuyButtonStates.PRICE_IMPACT_HIGH]: {
...defaultBuyButtonState,
handleClick: handleClickOverride ?? (() => undefined),
disabled: false,
buttonColor: priceImpact ? priceImpact.priceImpactSeverity.color : defaultBuyButtonState.buttonColor,
helperText: <Trans>Price impact warning</Trans>,
helperTextColor: priceImpact ? priceImpact.priceImpactSeverity.color : defaultBuyButtonState.helperTextColor,
buttonText: <Trans>Pay Anyway</Trans>,
},
[BuyButtonStates.PAY]: {
...defaultBuyButtonState,
handleClick: handleClickOverride ?? (() => undefined),
disabled: false,
buttonText: <Trans>Pay</Trans>,
helperText: usingPayWithAnyToken ? <Trans>Refunds for unavailable items will be given in ETH</Trans> : undefined,
},
}
return buyButtonStateData[buyButtonState]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment