Commit 8c2a0f19 authored by eddie's avatar eddie Committed by GitHub

feat: update content in Swap Submission Modal (#6577)

* test: swap flow cypress tests

* fix: use default parameter

* feat: use Swap Component on TDP

* feat: auto nav for TDP tokens

* chore: merge

* chore: merge

* chore: merge

* chore: merge

* fix: remove extra inputCurrency URL parsing logic

* fix: undo last change

* fix: pass expected chain id to swap component

* fix: search for default tokens on unconnected networks if needed

* test: e2e test for l2 token

* fix: delete irrelevant tests

* fix: address comments

* fix: lint error

* test: update TDP e2e tests

* fix: use pageChainId for filter

* fix: rename chainId

* fix: typecheck

* fix: chainId bug

* fix: chainId required fixes

* fix: bad merge in e2e test

* fix: remove unused test util

* fix: remove unnecessary variable

* fix: token defaults

* fix: address comments

* fix: address comments and fix tests

* fix: e2e test formatting, remove Maybe<>

* fix: remove unused variable

* fix: use feature flag for swap component on TDP

* fix: back button

* feat: copy review screen UI from widgetg

* fix: modal padding

* feat: add final detail row

* fix: remove widget comment

* fix: update unit tests

* fix: code style consistency

* fix: remove padding from AutoColumn

* fix: update snapshots

* fix: use semantic gaps

* fix: more px and gaps

* fix: design feedbacks

* fix: button radius in summary modal

* fix: design nits

* feat: update design of summary modal

* fix: font weight and vertical spacing

* fix: update snapshots

* fix: css nits

* wip: move approval to summary modal

* wip: not working

* feat: working

* fix: fix flow

* feat: simplify states and build new modal UI

* feat: todos and differs fix

* feat: update tx status modal

* feat: split up approve and permit

* feat: error state

* feat: update success and error states

* feat: undo changes to TxConfirmationModal

* feat: re-order functions

* wip: move approval to summary modal

* wip: not working

* feat: update permit2 e2e tests

* feat: tests passing

* fix: swap test

* fix: bad merge

* wip: move approval to summary modal

* wip: not working

* feat: PendingModalContent tests

* feat: useMaxAmountIn

* fix: bad merge

* fix: naming

* fix: modal flicker when refetching trade

* wip: move approval to summary modal

* wip: not working

* feat: working

* fix: fix flow

* feat: simplify states and build new modal UI

* feat: todos and differs fix

* feat: update tx status modal

* feat: split up approve and permit

* feat: error state

* feat: update success and error states

* feat: undo changes to TxConfirmationModal

* feat: remove step indicators when only one step

* feat: move content into PendingModalContent component

* fix: lint

* chore: merge

* fix: update tests for new modal

* feat: add l2 chain logo to modal

* feat: add unit test

* fix: correct modal state when moving between steps

* fix: correct modal state when moving between steps

* fix: proper error handling of user rejection of swap

* feat: update e2e test

* fix: typecheck

* feat: design updates, state updates

* fix: comments

* fix: code style improvements

* feat: require trade to be defined

* fix: remove extra props from ThemedTexts

* fix: one more trans

* fix: remove unused export

* feat: remove undefined checks and other fixes

* fix: update test

* fix: add missing dollar sign

* fix: remove null check and update test

* fix: remove max width from detail row value

* fix: remove isOpen prop

* fix: isopen

* feat: refactor approval flow into a hook

* fix: custom error type

* fix: testid fix

* fix: text colors

* fix: add comment

* fix: tradeMeaningfullyDiffers improvement and prepareFlow fix

* fix: address  comments

* fix: headerContent prop

* fix: change tooltip to external link

* feat: add comments explaining async state

* fix: test updates

* fix: nits

* fix: reduce nesting

* fix: address comments

* test: remove line from test for debugging

* fix: update tests

* fix: address  comments

* fix: comments

* fix: update tests

* fix: update tests

* fix: more nesting in test

* fix: update test

* fix: update e2e test

* fix: update error test

* fix: update content in test

* fix: reorganize test code
parent 682fba21
...@@ -60,10 +60,10 @@ describe('Permit2', () => { ...@@ -60,10 +60,10 @@ describe('Permit2', () => {
it('swaps after completing full permit2 approval process', () => { it('swaps after completing full permit2 approval process', () => {
initiateSwap() initiateSwap()
cy.contains('Approve permit').should('exist') cy.contains('Allow trading DAI on Uniswap').should('exist')
cy.contains('Approved').should('exist') cy.contains('Approved').should('exist')
cy.contains('Approve DAI').should('exist') cy.contains('Unlock DAI for swapping').should('exist')
cy.contains('Confirm Swap').should('exist') cy.contains('Confirm Swap').should('exist')
cy.then(() => { cy.then(() => {
...@@ -96,7 +96,7 @@ describe('Permit2', () => { ...@@ -96,7 +96,7 @@ describe('Permit2', () => {
}) })
cy.get(getTestSelector('confirm-swap-button')).click() cy.get(getTestSelector('confirm-swap-button')).click()
cy.contains('Approve permit').should('exist') cy.contains('Allow trading DAI on Uniswap').should('exist')
cy.contains('Approved').should('exist') cy.contains('Approved').should('exist')
// permitApprovalStub should reject here, and the modal should revert to the review state. // permitApprovalStub should reject here, and the modal should revert to the review state.
...@@ -200,7 +200,7 @@ describe('Permit2', () => { ...@@ -200,7 +200,7 @@ describe('Permit2', () => {
.then(() => { .then(() => {
initiateSwap() initiateSwap()
const approvalTime = Date.now() const approvalTime = Date.now()
cy.contains('Approve permit').should('exist') cy.contains('Allow trading DAI on Uniswap').should('exist')
cy.contains('Confirm Swap').should('exist') cy.contains('Confirm Swap').should('exist')
cy.contains('Swapped').should('exist') cy.contains('Swapped').should('exist')
......
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.2601 18.3918C12.9161 18.5558 12.5141 18.6779 12.0591 18.7599L5.48907 19.9099C3.29907 20.2999 2.00896 19.3999 1.62896 17.2099L0.0891657 8.45987C-0.300834 6.26987 0.599117 4.97988 2.78912 4.58988L4.58697 4.27384C4.79197 4.23784 4.97114 4.41686 4.93414 4.62186L3.75811 11.2799C3.22811 14.3099 4.65803 16.3499 7.67803 16.8799C7.67803 16.8799 12.8971 17.7969 13.1661 17.8489C13.4981 17.9088 13.5511 18.2628 13.2601 18.3918ZM19.9131 5.10587L18.3689 13.8598C17.997 15.9678 16.7811 16.8688 14.7361 16.5888C14.6581 16.5778 14.5881 16.5779 14.5071 16.5639L7.94195 15.4059C5.75295 15.0199 4.85209 13.7329 5.23809 11.5439L6.58111 3.92783L6.78204 2.78983C7.16804 0.600828 8.4551 -0.300151 10.6441 0.0858488L17.21 1.24387C19.398 1.62987 20.2991 2.91787 19.9131 5.10587ZM13.554 11.8958C13.626 11.4878 13.3541 11.0988 12.9461 11.0268L8.8421 10.3028C8.4361 10.2298 8.04518 10.5039 7.97418 10.9109C7.90218 11.3189 8.17409 11.7079 8.58209 11.7799L12.6861 12.5039C12.7301 12.5119 12.7739 12.5149 12.8169 12.5149C13.1739 12.5159 13.49 12.2598 13.554 11.8958ZM16.597 9.03482C16.669 8.62682 16.3971 8.23787 15.9891 8.16587L9.42413 7.00785C9.02013 6.93685 8.62696 7.20888 8.55596 7.61588C8.48396 8.02388 8.75612 8.41284 9.16412 8.48484L15.7291 9.64286C15.7731 9.65086 15.8172 9.65384 15.8602 9.65384C16.2172 9.65384 16.533 9.39782 16.597 9.03482ZM17.2972 5.77286C17.3692 5.36486 17.097 4.97584 16.689 4.90384L10.1241 3.74582C9.72008 3.67382 9.32716 3.94685 9.25616 4.35385C9.18416 4.76185 9.45607 5.15087 9.86407 5.22287L16.429 6.38083C16.473 6.38883 16.5171 6.39188 16.5601 6.39188C16.9171 6.39288 17.2332 6.13686 17.2972 5.77286Z" fill="#F5F6FC" />
</svg>
...@@ -258,8 +258,9 @@ export default function ConfirmSwapModal({ ...@@ -258,8 +258,9 @@ export default function ConfirmSwapModal({
hideStepIndicators={pendingModalSteps.length === 1} hideStepIndicators={pendingModalSteps.length === 1}
steps={pendingModalSteps} steps={pendingModalSteps}
currentStep={confirmModalState} currentStep={confirmModalState}
approvalCurrency={trade?.inputAmount?.currency} trade={trade}
txHash={txHash} swapTxHash={txHash}
tokenApprovalPending={allowance.state === AllowanceState.REQUIRED && allowance.isApprovalPending}
/> />
) )
}, [ }, [
...@@ -268,6 +269,7 @@ export default function ConfirmSwapModal({ ...@@ -268,6 +269,7 @@ export default function ConfirmSwapModal({
pendingModalSteps, pendingModalSteps,
trade, trade,
txHash, txHash,
allowance,
allowedSlippage, allowedSlippage,
swapQuoteReceivedDate, swapQuoteReceivedDate,
fiatValueInput, fiatValueInput,
......
import { DAI_MAINNET } from '@uniswap/smart-order-router'
import { useIsTransactionConfirmed } from 'state/transactions/hooks' import { useIsTransactionConfirmed } from 'state/transactions/hooks'
import { TEST_TRADE_EXACT_INPUT } from 'test-utils/constants'
import { mocked } from 'test-utils/mocked' import { mocked } from 'test-utils/mocked'
import { render, screen } from 'test-utils/render' import { render, screen } from 'test-utils/render'
...@@ -24,15 +24,12 @@ describe('PendingModalContent', () => { ...@@ -24,15 +24,12 @@ describe('PendingModalContent', () => {
<PendingModalContent <PendingModalContent
steps={[ConfirmModalState.APPROVING_TOKEN]} steps={[ConfirmModalState.APPROVING_TOKEN]}
currentStep={ConfirmModalState.APPROVING_TOKEN} currentStep={ConfirmModalState.APPROVING_TOKEN}
approvalCurrency={DAI_MAINNET} trade={TEST_TRADE_EXACT_INPUT}
/> />
) )
expect(screen.getByText('Approve permit')).toBeInTheDocument() expect(screen.getByText('Allow trading ABC on Uniswap')).toBeInTheDocument()
expect(screen.getByText('Proceed in wallet')).toBeInTheDocument() expect(screen.getByText('Proceed in your wallet')).toBeInTheDocument()
expect(screen.getByText('Why are permits required?')).toBeInTheDocument() expect(screen.getByText('Why is this required?')).toBeInTheDocument()
expect(
screen.getByText('Permit2 allows token approvals to be shared and managed across different applications.')
).toBeInTheDocument()
}) })
describe('renders the correct step when there are multiple', () => { describe('renders the correct step when there are multiple', () => {
...@@ -45,22 +42,13 @@ describe('PendingModalContent', () => { ...@@ -45,22 +42,13 @@ describe('PendingModalContent', () => {
ConfirmModalState.PENDING_CONFIRMATION, ConfirmModalState.PENDING_CONFIRMATION,
]} ]}
currentStep={ConfirmModalState.APPROVING_TOKEN} currentStep={ConfirmModalState.APPROVING_TOKEN}
approvalCurrency={DAI_MAINNET} trade={TEST_TRADE_EXACT_INPUT}
/> />
) )
expect(screen.getByText('Approve permit')).toBeInTheDocument() expect(screen.getByText('Allow trading ABC on Uniswap')).toBeInTheDocument()
expect(screen.getByText('Proceed in wallet')).toBeInTheDocument() expect(screen.getByText('Proceed in your wallet')).toBeInTheDocument()
expect(screen.getByText('Why are permits required?')).toBeInTheDocument() expect(screen.getByText('Why is this required?')).toBeInTheDocument()
expect( expect(screen.queryByText('Unlock ABC for swapping')).not.toBeInTheDocument()
screen.getByText('Permit2 allows token approvals to be shared and managed across different applications.')
).toBeInTheDocument()
expect(screen.queryByText('Approve DAI')).toBeNull()
expect(screen.queryByText('Why are approvals required?')).toBeNull()
expect(
screen.queryByText(
'This provides the Uniswap protocol access to your token for trading. For security, this will expire after 30 days.'
)
).toBeNull()
}) })
it('renders the second step with activeStepIndex=1', () => { it('renders the second step with activeStepIndex=1', () => {
...@@ -72,22 +60,13 @@ describe('PendingModalContent', () => { ...@@ -72,22 +60,13 @@ describe('PendingModalContent', () => {
ConfirmModalState.PENDING_CONFIRMATION, ConfirmModalState.PENDING_CONFIRMATION,
]} ]}
currentStep={ConfirmModalState.PERMITTING} currentStep={ConfirmModalState.PERMITTING}
approvalCurrency={DAI_MAINNET} trade={TEST_TRADE_EXACT_INPUT}
/> />
) )
expect(screen.queryByText('Approve permit')).toBeNull() expect(screen.getByText('Unlock ABC for swapping')).toBeInTheDocument()
expect(screen.queryByText('Why are permits required?')).toBeNull() expect(screen.getByText('Proceed in your wallet')).toBeInTheDocument()
expect( expect(screen.getByText('Why is this required?')).toBeInTheDocument()
screen.queryByText('Permit2 allows token approvals to be shared and managed across different applications.') expect(screen.queryByText('Allow trading ABC on Uniswap')).not.toBeInTheDocument()
).toBeNull()
expect(screen.queryByText('Approve DAI')).toBeInTheDocument()
expect(screen.queryByText('Proceed in wallet')).toBeInTheDocument()
expect(screen.queryByText('Why are approvals required?')).toBeInTheDocument()
expect(
screen.queryByText(
'This provides the Uniswap protocol access to your token for trading. For security, this will expire after 30 days.'
)
).toBeInTheDocument()
}) })
}) })
...@@ -101,10 +80,10 @@ describe('PendingModalContent', () => { ...@@ -101,10 +80,10 @@ describe('PendingModalContent', () => {
ConfirmModalState.PENDING_CONFIRMATION, ConfirmModalState.PENDING_CONFIRMATION,
]} ]}
currentStep={ConfirmModalState.APPROVING_TOKEN} currentStep={ConfirmModalState.APPROVING_TOKEN}
approvalCurrency={DAI_MAINNET} trade={TEST_TRADE_EXACT_INPUT}
/> />
) )
expect(screen.getByTestId('pending-modal-currency-logo-loader-DAI')).toBeInTheDocument() expect(screen.getByTestId('papers-icon-container-ABC')).toBeInTheDocument()
expect(screen.queryByTestId('pending-modal-failure-icon')).toBeNull() expect(screen.queryByTestId('pending-modal-failure-icon')).toBeNull()
}) })
...@@ -125,7 +104,6 @@ describe('PendingModalContent', () => { ...@@ -125,7 +104,6 @@ describe('PendingModalContent', () => {
ConfirmModalState.PENDING_CONFIRMATION, ConfirmModalState.PENDING_CONFIRMATION,
]} ]}
currentStep={ConfirmModalState.PENDING_CONFIRMATION} currentStep={ConfirmModalState.PENDING_CONFIRMATION}
approvalCurrency={DAI_MAINNET}
/> />
) )
expect(screen.queryByTestId('pending-modal-failure-icon')).toBeNull() expect(screen.queryByTestId('pending-modal-failure-icon')).toBeNull()
......
import { t, Trans } from '@lingui/macro' import { t, Trans } from '@lingui/macro'
import { formatCurrencyAmount } from '@uniswap/conedison/format'
import { NumberType } from '@uniswap/conedison/format'
import { Currency } from '@uniswap/sdk-core' import { Currency } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { ButtonPrimary } from 'components/Button' import { ButtonPrimary } from 'components/Button'
import { ColumnCenter } from 'components/Column' import { ColumnCenter } from 'components/Column'
import Loader from 'components/Icons/LoadingSpinner' import Loader from 'components/Icons/LoadingSpinner'
...@@ -7,18 +10,26 @@ import CurrencyLogo from 'components/Logo/CurrencyLogo' ...@@ -7,18 +10,26 @@ import CurrencyLogo from 'components/Logo/CurrencyLogo'
import QuestionHelper from 'components/QuestionHelper' import QuestionHelper from 'components/QuestionHelper'
import Row from 'components/Row' import Row from 'components/Row'
import AnimatedConfirmation from 'components/TransactionConfirmationModal/AnimatedConfirmation' import AnimatedConfirmation from 'components/TransactionConfirmationModal/AnimatedConfirmation'
import { SupportedChainId } from 'constants/chains'
import { ReactNode } from 'react' import { ReactNode } from 'react'
import { AlertTriangle } from 'react-feather' import { AlertTriangle, ArrowRight } from 'react-feather'
import { InterfaceTrade } from 'state/routing/types'
import { useIsTransactionConfirmed } from 'state/transactions/hooks' import { useIsTransactionConfirmed } from 'state/transactions/hooks'
import styled, { DefaultTheme, useTheme } from 'styled-components/macro' import styled, { DefaultTheme, useTheme } from 'styled-components/macro'
import { ExternalLink } from 'theme'
import { ThemedText } from 'theme/components/text' import { ThemedText } from 'theme/components/text'
import { ReactComponent as PapersIcon } from '../../assets/svg/papers-text.svg'
import { ConfirmModalState } from './ConfirmSwapModal' import { ConfirmModalState } from './ConfirmSwapModal'
const Container = styled(ColumnCenter)` const Container = styled(ColumnCenter)`
margin: 48px 0 28px; margin: 48px 0 28px;
` `
const HeaderContainer = styled(ColumnCenter)<{ $disabled?: boolean }>`
${({ $disabled }) => $disabled && `opacity: 0.5;`}
`
const LogoContainer = styled.div` const LogoContainer = styled.div`
position: relative; position: relative;
display: flex; display: flex;
...@@ -52,6 +63,70 @@ const LoadingIndicator = styled(Loader)` ...@@ -52,6 +63,70 @@ const LoadingIndicator = styled(Loader)`
position: absolute; position: absolute;
` `
function CurrencyLoader({ currency }: { currency?: Currency }) {
const theme = useTheme()
return (
<LogoContainer data-testid={`pending-modal-currency-logo-loader-${currency?.symbol}`}>
<LogoLayer>
<CurrencyLogo currency={currency} size="48px" />
</LogoLayer>
<LoadingIndicator stroke={theme.textTertiary} />
</LogoContainer>
)
}
const PinkCircle = styled(LogoContainer)`
display: flex;
height: 48px;
width: 48px;
align-items: center;
justify-content: center;
background-color: ${({ theme }) => theme.userThemeColor};
z-index: 1;
`
function PaperIcon({ currency, loading }: { currency?: Currency; loading: boolean }) {
const theme = useTheme()
return (
<LogoContainer data-testid={`papers-icon-container-${currency?.symbol}`}>
<PinkCircle>
<PapersIcon />
<CurrencyLogo
currency={currency}
size="20px"
style={{
position: 'absolute',
bottom: '-4px',
right: '-4px',
outline: `2px solid ${theme.background}`,
borderRadius: '50%',
}}
/>
</PinkCircle>
{loading && <LoadingIndicator stroke={theme.textTertiary} />}
</LogoContainer>
)
}
function TradeSummary({ trade }: { trade: InterfaceTrade }) {
const theme = useTheme()
return (
<Row gap="sm">
<CurrencyLogo currency={trade.inputAmount.currency} size="16px" />
<ThemedText.LabelSmall color="textPrimary">
{formatCurrencyAmount(trade.inputAmount, NumberType.SwapTradeAmount)}
</ThemedText.LabelSmall>
<ThemedText.LabelSmall color="textPrimary">{trade.inputAmount.currency.symbol}</ThemedText.LabelSmall>
<ArrowRight color={theme.textPrimary} size="12px" />
<CurrencyLogo currency={trade.outputAmount.currency} size="16px" />
<ThemedText.LabelSmall color="textPrimary">
{formatCurrencyAmount(trade.outputAmount, NumberType.SwapTradeAmount)}
</ThemedText.LabelSmall>
<ThemedText.LabelSmall color="textPrimary">{trade.outputAmount.currency.symbol}</ThemedText.LabelSmall>
</Row>
)
}
// This component is used for all steps after ConfirmModalState.REVIEWING // This component is used for all steps after ConfirmModalState.REVIEWING
export type PendingConfirmModalState = Extract< export type PendingConfirmModalState = Extract<
ConfirmModalState, ConfirmModalState,
...@@ -70,51 +145,73 @@ interface PendingModalStep { ...@@ -70,51 +145,73 @@ interface PendingModalStep {
interface PendingModalContentProps { interface PendingModalContentProps {
steps: PendingConfirmModalState[] steps: PendingConfirmModalState[]
currentStep: PendingConfirmModalState currentStep: PendingConfirmModalState
approvalCurrency?: Currency trade?: InterfaceTrade
swapTxHash?: string
hideStepIndicators?: boolean hideStepIndicators?: boolean
txHash?: string tokenApprovalPending?: boolean
} }
function CurrencyLoader({ currency }: { currency?: Currency }) { interface ContentArgs {
const theme = useTheme() chainId?: number
return ( step: PendingConfirmModalState
<LogoContainer data-testid={`pending-modal-currency-logo-loader-${currency?.symbol}`}> approvalCurrency?: Currency
<LogoLayer> trade?: InterfaceTrade
<CurrencyLogo currency={currency} size="48px" /> swapConfirmed: boolean
</LogoLayer> swapPending: boolean
<LoadingIndicator stroke={theme.textTertiary} /> tokenApprovalPending: boolean
</LogoContainer> theme: DefaultTheme
) swapTxHash?: string
} }
function getContent( function getContent(args: ContentArgs): PendingModalStep {
step: PendingConfirmModalState, const { chainId, step, approvalCurrency, swapConfirmed, swapPending, tokenApprovalPending, theme, trade } = args
approvalCurrency: Currency | undefined,
confirmed: boolean,
theme: DefaultTheme
): PendingModalStep {
switch (step) { switch (step) {
case ConfirmModalState.APPROVING_TOKEN: case ConfirmModalState.APPROVING_TOKEN:
return { return {
title: t`Approve permit`, title: t`Allow trading ${approvalCurrency?.symbol ?? 'token'} on Uniswap`,
subtitle: t`Proceed in wallet`, subtitle: (
label: t`Why are permits required?`, <>
tooltipText: t`Permit2 allows token approvals to be shared and managed across different applications.`, <Trans>First, we need your permission to use your DAI for swapping.</Trans>{' '}
logo: <CurrencyLoader currency={approvalCurrency} />, <ExternalLink href="https://support.uniswap.org/hc/en-us/articles/8120520483085">
<Trans>Why is this required?</Trans>
</ExternalLink>
</>
),
label: tokenApprovalPending ? t`Pending...` : t`Proceed in your wallet`,
logo: <PaperIcon currency={approvalCurrency} loading={tokenApprovalPending} />,
} }
case ConfirmModalState.PERMITTING: case ConfirmModalState.PERMITTING:
return { return {
title: t`Approve ${approvalCurrency?.symbol ?? 'token'}`, title: t`Unlock ${approvalCurrency?.symbol ?? 'token'} for swapping`,
subtitle: t`Proceed in wallet`, subtitle: (
label: t`Why are approvals required?`, <>
tooltipText: t`This provides the Uniswap protocol access to your token for trading. For security, this will expire after 30 days.`, <Trans>This will expire after 30 days for your security.</Trans>{' '}
<ExternalLink href="https://support.uniswap.org/hc/en-us/articles/360056642192">
<Trans>Why is this required?</Trans>
</ExternalLink>
</>
),
label: t`Proceed in your wallet`,
logo: <CurrencyLoader currency={approvalCurrency} />, logo: <CurrencyLoader currency={approvalCurrency} />,
} }
case ConfirmModalState.PENDING_CONFIRMATION: case ConfirmModalState.PENDING_CONFIRMATION:
return { return {
title: t`Confirm Swap`, title: swapPending ? t`Transaction submitted` : swapConfirmed ? t`Success` : t`Confirm Swap`,
subtitle: t`Proceed in wallet`, subtitle: swapConfirmed ? (
logo: confirmed ? <SizedAnimatedConfirmation /> : <Loader stroke={theme.textTertiary} size="48px" />, <ExternalLink href={`https://etherscan.io/tx/${swapConfirmed}`} color="textSecondary">
<Trans>View on Explorer</Trans>
</ExternalLink>
) : trade ? (
<TradeSummary trade={trade} />
) : null,
label: !swapPending && !swapConfirmed ? t`Proceed in your wallet` : null,
logo:
// On mainnet, we show the success icon once the tx is sent, since it takes longer to confirm than on L2s.
swapConfirmed || (swapPending && chainId === SupportedChainId.MAINNET) ? (
<SizedAnimatedConfirmation />
) : (
<Loader stroke={theme.textTertiary} size="48px" />
),
} }
} }
} }
...@@ -122,39 +219,50 @@ function getContent( ...@@ -122,39 +219,50 @@ function getContent(
export function PendingModalContent({ export function PendingModalContent({
steps, steps,
currentStep, currentStep,
approvalCurrency, trade,
txHash, swapTxHash,
hideStepIndicators, hideStepIndicators,
tokenApprovalPending = false,
}: PendingModalContentProps) { }: PendingModalContentProps) {
const theme = useTheme() const theme = useTheme()
const confirmed = useIsTransactionConfirmed(txHash) const { chainId } = useWeb3React()
const { logo, title, subtitle, label, tooltipText, button } = getContent( const swapConfirmed = useIsTransactionConfirmed(swapTxHash)
currentStep, const swapPending = swapTxHash !== undefined && !swapConfirmed
approvalCurrency, const { logo, title, subtitle, label, button } = getContent({
confirmed, chainId,
theme step: currentStep,
) approvalCurrency: trade?.inputAmount.currency,
swapConfirmed,
swapPending,
tokenApprovalPending,
theme,
swapTxHash,
trade,
})
if (steps.length === 0) { if (steps.length === 0) {
return null return null
} }
return ( return (
<Container gap="lg"> <Container gap="lg">
{logo} {logo}
{/* TODO: implement animations between title/subtitles of each step. */} {/* TODO: implement animations between title/subtitles of each step. */}
<ColumnCenter gap="md"> <HeaderContainer gap="md" $disabled={tokenApprovalPending || swapPending}>
<ThemedText.HeadlineSmall data-testid="PendingModalContent-title">{title}</ThemedText.HeadlineSmall> <ThemedText.HeadlineSmall data-testid="PendingModalContent-title">{title}</ThemedText.HeadlineSmall>
{subtitle && ( {subtitle && (
<ThemedText.LabelSmall data-testid="PendingModalContent-subtitle">{subtitle}</ThemedText.LabelSmall> <ThemedText.LabelSmall textAlign="center" data-testid="PendingModalContent-subtitle">
{subtitle}
</ThemedText.LabelSmall>
)} )}
<Row justify="center"> <Row justify="center" marginTop="32px">
{label && ( {label && (
<ThemedText.Caption color="textSecondary" data-testid="PendingModalContent-label"> <ThemedText.Caption color="textSecondary" data-testid="PendingModalContent-label">
{label} {label}
</ThemedText.Caption> </ThemedText.Caption>
)} )}
{tooltipText && <QuestionHelper text={tooltipText} />}
</Row> </Row>
</ColumnCenter> </HeaderContainer>
{button && ( {button && (
<Row justify="center" data-testid="PendingModalContent-button"> <Row justify="center" data-testid="PendingModalContent-button">
{button} {button}
...@@ -198,7 +306,7 @@ function getErrorContent(errorType: PendingModalError) { ...@@ -198,7 +306,7 @@ function getErrorContent(errorType: PendingModalError) {
} }
case PendingModalError.CONFIRMATION_ERROR: case PendingModalError.CONFIRMATION_ERROR:
return { return {
title: t`Confirmation failed`, title: t`Swap failed`,
} }
} }
} }
......
...@@ -24,6 +24,7 @@ interface AllowanceRequired { ...@@ -24,6 +24,7 @@ interface AllowanceRequired {
state: AllowanceState.REQUIRED state: AllowanceState.REQUIRED
token: Token token: Token
isApprovalLoading: boolean isApprovalLoading: boolean
isApprovalPending: boolean
approveAndPermit: () => Promise<void> approveAndPermit: () => Promise<void>
approve: () => Promise<void> approve: () => Promise<void>
permit: () => Promise<void> permit: () => Promise<void>
...@@ -127,6 +128,7 @@ export default function usePermit2Allowance(amount?: CurrencyAmount<Token>, spen ...@@ -127,6 +128,7 @@ export default function usePermit2Allowance(amount?: CurrencyAmount<Token>, spen
token, token,
state: AllowanceState.REQUIRED, state: AllowanceState.REQUIRED,
isApprovalLoading: false, isApprovalLoading: false,
isApprovalPending,
approveAndPermit, approveAndPermit,
approve, approve,
permit, permit,
...@@ -138,6 +140,7 @@ export default function usePermit2Allowance(amount?: CurrencyAmount<Token>, spen ...@@ -138,6 +140,7 @@ export default function usePermit2Allowance(amount?: CurrencyAmount<Token>, spen
token, token,
state: AllowanceState.REQUIRED, state: AllowanceState.REQUIRED,
isApprovalLoading, isApprovalLoading,
isApprovalPending,
approveAndPermit, approveAndPermit,
approve, approve,
permit, permit,
...@@ -157,6 +160,7 @@ export default function usePermit2Allowance(amount?: CurrencyAmount<Token>, spen ...@@ -157,6 +160,7 @@ export default function usePermit2Allowance(amount?: CurrencyAmount<Token>, spen
approve, approve,
approveAndPermit, approveAndPermit,
isApprovalLoading, isApprovalLoading,
isApprovalPending,
isApproved, isApproved,
isPermitted, isPermitted,
isSigned, isSigned,
......
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