diff --git a/src/components/AccountDetails/Copy.tsx b/src/components/AccountDetails/Copy.tsx index 5345283b4d..a1b7d814c9 100644 --- a/src/components/AccountDetails/Copy.tsx +++ b/src/components/AccountDetails/Copy.tsx @@ -2,10 +2,10 @@ import React from 'react' import styled from 'styled-components' import useCopyClipboard from '../../hooks/useCopyClipboard' -import { Link } from '../../theme' +import { LinkStyledButton } from '../../theme' import { CheckCircle, Copy } from 'react-feather' -const CopyIcon = styled(Link)` +const CopyIcon = styled(LinkStyledButton)` color: ${({ theme }) => theme.text4}; flex-shrink: 0; display: flex; diff --git a/src/components/AccountDetails/Transaction.tsx b/src/components/AccountDetails/Transaction.tsx index 2849fc663c..17c13eb0ce 100644 --- a/src/components/AccountDetails/Transaction.tsx +++ b/src/components/AccountDetails/Transaction.tsx @@ -4,7 +4,7 @@ import { Check, Triangle } from 'react-feather' import { useActiveWeb3React } from '../../hooks' import { getEtherscanLink } from '../../utils' -import { Link, Spinner } from '../../theme' +import { ExternalLink, Spinner } from '../../theme' import Circle from '../../assets/images/circle.svg' import { transparentize } from 'polished' @@ -18,7 +18,7 @@ const TransactionStatusText = styled.div` margin-right: 0.5rem; ` -const TransactionState = styled(Link)<{ pending: boolean; success?: boolean }>` +const TransactionState = styled(ExternalLink)<{ pending: boolean; success?: boolean }>` display: flex; justify-content: space-between; text-decoration: none !important; diff --git a/src/components/AccountDetails/index.tsx b/src/components/AccountDetails/index.tsx index 9f3d3f9e8b..6519d0bfbb 100644 --- a/src/components/AccountDetails/index.tsx +++ b/src/components/AccountDetails/index.tsx @@ -21,7 +21,7 @@ import Identicon from '../Identicon' import { ButtonEmpty } from '../Button' -import { Link, TYPE } from '../../theme' +import { ExternalLink, LinkStyledButton, TYPE } from '../../theme' const HeaderRow = styled.div` ${({ theme }) => theme.flexRowNoWrap}; @@ -160,7 +160,7 @@ const ConnectButtonRow = styled.div` margin: 10px 0; ` -const StyledLink = styled(Link)<{ hasENS: boolean; isENS: boolean }>` +const AddressLink = styled(ExternalLink)<{ hasENS: boolean; isENS: boolean }>` color: ${({ hasENS, isENS, theme }) => (hasENS ? (isENS ? theme.primary1 : theme.text3) : theme.primary1)}; ` @@ -357,17 +357,21 @@ export default function AccountDetails({ {ENSName ? ( <> - + View on Etherscan ↗ - + ) : ( <> - + View on Etherscan ↗ - + )} @@ -395,7 +399,7 @@ export default function AccountDetails({ Recent Transactions - (clear all) + (clear all) {renderTransactions(pendingTransactions)} {renderTransactions(confirmedTransactions)} diff --git a/src/components/AddressInputPanel/index.tsx b/src/components/AddressInputPanel/index.tsx index 0b6fd3e5a5..f5132d637e 100644 --- a/src/components/AddressInputPanel/index.tsx +++ b/src/components/AddressInputPanel/index.tsx @@ -4,7 +4,7 @@ import useDebounce from '../../hooks/useDebounce' import { isAddress } from '../../utils' import { useActiveWeb3React } from '../../hooks' -import { Link, TYPE } from '../../theme' +import { ExternalLink, TYPE } from '../../theme' import { AutoColumn } from '../Column' import { RowBetween } from '../Row' import { getEtherscanLink } from '../../utils' @@ -160,12 +160,12 @@ export default function AddressInputPanel({ Recipient {data.address && ( - (View on Etherscan) - + )} { +interface ConfirmationModalProps { isOpen: boolean onDismiss: () => void hash: string @@ -44,8 +42,7 @@ interface ConfirmationModalProps extends RouteComponentProps<{}> { title?: string } -function ConfirmationModal({ - history, +export default function ConfirmationModal({ isOpen, onDismiss, hash, @@ -59,13 +56,6 @@ function ConfirmationModal({ const { chainId } = useActiveWeb3React() const theme = useContext(ThemeContext) - const dismissAndReturn = useCallback(() => { - if (history.location.pathname.match('/add') || history.location.pathname.match('/remove')) { - history.push('/pool') - } - onDismiss() - }, [onDismiss, history]) - return ( {!attemptingTxn ? ( @@ -106,12 +96,12 @@ function ConfirmationModal({ {!pendingConfirmation && ( <> - + View on Etherscan - - + + Close @@ -131,5 +121,3 @@ function ConfirmationModal({ ) } - -export default withRouter(ConfirmationModal) diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx index 0b02259796..85b3b1eaf7 100644 --- a/src/components/Header/index.tsx +++ b/src/components/Header/index.tsx @@ -8,7 +8,7 @@ import Row from '../Row' import Menu from '../Menu' import Web3Status from '../Web3Status' -import { Link } from '../../theme' +import { ExternalLink } from '../../theme' import { Text } from 'rebass' import { WETH, ChainId } from '@uniswap/sdk' import { isMobile } from 'react-device-detect' @@ -159,13 +159,13 @@ export default function Header() { Uniswap V2 is live! Read the  - + blog post ↗ - +  or  - + migrate your liquidity ↗ - + . diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx index e2ce3dcf7b..ee3cdd1618 100644 --- a/src/components/Menu/index.tsx +++ b/src/components/Menu/index.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components' import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg' import useToggle from '../../hooks/useToggle' -import { Link } from '../../theme' +import { ExternalLink } from '../../theme' const StyledMenuIcon = styled(MenuIcon)` path { @@ -63,7 +63,7 @@ const MenuFlyout = styled.span` z-index: 100; ` -const MenuItem = styled(Link)` +const MenuItem = styled(ExternalLink)` flex: 1; padding: 0.5rem 0.5rem; color: ${({ theme }) => theme.text2}; diff --git a/src/components/Popups/index.tsx b/src/components/Popups/index.tsx index 968332d00a..1a6b59a7af 100644 --- a/src/components/Popups/index.tsx +++ b/src/components/Popups/index.tsx @@ -1,11 +1,12 @@ -import React, { useContext } from 'react' +import { ChainId, Pair, Token } from '@uniswap/sdk' +import React, { useContext, useMemo } from 'react' import styled, { ThemeContext } from 'styled-components' import { useMediaLayout } from 'use-media' import { X } from 'react-feather' import { PopupContent } from '../../state/application/actions' import { useActivePopups, useRemovePopup } from '../../state/application/hooks' -import { Link } from '../../theme' +import { ExternalLink } from '../../theme' import { AutoColumn } from '../Column' import DoubleTokenLogo from '../DoubleLogo' import Row from '../Row' @@ -71,6 +72,40 @@ const Popup = styled.div` `} ` +function PoolPopup({ + token0, + token1 +}: { + token0: { address?: string; symbol?: string } + token1: { address?: string; symbol?: string } +}) { + const pairAddress: string | null = useMemo(() => { + if (!token0 || !token1) return null + // just mock it out + return Pair.getAddress( + new Token(ChainId.MAINNET, token0.address, 18), + new Token(ChainId.MAINNET, token1.address, 18) + ) + }, [token0, token1]) + + return ( + + + Pool Imported + + + + + UNI {token0?.symbol} / {token1?.symbol} + + + {pairAddress ? ( + View on Uniswap Info. + ) : null} + + ) +} + function PopupItem({ content, popKey }: { content: PopupContent; popKey: string }) { if ('txn' in content) { const { @@ -81,20 +116,8 @@ function PopupItem({ content, popKey }: { content: PopupContent; popKey: string const { poolAdded: { token0, token1 } } = content - return ( - - - Pool Imported - - - - - UNI {token0?.symbol} / {token1?.symbol} - - - View on Uniswap Info. - - ) + + return } } diff --git a/src/components/PositionCard/index.tsx b/src/components/PositionCard/index.tsx index 8a00dc0975..c5b19ee216 100644 --- a/src/components/PositionCard/index.tsx +++ b/src/components/PositionCard/index.tsx @@ -12,7 +12,7 @@ import Card, { GreyCard } from '../Card' import TokenLogo from '../TokenLogo' import DoubleLogo from '../DoubleLogo' import { Text } from 'rebass' -import { Link } from '../../theme/components' +import { ExternalLink } from '../../theme/components' import { AutoColumn } from '../Column' import { ChevronDown, ChevronUp } from 'react-feather' import { ButtonSecondary } from '../Button' @@ -204,7 +204,9 @@ function PositionCard({ pair, history, border, minimal = false }: PositionCardPr )} - View pool information ↗ + + View pool information ↗ + - (Remove) + (Remove) )} diff --git a/src/components/SearchModal/index.tsx b/src/components/SearchModal/index.tsx index 437617d3d4..97f678cb00 100644 --- a/src/components/SearchModal/index.tsx +++ b/src/components/SearchModal/index.tsx @@ -10,7 +10,7 @@ import { useActiveWeb3React } from '../../hooks' import { useAllTokens, useTokenByAddressAndAutomaticallyAdd } from '../../hooks/Tokens' import { useAllDummyPairs, useRemoveUserAddedToken } from '../../state/user/hooks' import { useAllTokenBalancesTreatingWETHasETH, useTokenBalances } from '../../state/wallet/hooks' -import { CloseIcon, Link as StyledLink } from '../../theme/components' +import { CloseIcon, LinkStyledButton, StyledInternalLink } from '../../theme/components' import { isAddress } from '../../utils' import Column from '../Column' import Modal from '../Modal' @@ -207,18 +207,12 @@ function SearchModal({
{isTokenView ? ( - Having trouble finding a token? + Having trouble finding a token? ) : ( {!isMobile && "Don't see a pool? "} - { - history.push('/find') - }} - > - {!isMobile ? 'Import it.' : 'Import pool.'} - + {!isMobile ? 'Import it.' : 'Import pool.'} )}
diff --git a/src/components/TokenWarningCard/index.tsx b/src/components/TokenWarningCard/index.tsx index fd14e26207..fff7e9918d 100644 --- a/src/components/TokenWarningCard/index.tsx +++ b/src/components/TokenWarningCard/index.tsx @@ -8,7 +8,7 @@ import { useActiveWeb3React } from '../../hooks' import { useAllTokens } from '../../hooks/Tokens' import { Field } from '../../state/swap/actions' import { useTokenWarningDismissal } from '../../state/user/hooks' -import { Link, TYPE } from '../../theme' +import { ExternalLink, TYPE } from '../../theme' import { getEtherscanLink } from '../../utils' import PropsOfExcluding from '../../utils/props-of-excluding' import QuestionHelper from '../QuestionHelper' @@ -111,9 +111,9 @@ export default function TokenWarningCard({ token, ...rest }: TokenWarningCardPro ? `${token.name} (${token.symbol})` : token.name || token.symbol} - + (View on Etherscan) - + Verify this is the correct token before making any transactions. diff --git a/src/components/TxnPopup/index.tsx b/src/components/TxnPopup/index.tsx index b2785e5792..0656ee33fd 100644 --- a/src/components/TxnPopup/index.tsx +++ b/src/components/TxnPopup/index.tsx @@ -8,7 +8,7 @@ import useInterval from '../../hooks/useInterval' import { useRemovePopup } from '../../state/application/hooks' import { TYPE } from '../../theme' -import { Link } from '../../theme/components' +import { ExternalLink } from '../../theme/components' import { getEtherscanLink } from '../../utils' import { AutoColumn } from '../Column' import { AutoRow } from '../Row' @@ -62,7 +62,7 @@ export default function TxnPopup({ {summary ? summary : 'Hash: ' + hash.slice(0, 8) + '...' + hash.slice(58, 65)} - View on Etherscan + View on Etherscan diff --git a/src/components/WalletModal/Option.tsx b/src/components/WalletModal/Option.tsx index 1263fa0c45..a01cec336f 100644 --- a/src/components/WalletModal/Option.tsx +++ b/src/components/WalletModal/Option.tsx @@ -1,6 +1,6 @@ import React from 'react' import styled from 'styled-components' -import { Link } from '../../theme' +import { ExternalLink } from '../../theme' const InfoCard = styled.button<{ active?: boolean }>` background-color: ${({ theme, active }) => (active ? theme.bg3 : theme.bg2)}; @@ -134,7 +134,7 @@ export default function Option({ ) if (link) { - return {content} + return {content} } return content diff --git a/src/components/WalletModal/index.tsx b/src/components/WalletModal/index.tsx index f7ef81828d..37d4bbc5df 100644 --- a/src/components/WalletModal/index.tsx +++ b/src/components/WalletModal/index.tsx @@ -12,7 +12,7 @@ import AccountDetails from '../AccountDetails' import PendingView from './PendingView' import Option from './Option' import { SUPPORTED_WALLETS } from '../../constants' -import { Link } from '../../theme' +import { ExternalLink } from '../../theme' import MetamaskIcon from '../../assets/images/metamask.png' import { ReactComponent as Close } from '../../assets/images/x.svg' import { injected, walletconnect, fortmatic, portis } from '../../connectors' @@ -358,9 +358,9 @@ export default function WalletModal({ {walletView !== WALLET_VIEWS.PENDING && ( New to Ethereum?  {' '} - + Learn more about wallets - + )} diff --git a/src/components/swap/TransferModalHeader.tsx b/src/components/swap/TransferModalHeader.tsx index 05922e0c84..7d701531d3 100644 --- a/src/components/swap/TransferModalHeader.tsx +++ b/src/components/swap/TransferModalHeader.tsx @@ -2,7 +2,7 @@ import { TokenAmount } from '@uniswap/sdk' import React from 'react' import { Text } from 'rebass' import { useActiveWeb3React } from '../../hooks' -import { Link, TYPE } from '../../theme' +import { ExternalLink, TYPE } from '../../theme' import { getEtherscanLink } from '../../utils' import Copy from '../AccountDetails/Copy' import { AutoColumn } from '../Column' @@ -32,21 +32,21 @@ export function TransferModalHeader({ {ENSName} - + {recipient?.slice(0, 8)}...{recipient?.slice(34, 42)}↗ - + ) : ( - + {recipient?.slice(0, 6)}...{recipient?.slice(36, 42)}↗ - + )} diff --git a/src/components/swap/V1TradeLink.tsx b/src/components/swap/V1TradeLink.tsx index d3fdb8cabd..4a65d584e4 100644 --- a/src/components/swap/V1TradeLink.tsx +++ b/src/components/swap/V1TradeLink.tsx @@ -2,7 +2,7 @@ import React, { useContext } from 'react' import { Text } from 'rebass' import { ThemeContext } from 'styled-components' -import { Link } from '../../theme' +import { ExternalLink } from '../../theme' import { YellowCard } from '../Card' import { AutoColumn } from '../Column' @@ -12,10 +12,10 @@ export default function V1TradeLink({ v1TradeLinkIfBetter }: { v1TradeLinkIfBett - There is a better price for this trade on - - Uniswap V1 ↗ - + There is a better price for this trade on{' '} + + Uniswap V1 ↗ + diff --git a/src/pages/AddLiquidity/index.tsx b/src/pages/AddLiquidity/index.tsx index 0b4df13a0f..a84f219a90 100644 --- a/src/pages/AddLiquidity/index.tsx +++ b/src/pages/AddLiquidity/index.tsx @@ -36,7 +36,7 @@ import { useApproveCallback, ApprovalState } from '../../hooks/useApproveCallbac import { useWalletModalToggle } from '../../state/application/hooks' import AdvancedSwapDetailsDropdown from '../../components/swap/AdvancedSwapDetailsDropdown' -export default function AddLiquidity({ match: { params } }: RouteComponentProps<{ tokens: string }>) { +export default function AddLiquidity({ match: { params }, history }: RouteComponentProps<{ tokens: string }>) { useDefaultsFromURLMatchParams(params) const { account, chainId, library } = useActiveWeb3React() @@ -311,6 +311,10 @@ export default function AddLiquidity({ match: { params } }: RouteComponentProps< { + if (attemptingTxn) { + history.push('/pool') + return + } setPendingConfirmation(true) setAttemptingTxn(false) setShowConfirm(false) diff --git a/src/pages/CreatePool/index.tsx b/src/pages/CreatePool/index.tsx index 72bde9d488..011067fe6c 100644 --- a/src/pages/CreatePool/index.tsx +++ b/src/pages/CreatePool/index.tsx @@ -8,7 +8,7 @@ import TokenLogo from '../../components/TokenLogo' import SearchModal from '../../components/SearchModal' import { Text } from 'rebass' import { Plus } from 'react-feather' -import { TYPE, Link } from '../../theme' +import { TYPE, StyledInternalLink } from '../../theme' import { AutoColumn, ColumnCenter } from '../../components/Column' import { ButtonPrimary, ButtonDropwdown, ButtonDropwdownLight } from '../../components/Button' @@ -27,7 +27,7 @@ enum STEP { SHOW_CREATE_PAGE = 'SHOW_CREATE_PAGE' // show create page } -export default function CreatePool({ history, location }: RouteComponentProps) { +export default function CreatePool({ location }: RouteComponentProps) { const { chainId } = useActiveWeb3React() const [showSearch, setShowSearch] = useState(false) const [activeField, setActiveField] = useState(Fields.TOKEN0) @@ -116,8 +116,8 @@ export default function CreatePool({ history, location }: RouteComponentProps) { {pair ? ( // pair already exists - prompt to add liquidity to existing pool - Pool already exists! - history.push('/add/' + token0Address + '-' + token1Address)}> Join the pool. + Pool already exists!{' '} + Join the pool. ) : ( diff --git a/src/pages/Pool/index.tsx b/src/pages/Pool/index.tsx index cfa41729ec..1b2bcaa702 100644 --- a/src/pages/Pool/index.tsx +++ b/src/pages/Pool/index.tsx @@ -8,7 +8,7 @@ import SearchModal from '../../components/SearchModal' import PositionCard from '../../components/PositionCard' import { useUserProbablyHasV1Liquidity } from '../../data/V1' import { useTokenBalances } from '../../state/wallet/hooks' -import { Link, TYPE } from '../../theme' +import { LinkStyledButton, StyledInternalLink, TYPE } from '../../theme' import { Text } from 'rebass' import { LightCard } from '../../components/Card' import { RowBetween } from '../../components/Row' @@ -98,19 +98,12 @@ export default function Pool({ history }: RouteComponentProps) { {!hasV1Liquidity ? ( <> {filteredExchangeList?.length !== 0 ? `Don't see a pool you joined? ` : 'Already joined a pool? '}{' '} - { - history.push('/find') - }} - > + Import it. - + ) : ( - - Migrate your V1 liquidity. - + Migrate your V1 liquidity. )} diff --git a/src/pages/PoolFinder/index.tsx b/src/pages/PoolFinder/index.tsx index 394a98f180..83c49bf323 100644 --- a/src/pages/PoolFinder/index.tsx +++ b/src/pages/PoolFinder/index.tsx @@ -15,7 +15,7 @@ import { useActiveWeb3React } from '../../hooks' import { useToken } from '../../hooks/Tokens' import { usePairAdder } from '../../state/user/hooks' import { useTokenBalanceTreatingWETHasETH } from '../../state/wallet/hooks' -import { Link } from '../../theme' +import { StyledInternalLink } from '../../theme' import AppBody from '../AppBody' enum Fields { @@ -119,13 +119,9 @@ export default function PoolFinder({ history }: RouteComponentProps) { Pool found, you don’t have liquidity on this pair yet. - { - history.push('/add/' + token0Address + '-' + token1Address) - }} - > + Add liquidity to this pair instead. - + ) @@ -133,13 +129,7 @@ export default function PoolFinder({ history }: RouteComponentProps) { No pool found. - { - history.push('/add/' + token0Address + '-' + token1Address) - }} - > - Create pool? - + Create pool? ) : ( diff --git a/src/pages/RemoveLiquidity/index.tsx b/src/pages/RemoveLiquidity/index.tsx index b1bb4f80f8..f809dc3f75 100644 --- a/src/pages/RemoveLiquidity/index.tsx +++ b/src/pages/RemoveLiquidity/index.tsx @@ -35,7 +35,7 @@ import AdvancedSwapDetailsDropdown from '../../components/swap/AdvancedSwapDetai import { Field } from '../../state/burn/actions' import { useWalletModalToggle } from '../../state/application/hooks' -export default function RemoveLiquidity({ match: { params } }: RouteComponentProps<{ tokens: string }>) { +export default function RemoveLiquidity({ match: { params }, history }: RouteComponentProps<{ tokens: string }>) { useDefaultsFromURLMatchParams(params) const { account, chainId, library } = useActiveWeb3React() @@ -398,6 +398,10 @@ export default function RemoveLiquidity({ match: { params } }: RouteComponentPro { + if (attemptingTxn) { + history.push('/pool') + return + } resetModalState() setShowConfirm(false) setShowAdvanced(false) diff --git a/src/theme/components.tsx b/src/theme/components.tsx index ef92e536b1..bc34bcffab 100644 --- a/src/theme/components.tsx +++ b/src/theme/components.tsx @@ -1,5 +1,6 @@ import React, { HTMLProps, useCallback } from 'react' import ReactGA from 'react-ga' +import { Link } from 'react-router-dom' import styled, { keyframes } from 'styled-components' import { darken } from 'polished' import { X } from 'react-feather' @@ -38,6 +39,51 @@ export const CloseIcon = styled(X)<{ onClick: () => void }>` cursor: pointer; ` +// A button that triggers some onClick result, but looks like a link. +export const LinkStyledButton = styled.button` + border: none; + text-decoration: none; + background: none; + + cursor: pointer; + color: ${({ theme }) => theme.primary1}; + font-weight: 500; + + :hover { + text-decoration: underline; + } + + :focus { + outline: none; + text-decoration: underline; + } + + :active { + text-decoration: none; + } +` + +// An internal link from the react-router-dom library that is correctly styled +export const StyledInternalLink = styled(Link)` + text-decoration: none; + cursor: pointer; + color: ${({ theme }) => theme.primary1}; + font-weight: 500; + + :hover { + text-decoration: underline; + } + + :focus { + outline: none; + text-decoration: underline; + } + + :active { + text-decoration: none; + } +` + const StyledLink = styled.a` text-decoration: none; cursor: pointer; @@ -58,20 +104,19 @@ const StyledLink = styled.a` } ` -export function Link({ - onClick, +/** + * Outbound link that handles firing google analytics events + */ +export function ExternalLink({ target = '_blank', href, rel = 'noopener noreferrer', ...rest -}: Omit, 'as' | 'ref'>) { +}: Omit, 'as' | 'ref' | 'onClick'> & { href: string }) { const handleClick = useCallback( (event: React.MouseEvent) => { - onClick && onClick(event) // first call back into the original onClick - if (!href) return - - // don't prevent default, don't redirect - if (target === '_blank') { + // don't prevent default, don't redirect if it's a new tab + if (target === '_blank' || event.ctrlKey || event.metaKey) { ReactGA.outboundLink({ label: href }, () => { console.debug('Fired outbound link event', href) }) @@ -83,7 +128,7 @@ export function Link({ }) } }, - [href, onClick, target] + [href, target] ) return }