feat: updated rate/routing tooltips (#7412)

* feat: updated routing tooltips

* refactor: gas price formatting

* fit: boolean rendering
This commit is contained in:
cartcrom 2023-10-05 17:25:53 -04:00 committed by GitHub
parent 2d8dac5c15
commit 932c4482d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 557 additions and 543 deletions

@ -14,7 +14,7 @@ import { Z_INDEX } from 'theme/zIndex'
import { RoutingDiagramEntry } from 'utils/getRoutingDiagramEntries'
import { ReactComponent as DotLine } from '../../assets/svg/dot_line.svg'
import { MouseoverTooltip } from '../Tooltip'
import { MouseoverTooltip, TooltipSize } from '../Tooltip'
const Wrapper = styled(Box)`
align-items: center;
@ -142,6 +142,7 @@ function Pool({ currency0, currency1, feeAmount }: { currency0: Currency; curren
return (
<MouseoverTooltip
text={<Trans>{tokenInfo0?.symbol + '/' + tokenInfo1?.symbol + ' ' + feeAmount / 10000}% pool</Trans>}
size={TooltipSize.ExtraSmall}
>
<PoolBadge>
<Box margin="0 4px 0 12px">

@ -20,7 +20,8 @@ import { getPriceImpactColor } from 'utils/prices'
import { GasBreakdownTooltip, UniswapXDescription } from './GasBreakdownTooltip'
import { MaxSlippageTooltip } from './MaxSlippageTooltip'
import SwapRoute from './SwapRoute'
import { RoutingTooltip, SwapRoute } from './SwapRoute'
import TradePrice from './TradePrice'
export enum SwapLineItemType {
EXCHANGE_RATE,
@ -76,15 +77,6 @@ function Loading({ width = 50 }: { width?: number }) {
return <LoadingRow data-testid="loading-row" height={15} width={width} />
}
function ExchangeRateRow({ trade }: { trade: InterfaceTrade }) {
const { formatNumber } = useFormatter()
const rate = `1 ${trade.executionPrice.quoteCurrency.symbol} = ${formatNumber({
input: parseFloat(trade.executionPrice.toFixed(9)),
type: NumberType.TokenTx,
})} ${trade.executionPrice.baseCurrency.symbol}`
return <>{rate}</>
}
function ColoredPercentRow({ percent }: { percent: Percent }) {
const { formatSlippage } = useFormatter()
return <ColorWrapper textColor={getPriceImpactColor(percent)}>{formatSlippage(percent)}</ColorWrapper>
@ -122,8 +114,10 @@ function useLineItem(props: SwapLineItemProps): LineItemData | undefined {
switch (type) {
case SwapLineItemType.EXCHANGE_RATE:
return {
Label: () => <Trans>Exchange rate</Trans>,
Value: () => <ExchangeRateRow trade={trade} />,
Label: () => <Trans>Rate</Trans>,
Value: () => <TradePrice price={trade.executionPrice} />,
TooltipBody: !isPreview ? () => <RoutingTooltip trade={trade} /> : undefined,
tooltipSize: isUniswapX ? TooltipSize.Small : TooltipSize.Large,
}
case SwapLineItemType.NETWORK_COST:
if (!SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId)) return
@ -185,12 +179,12 @@ function useLineItem(props: SwapLineItemProps): LineItemData | undefined {
loaderWidth: 70,
}
case SwapLineItemType.ROUTING_INFO:
if (isPreview) return { Label: () => <Trans>Order routing</Trans>, Value: () => <Loading /> }
if (isPreview || syncing) return { Label: () => <Trans>Order routing</Trans>, Value: () => <Loading /> }
return {
Label: () => <Trans>Order routing</Trans>,
TooltipBody: () => {
if (isUniswapX) return <UniswapXDescription />
return <SwapRoute data-testid="swap-route-info" trade={trade} syncing={syncing} />
return <SwapRoute data-testid="swap-route-info" trade={trade} />
},
tooltipSize: isUniswapX ? TooltipSize.Small : TooltipSize.Large,
Value: () => <RouterLabel trade={trade} />,

@ -1,64 +1,83 @@
import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core'
import Column from 'components/Column'
import { LoadingRows } from 'components/Loader/styled'
import RoutingDiagram from 'components/RoutingDiagram/RoutingDiagram'
import { RowBetween } from 'components/Row'
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains'
import useAutoRouterSupported from 'hooks/useAutoRouterSupported'
import { ClassicTrade } from 'state/routing/types'
import { ClassicTrade, SubmittableTrade } from 'state/routing/types'
import { isClassicTrade } from 'state/routing/utils'
import { Separator, ThemedText } from 'theme/components'
import { NumberType, useFormatter } from 'utils/formatNumbers'
import getRoutingDiagramEntries from 'utils/getRoutingDiagramEntries'
import RouterLabel from '../RouterLabel'
import { UniswapXDescription } from './GasBreakdownTooltip'
export default function SwapRoute({ trade, syncing }: { trade: ClassicTrade; syncing: boolean }) {
const { chainId } = useWeb3React()
const autoRouterSupported = useAutoRouterSupported()
// TODO(WEB-2022)
// Can `trade.gasUseEstimateUSD` be defined when `chainId` is not in `SUPPORTED_GAS_ESTIMATE_CHAIN_IDS`?
function useGasPrice({ gasUseEstimateUSD, inputAmount }: ClassicTrade) {
const { formatNumber } = useFormatter()
if (!gasUseEstimateUSD || !SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(inputAmount.currency.chainId)) return undefined
const routes = getRoutingDiagramEntries(trade)
const gasPrice =
// TODO(WEB-2022)
// Can `trade.gasUseEstimateUSD` be defined when `chainId` is not in `SUPPORTED_GAS_ESTIMATE_CHAIN_IDS`?
trade.gasUseEstimateUSD && chainId && SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId)
? trade.gasUseEstimateUSD === 0
? '<$0.01'
: '$' + trade.gasUseEstimateUSD.toFixed(2)
: undefined
return gasUseEstimateUSD === 0 ? '<$0.01' : formatNumber({ input: gasUseEstimateUSD, type: NumberType.FiatGasPrice })
}
function RouteLabel({ trade }: { trade: SubmittableTrade }) {
return (
<RowBetween>
<ThemedText.BodySmall color="neutral2">Order Routing</ThemedText.BodySmall>
<RouterLabel trade={trade} color="neutral1" />
</RowBetween>
)
}
function PriceImpactRow({ trade }: { trade: ClassicTrade }) {
const { formatPriceImpact } = useFormatter()
return (
<ThemedText.BodySmall color="neutral2">
<RowBetween>
<Trans>Price Impact</Trans>
<div>{formatPriceImpact(trade.priceImpact)}</div>
</RowBetween>
</ThemedText.BodySmall>
)
}
export function RoutingTooltip({ trade }: { trade: SubmittableTrade }) {
return isClassicTrade(trade) ? (
<Column gap="md">
<RouterLabel trade={trade} color="neutral2" />
<PriceImpactRow trade={trade} />
<Separator />
{syncing ? (
<LoadingRows>
<div style={{ width: '100%', height: '30px' }} />
</LoadingRows>
<RouteLabel trade={trade} />
<SwapRoute trade={trade} />
</Column>
) : (
<RoutingDiagram
currencyIn={trade.inputAmount.currency}
currencyOut={trade.outputAmount.currency}
routes={routes}
/>
)}
{autoRouterSupported && (
<>
<Column gap="md">
<RouteLabel trade={trade} />
<Separator />
{syncing ? (
<LoadingRows>
<div style={{ width: '100%', height: '15px' }} />
</LoadingRows>
) : (
<ThemedText.Caption color="neutral2">
{gasPrice ? <Trans>Best price route costs ~{gasPrice} in gas.</Trans> : null}{' '}
<Trans>
This route optimizes your total output by considering split routes, multiple hops, and the gas cost of
each step.
</Trans>
</ThemedText.Caption>
)}
</>
)}
<UniswapXDescription />
</Column>
)
}
export function SwapRoute({ trade }: { trade: ClassicTrade }) {
const { inputAmount, outputAmount } = trade
const routes = getRoutingDiagramEntries(trade)
const gasPrice = useGasPrice(trade)
return useAutoRouterSupported() ? (
<Column gap="md">
<RoutingDiagram routes={routes} currencyIn={inputAmount.currency} currencyOut={outputAmount.currency} />
<ThemedText.Caption color="neutral2">
{Boolean(gasPrice) && <Trans>Best price route costs ~{gasPrice} in gas. </Trans>}
{Boolean(gasPrice) && ' '}
<Trans>
This route optimizes your total output by considering split routes, multiple hops, and the gas cost of each
step.
</Trans>
</ThemedText.Caption>
</Column>
) : (
<RoutingDiagram routes={routes} currencyIn={inputAmount.currency} currencyOut={outputAmount.currency} />
)
}

@ -146,28 +146,6 @@ exports[`SwapDetailsDropdown.tsx renders a trade 1`] = `
fill: #7D7D7D;
}
.c20 {
text-align: right;
overflow-wrap: break-word;
}
.c19 {
cursor: help;
color: #7D7D7D;
}
.c22 {
background: #22222212;
border-radius: 8px;
color: #7D7D7D;
height: 20px;
padding: 0 6px;
}
.c22::after {
content: 'Auto';
}
.c8 {
background-color: transparent;
border: none;
@ -200,6 +178,28 @@ exports[`SwapDetailsDropdown.tsx renders a trade 1`] = `
user-select: text;
}
.c20 {
text-align: right;
overflow-wrap: break-word;
}
.c19 {
cursor: help;
color: #7D7D7D;
}
.c22 {
background: #22222212;
border-radius: 8px;
color: #7D7D7D;
height: 20px;
padding: 0 6px;
}
.c22::after {
content: 'Auto';
}
.c5 {
padding: 0;
-webkit-align-items: center;

File diff suppressed because it is too large Load Diff

@ -91,22 +91,49 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
gap: 12px;
}
.c9 {
.c7 {
display: inline-block;
height: inherit;
}
.c7 {
.c9 {
background-color: transparent;
border: none;
cursor: pointer;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
padding: 0;
grid-template-columns: 1fr auto;
grid-gap: 0.25rem;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
text-align: left;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
}
.c8 {
text-align: right;
overflow-wrap: break-word;
}
.c6 {
cursor: auto;
color: #7D7D7D;
}
.c8 {
cursor: help;
color: #7D7D7D;
}
@ -137,29 +164,45 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
class="c5 c6 css-142zc9n"
data-testid="swap-li-label"
>
Exchange rate
Rate
</div>
<div
class="c5 c7 css-142zc9n"
class="c7"
>
<div>
<div
class="c5 c8 css-142zc9n"
>
<button
class="c9"
title="1 DEF = 1.00 ABC "
>
<div
class="c5 css-142zc9n"
>
1 DEF = 1.00 ABC
</div>
</button>
</div>
</div>
</div>
</div>
<div
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
class="c5 c6 css-142zc9n"
data-testid="swap-li-label"
>
Price impact
</div>
<div
class="c9"
class="c7"
>
<div>
<div
class="c5 c7 css-142zc9n"
class="c5 c8 css-142zc9n"
>
<span
class=""
@ -174,17 +217,17 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
class="c5 c6 css-142zc9n"
data-testid="swap-li-label"
>
Max. slippage
</div>
<div
class="c9"
class="c7"
>
<div>
<div
class="c5 c7 css-142zc9n"
class="c5 c8 css-142zc9n"
>
<div
class="c2 c10"
@ -202,17 +245,17 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
class="c5 c6 css-142zc9n"
data-testid="swap-li-label"
>
Receive at least
</div>
<div
class="c9"
class="c7"
>
<div>
<div
class="c5 c7 css-142zc9n"
class="c5 c8 css-142zc9n"
>
0.00000000000000098 DEF
</div>
@ -223,17 +266,17 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
class="c5 c6 css-142zc9n"
data-testid="swap-li-label"
>
Network cost
</div>
<div
class="c9"
class="c7"
>
<div>
<div
class="c5 c7 css-142zc9n"
class="c5 c8 css-142zc9n"
>
<div
class="c2 c13"
@ -447,7 +490,7 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
justify-content: flex-start;
}
.c11 {
.c12 {
width: 100%;
display: -webkit-box;
display: -webkit-flex;
@ -476,7 +519,7 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
color: #222222;
}
.c12 {
.c13 {
color: #7D7D7D;
}
@ -495,7 +538,7 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
gap: 12px;
}
.c10 {
.c11 {
-webkit-animation: fAQEyV 1.5s infinite;
animation: fAQEyV 1.5s infinite;
-webkit-animation-fill-mode: both;
@ -508,11 +551,43 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
width: 50px;
}
.c9 {
.c10 {
display: inline-block;
height: inherit;
}
.c8 {
background-color: transparent;
border: none;
cursor: pointer;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
padding: 0;
grid-template-columns: 1fr auto;
grid-gap: 0.25rem;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
text-align: left;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
}
.c7 {
text-align: right;
overflow-wrap: break-word;
@ -523,12 +598,12 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
color: #7D7D7D;
}
.c8 {
.c9 {
cursor: help;
color: #7D7D7D;
}
.c13 {
.c14 {
background: #22222212;
border-radius: 8px;
color: #7D7D7D;
@ -536,7 +611,7 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
padding: 0 6px;
}
.c13::after {
.c14::after {
content: 'Auto';
}
@ -558,32 +633,42 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
class="c5 c6 css-142zc9n"
data-testid="swap-li-label"
>
Exchange rate
Rate
</div>
<div
class="c5 c7 css-142zc9n"
>
<button
class="c8"
title="1 DEF = 1.00 ABC "
>
<div
class="c5 css-142zc9n"
>
1 DEF = 1.00 ABC
</div>
</button>
</div>
</div>
<div
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
class="c5 c9 css-142zc9n"
data-testid="swap-li-label"
>
Price impact
</div>
<div
class="c9"
class="c10"
>
<div>
<div
class="c5 c7 css-142zc9n"
>
<div
class="c10"
class="c11"
data-testid="loading-row"
height="15"
width="50"
@ -596,23 +681,23 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
class="c5 c9 css-142zc9n"
data-testid="swap-li-label"
>
Max. slippage
</div>
<div
class="c9"
class="c10"
>
<div>
<div
class="c5 c7 css-142zc9n"
>
<div
class="c2 c11"
class="c2 c12"
>
<div
class="c12 c13 css-1lgneq0"
class="c13 c14 css-1lgneq0"
/>
2%
</div>
@ -624,13 +709,13 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
class="c5 c9 css-142zc9n"
data-testid="swap-li-label"
>
Receive at least
</div>
<div
class="c9"
class="c10"
>
<div>
<div
@ -645,20 +730,20 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
class="c5 c9 css-142zc9n"
data-testid="swap-li-label"
>
Network cost
</div>
<div
class="c9"
class="c10"
>
<div>
<div
class="c5 c7 css-142zc9n"
>
<div
class="c10"
class="c11"
data-testid="loading-row"
height="15"
width="50"