Commit 9318c120 authored by 0xlucius's avatar 0xlucius Committed by GitHub

feat: Add on-hover tooltips for tx details (#3178)

* Add on-hover tooltips for tx details

* Change tooltips to use <Trans> macro instead of t

* fix: remove info tooltip on transaction popup

* fix: update getting the nativeCurrencyVariable

* use getNativeCurrency() instead of chainInfo const
Co-authored-by: default avatarChristine Legge <christine.legge@uniswap.org>
parent 5055695b
...@@ -18,6 +18,7 @@ export const TooltipContainer = styled.div` ...@@ -18,6 +18,7 @@ export const TooltipContainer = styled.div`
interface TooltipProps extends Omit<PopoverProps, 'content'> { interface TooltipProps extends Omit<PopoverProps, 'content'> {
text: ReactNode text: ReactNode
disableHover?: boolean // disable the hover and content display
} }
interface TooltipContentProps extends Omit<PopoverProps, 'content'> { interface TooltipContentProps extends Omit<PopoverProps, 'content'> {
...@@ -29,19 +30,20 @@ interface TooltipContentProps extends Omit<PopoverProps, 'content'> { ...@@ -29,19 +30,20 @@ interface TooltipContentProps extends Omit<PopoverProps, 'content'> {
} }
export default function Tooltip({ text, ...rest }: TooltipProps) { export default function Tooltip({ text, ...rest }: TooltipProps) {
return <Popover content={<TooltipContainer>{text}</TooltipContainer>} {...rest} /> return <Popover content={text && <TooltipContainer>{text}</TooltipContainer>} {...rest} />
} }
function TooltipContent({ content, wrap = false, ...rest }: TooltipContentProps) { function TooltipContent({ content, wrap = false, ...rest }: TooltipContentProps) {
return <Popover content={wrap ? <TooltipContainer>{content}</TooltipContainer> : content} {...rest} /> return <Popover content={wrap ? <TooltipContainer>{content}</TooltipContainer> : content} {...rest} />
} }
export function MouseoverTooltip({ children, ...rest }: Omit<TooltipProps, 'show'>) { /** Standard text tooltip. */
export function MouseoverTooltip({ text, disableHover, children, ...rest }: Omit<TooltipProps, 'show'>) {
const [show, setShow] = useState(false) const [show, setShow] = useState(false)
const open = useCallback(() => setShow(true), [setShow]) const open = useCallback(() => setShow(true), [setShow])
const close = useCallback(() => setShow(false), [setShow]) const close = useCallback(() => setShow(false), [setShow])
return ( return (
<Tooltip {...rest} show={show}> <Tooltip {...rest} show={show} text={disableHover ? null : text}>
<div onMouseEnter={open} onMouseLeave={close}> <div onMouseEnter={open} onMouseLeave={close}>
{children} {children}
</div> </div>
...@@ -49,6 +51,7 @@ export function MouseoverTooltip({ children, ...rest }: Omit<TooltipProps, 'show ...@@ -49,6 +51,7 @@ export function MouseoverTooltip({ children, ...rest }: Omit<TooltipProps, 'show
) )
} }
/** Tooltip that displays custom content. */
export function MouseoverTooltipContent({ export function MouseoverTooltipContent({
content, content,
children, children,
......
...@@ -4,6 +4,7 @@ import Card from 'components/Card' ...@@ -4,6 +4,7 @@ import Card from 'components/Card'
import { LoadingRows } from 'components/Loader/styled' import { LoadingRows } from 'components/Loader/styled'
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains' import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains'
import useActiveWeb3React from 'hooks/useActiveWeb3React' import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import { useContext, useMemo } from 'react' import { useContext, useMemo } from 'react'
import { InterfaceTrade } from 'state/routing/types' import { InterfaceTrade } from 'state/routing/types'
import styled, { ThemeContext } from 'styled-components/macro' import styled, { ThemeContext } from 'styled-components/macro'
...@@ -12,6 +13,7 @@ import { Separator, ThemedText } from '../../theme' ...@@ -12,6 +13,7 @@ import { Separator, ThemedText } from '../../theme'
import { computeRealizedLPFeePercent } from '../../utils/prices' import { computeRealizedLPFeePercent } from '../../utils/prices'
import { AutoColumn } from '../Column' import { AutoColumn } from '../Column'
import { RowBetween, RowFixed } from '../Row' import { RowBetween, RowFixed } from '../Row'
import { MouseoverTooltip } from '../Tooltip'
import FormattedPriceImpact from './FormattedPriceImpact' import FormattedPriceImpact from './FormattedPriceImpact'
const StyledCard = styled(Card)` const StyledCard = styled(Card)`
...@@ -23,6 +25,7 @@ interface AdvancedSwapDetailsProps { ...@@ -23,6 +25,7 @@ interface AdvancedSwapDetailsProps {
allowedSlippage: Percent allowedSlippage: Percent
syncing?: boolean syncing?: boolean
hideRouteDiagram?: boolean hideRouteDiagram?: boolean
hideInfoTooltips?: boolean
} }
function TextWithLoadingPlaceholder({ function TextWithLoadingPlaceholder({
...@@ -43,9 +46,15 @@ function TextWithLoadingPlaceholder({ ...@@ -43,9 +46,15 @@ function TextWithLoadingPlaceholder({
) )
} }
export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }: AdvancedSwapDetailsProps) { export function AdvancedSwapDetails({
trade,
allowedSlippage,
syncing = false,
hideInfoTooltips = false,
}: AdvancedSwapDetailsProps) {
const theme = useContext(ThemeContext) const theme = useContext(ThemeContext)
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
const nativeCurrency = useNativeCurrency()
const { expectedOutputAmount, priceImpact } = useMemo(() => { const { expectedOutputAmount, priceImpact } = useMemo(() => {
if (!trade) return { expectedOutputAmount: undefined, priceImpact: undefined } if (!trade) return { expectedOutputAmount: undefined, priceImpact: undefined }
...@@ -60,9 +69,19 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }: ...@@ -60,9 +69,19 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }:
<AutoColumn gap="8px"> <AutoColumn gap="8px">
<RowBetween> <RowBetween>
<RowFixed> <RowFixed>
<ThemedText.SubHeader color={theme.text1}> <MouseoverTooltip
<Trans>Expected Output</Trans> text={
</ThemedText.SubHeader> <Trans>
The amount you expect to receive at the current market price. You may receive less or more if the
market price changes while your transaction is pending.
</Trans>
}
disableHover={hideInfoTooltips}
>
<ThemedText.SubHeader color={theme.text1}>
<Trans>Expected Output</Trans>
</ThemedText.SubHeader>
</MouseoverTooltip>
</RowFixed> </RowFixed>
<TextWithLoadingPlaceholder syncing={syncing} width={65}> <TextWithLoadingPlaceholder syncing={syncing} width={65}>
<ThemedText.Black textAlign="right" fontSize={14}> <ThemedText.Black textAlign="right" fontSize={14}>
...@@ -74,9 +93,14 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }: ...@@ -74,9 +93,14 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }:
</RowBetween> </RowBetween>
<RowBetween> <RowBetween>
<RowFixed> <RowFixed>
<ThemedText.SubHeader color={theme.text1}> <MouseoverTooltip
<Trans>Price Impact</Trans> text={<Trans>The impact your trade has on the market price of this pool.</Trans>}
</ThemedText.SubHeader> disableHover={hideInfoTooltips}
>
<ThemedText.SubHeader color={theme.text1}>
<Trans>Price Impact</Trans>
</ThemedText.SubHeader>
</MouseoverTooltip>
</RowFixed> </RowFixed>
<TextWithLoadingPlaceholder syncing={syncing} width={50}> <TextWithLoadingPlaceholder syncing={syncing} width={50}>
<ThemedText.Black textAlign="right" fontSize={14}> <ThemedText.Black textAlign="right" fontSize={14}>
...@@ -87,14 +111,24 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }: ...@@ -87,14 +111,24 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }:
<Separator /> <Separator />
<RowBetween> <RowBetween>
<RowFixed style={{ marginRight: '20px' }}> <RowFixed style={{ marginRight: '20px' }}>
<ThemedText.SubHeader color={theme.text3}> <MouseoverTooltip
{trade.tradeType === TradeType.EXACT_INPUT ? ( text={
<Trans>Minimum received</Trans> <Trans>
) : ( The minimum amount you are guaranteed to receive. If the price slips any further, your transaction
<Trans>Maximum sent</Trans> will revert.
)}{' '} </Trans>
<Trans>after slippage</Trans> ({allowedSlippage.toFixed(2)}%) }
</ThemedText.SubHeader> disableHover={hideInfoTooltips}
>
<ThemedText.SubHeader color={theme.text3}>
{trade.tradeType === TradeType.EXACT_INPUT ? (
<Trans>Minimum received</Trans>
) : (
<Trans>Maximum sent</Trans>
)}{' '}
<Trans>after slippage</Trans> ({allowedSlippage.toFixed(2)}%)
</ThemedText.SubHeader>
</MouseoverTooltip>
</RowFixed> </RowFixed>
<TextWithLoadingPlaceholder syncing={syncing} width={70}> <TextWithLoadingPlaceholder syncing={syncing} width={70}>
<ThemedText.Black textAlign="right" fontSize={14} color={theme.text3}> <ThemedText.Black textAlign="right" fontSize={14} color={theme.text3}>
...@@ -106,9 +140,18 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }: ...@@ -106,9 +140,18 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }:
</RowBetween> </RowBetween>
{!trade?.gasUseEstimateUSD || !chainId || !SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) ? null : ( {!trade?.gasUseEstimateUSD || !chainId || !SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) ? null : (
<RowBetween> <RowBetween>
<ThemedText.SubHeader color={theme.text3}> <MouseoverTooltip
<Trans>Network Fee</Trans> text={
</ThemedText.SubHeader> <Trans>
The fee paid to miners who process your transaction. This must be paid in {nativeCurrency.symbol}.
</Trans>
}
disableHover={hideInfoTooltips}
>
<ThemedText.SubHeader color={theme.text3}>
<Trans>Network Fee</Trans>
</ThemedText.SubHeader>
</MouseoverTooltip>
<TextWithLoadingPlaceholder syncing={syncing} width={50}> <TextWithLoadingPlaceholder syncing={syncing} width={50}>
<ThemedText.Black textAlign="right" fontSize={14} color={theme.text3}> <ThemedText.Black textAlign="right" fontSize={14} color={theme.text3}>
~${trade.gasUseEstimateUSD.toFixed(2)} ~${trade.gasUseEstimateUSD.toFixed(2)}
......
...@@ -147,7 +147,12 @@ export default function SwapDetailsDropdown({ ...@@ -147,7 +147,12 @@ export default function SwapDetailsDropdown({
content={ content={
<ResponsiveTooltipContainer origin="top right" style={{ padding: '0' }}> <ResponsiveTooltipContainer origin="top right" style={{ padding: '0' }}>
<Card padding="12px"> <Card padding="12px">
<AdvancedSwapDetails trade={trade} allowedSlippage={allowedSlippage} syncing={syncing} /> <AdvancedSwapDetails
trade={trade}
allowedSlippage={allowedSlippage}
syncing={syncing}
hideInfoTooltips={true}
/>
</Card> </Card>
</ResponsiveTooltipContainer> </ResponsiveTooltipContainer>
} }
......
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