diff --git a/README.md b/README.md index 959e9c5eae..9c850bf342 100644 --- a/README.md +++ b/README.md @@ -69,10 +69,10 @@ Other things to note: The Uniswap Interface supports swapping, adding liquidity, removing liquidity and migrating liquidity for Uniswap protocol V2. -- Swap on Uniswap V2: -- View V2 liquidity: -- Add V2 liquidity: -- Migrate V2 liquidity to V3: +- Swap on Uniswap V2: +- View V2 liquidity: +- Add V2 liquidity: +- Migrate V2 liquidity to V3: ## Accessing Uniswap V1 diff --git a/cypress/e2e/nfts.test.ts b/cypress/e2e/nfts.test.ts index 22b08a8b61..cd882b5e1f 100644 --- a/cypress/e2e/nfts.test.ts +++ b/cypress/e2e/nfts.test.ts @@ -12,7 +12,7 @@ describe('Testing nfts', () => { }) it('should load pudgy penguin collection page', () => { - cy.visit(`/#/nfts/collection/${PUDGY_COLLECTION_ADDRESS}`) + cy.visit(`/nfts/collection/${PUDGY_COLLECTION_ADDRESS}`) cy.get(getTestSelector('nft-collection-asset')).should('exist') cy.get(getTestSelector('nft-collection-filter-buy-now')).should('not.exist') cy.get(getTestSelector('nft-filter')).first().click() @@ -20,13 +20,13 @@ describe('Testing nfts', () => { }) it('should be able to navigate to activity', () => { - cy.visit(`/#/nfts/collection/${PUDGY_COLLECTION_ADDRESS}`) + cy.visit(`/nfts/collection/${PUDGY_COLLECTION_ADDRESS}`) cy.get(getTestSelector('nft-activity')).first().click() cy.get(getTestSelector('nft-activity-row')).should('exist') }) it('should go to the details page', () => { - cy.visit(`/#/nfts/collection/${PUDGY_COLLECTION_ADDRESS}`) + cy.visit(`/nfts/collection/${PUDGY_COLLECTION_ADDRESS}`) cy.get(getTestSelector('nft-filter')).first().click() cy.get(getTestSelector('nft-collection-filter-buy-now')).click() cy.get(getTestSelector('nft-collection-asset')).first().click() @@ -37,7 +37,7 @@ describe('Testing nfts', () => { }) it('should toggle buy now on details page', () => { - cy.visit(`/#/nfts/collection/${PUDGY_COLLECTION_ADDRESS}`) + cy.visit(`/nfts/collection/${PUDGY_COLLECTION_ADDRESS}`) cy.get(getTestSelector('nft-filter')).first().click() cy.get(getTestSelector('nft-collection-filter-buy-now')).click() cy.get(getTestSelector('nft-collection-asset')).first().click() diff --git a/cypress/e2e/token-explore.test.ts b/cypress/e2e/token-explore.test.ts index a418ac6b23..d41bd510c8 100644 --- a/cypress/e2e/token-explore.test.ts +++ b/cypress/e2e/token-explore.test.ts @@ -69,8 +69,5 @@ describe('Token explore', () => { cy.get(getTestSelector('tokens-network-filter-selected')).click() cy.get(getTestSelector('tokens-network-filter-option-optimism')).click() cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Optimism') - cy.reload() - cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Optimism') - cy.get(getTestSelector('chain-selector-logo')).invoke('attr', 'alt').should('eq', 'Ethereum') }) }) diff --git a/cypress/e2e/universal-search.test.ts b/cypress/e2e/universal-search.test.ts index f55de3378a..7a25cd262c 100644 --- a/cypress/e2e/universal-search.test.ts +++ b/cypress/e2e/universal-search.test.ts @@ -25,7 +25,7 @@ describe('Universal search bar', () => { .and('contain.text', '$') .and('contain.text', '%') .click() - cy.location('hash').should('equal', '#/tokens/ethereum/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984') + cy.location('pathname').should('equal', '/tokens/ethereum/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984') openSearch() cy.get(getTestSelector('searchbar-dropdown')) diff --git a/cypress/e2e/wallet-dropdown.test.ts b/cypress/e2e/wallet-dropdown.test.ts index 3709db9560..e0db6845fa 100644 --- a/cypress/e2e/wallet-dropdown.test.ts +++ b/cypress/e2e/wallet-dropdown.test.ts @@ -26,11 +26,11 @@ describe('Wallet Dropdown', () => { cy.contains('Uniswap available in: English').should('not.exist') cy.get(getTestSelector('wallet-language-item')).contains('Afrikaans').click({ force: true }) - cy.location('hash').should('match', /\?lng=af-ZA$/) + cy.location('search').should('match', /\?lng=af-ZA$/) cy.contains('Uniswap available in: English') cy.get(getTestSelector('wallet-language-item')).contains('English').click({ force: true }) - cy.location('hash').should('match', /\?lng=en-US$/) + cy.location('search').should('match', /\?lng=en-US$/) cy.contains('Uniswap available in: English').should('not.exist') }) } diff --git a/cypress/staging/t9n.test.ts b/cypress/staging/t9n.test.ts index 16dbc1da76..d59fd7ec7d 100644 --- a/cypress/staging/t9n.test.ts +++ b/cypress/staging/t9n.test.ts @@ -12,7 +12,7 @@ describe('translations', () => { cy.get(getTestSelector('web3-status-connected')).click() cy.get(getTestSelector('wallet-settings')).click() cy.get(getTestSelector('wallet-language-item')).contains('français').click({ force: true }) - cy.location('hash').should('match', /\?lng=fr-FR$/) + cy.location('search').should('match', /\?lng=fr-FR$/) cy.contains('Échanger') cy.contains('Uniswap disponible en : English') }) diff --git a/package.json b/package.json index 0731e02c18..6abe5be694 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "@uniswap/interface", "version": "1.1.0", "description": "Uniswap Interface", - "homepage": ".", "license": "GPL-3.0-or-later", "scripts": { "ajv": "node scripts/compile-ajv-validators.js", @@ -94,7 +93,6 @@ "@types/react": "^18.0.15", "@types/react-dom": "^18.0.6", "@types/react-redux": "^7.1.24", - "@types/react-router-dom": "^5.3.3", "@types/react-table": "^7.7.12", "@types/react-virtualized-auto-sizer": "^1.0.0", "@types/react-window": "^1.8.2", diff --git a/src/components/FiatOnrampModal/index.tsx b/src/components/FiatOnrampModal/index.tsx index 756420966e..fe7730c357 100644 --- a/src/components/FiatOnrampModal/index.tsx +++ b/src/components/FiatOnrampModal/index.tsx @@ -1,6 +1,7 @@ import { Trans } from '@lingui/macro' import { useWeb3React } from '@web3-react/core' import { useCallback, useEffect, useState } from 'react' +import { useHref } from 'react-router-dom' import { useCloseModal, useModalIsOpen } from 'state/application/hooks' import { ApplicationModal } from 'state/application/reducer' import styled, { useTheme } from 'styled-components/macro' @@ -79,6 +80,8 @@ export default function FiatOnrampModal() { const [error, setError] = useState(null) const [loading, setLoading] = useState(false) + const swapUrl = useHref('/swap') + const fetchSignedIframeUrl = useCallback(async () => { if (!account) { setError('Please connect an account before making a purchase.') @@ -98,7 +101,7 @@ export default function FiatOnrampModal() { theme: isDarkMode ? 'dark' : 'light', colorCode: theme.accentAction, defaultCurrencyCode: 'eth', - redirectUrl: 'https://app.uniswap.org/#/swap', + redirectUrl: swapUrl, walletAddresses: JSON.stringify( MOONPAY_SUPPORTED_CURRENCY_CODES.reduce( (acc, currencyCode) => ({ @@ -118,7 +121,7 @@ export default function FiatOnrampModal() { } finally { setLoading(false) } - }, [account, isDarkMode, theme.accentAction]) + }, [account, isDarkMode, swapUrl, theme.accentAction]) useEffect(() => { fetchSignedIframeUrl() diff --git a/src/components/Tokens/TokenTable/__snapshots__/TokenRow.test.tsx.snap b/src/components/Tokens/TokenTable/__snapshots__/TokenRow.test.tsx.snap index 0d96f015f7..b270d8a9f4 100644 --- a/src/components/Tokens/TokenTable/__snapshots__/TokenRow.test.tsx.snap +++ b/src/components/Tokens/TokenTable/__snapshots__/TokenRow.test.tsx.snap @@ -343,7 +343,7 @@ exports[`LoadedRow.tsx renders a row 1`] = ` >
- + @@ -70,7 +73,7 @@ createRoot(container).render( - + diff --git a/src/nft/components/card/containers.tsx b/src/nft/components/card/containers.tsx index ef2cf9e742..e972d8af00 100644 --- a/src/nft/components/card/containers.tsx +++ b/src/nft/components/card/containers.tsx @@ -95,7 +95,7 @@ const ActionButton = ({ (isDisabled ? undefined : clickActionButton(e))} + onClick={(e) => (isDisabled ? undefined : clickActionButton(e))} > {children} diff --git a/src/nft/components/collection/Activity.css.ts b/src/nft/components/collection/Activity.css.ts index 64d9161659..d405f380ef 100644 --- a/src/nft/components/collection/Activity.css.ts +++ b/src/nft/components/collection/Activity.css.ts @@ -38,6 +38,7 @@ export const eventRow = style([ borderBottomColor: 'backgroundOutline', }), { + textDecoration: 'none', height: '84px', ':hover': { background: themeVars.colors.backgroundSurface, diff --git a/src/nft/components/collection/Activity.tsx b/src/nft/components/collection/Activity.tsx index bf273de090..cadbfcb1d3 100644 --- a/src/nft/components/collection/Activity.tsx +++ b/src/nft/components/collection/Activity.tsx @@ -5,10 +5,11 @@ import { Box } from 'nft/components/Box' import { Column, Row } from 'nft/components/Flex' import { themeVars, vars } from 'nft/css/sprinkles.css' import { useBag, useIsMobile } from 'nft/hooks' -import { ActivityEvent, ActivityEventType } from 'nft/types' +import { ActivityEventType } from 'nft/types' import { fetchPrice } from 'nft/utils/fetchPrice' import { useCallback, useEffect, useReducer, useState } from 'react' import InfiniteScroll from 'react-infinite-scroll-component' +import { Link } from 'react-router-dom' import styled from 'styled-components/macro' import { useIsDarkMode } from 'theme/components/ThemeToggle' @@ -60,8 +61,6 @@ export const reduceFilters = (state: typeof initialFilterState, action: { eventT return { ...state, [action.eventType]: !state[action.eventType] } } -const baseHref = (event: ActivityEvent) => `/#/nfts/asset/${event.collectionAddress}/${event.tokenId}?origin=activity` - export const Activity = ({ contractAddress, rarityVerified, collectionName, chainId }: ActivityProps) => { const [activeFilters, filtersDispatch] = useReducer(reduceFilters, initialFilterState) @@ -138,9 +137,11 @@ export const Activity = ({ contractAddress, rarityVerified, collectionName, chai (event, i) => event.eventType && ( diff --git a/src/nft/components/collection/__snapshots__/CollectionAsset.test.tsx.snap b/src/nft/components/collection/__snapshots__/CollectionAsset.test.tsx.snap index e11eb9c62d..3ed44c8d12 100644 --- a/src/nft/components/collection/__snapshots__/CollectionAsset.test.tsx.snap +++ b/src/nft/components/collection/__snapshots__/CollectionAsset.test.tsx.snap @@ -309,7 +309,7 @@ exports[`NftCard renders correctly 1`] = ` >
( ) +const RedirectHashToPath = ({ children }: { children: JSX.Element }) => { + const { hash } = useLocation() + if (hash) { + return + } + return children +} + export default function App() { const isLoaded = useFeatureFlagsIsLoaded() const [shouldDisableNFTRoutes, setShouldDisableNFTRoutes] = useAtom(shouldDisableNFTRoutesAtom) @@ -209,7 +217,16 @@ export default function App() { }> {isLoaded ? ( - } /> + + + + } + /> }> diff --git a/src/pages/Landing/__snapshots__/index.test.tsx.snap b/src/pages/Landing/__snapshots__/index.test.tsx.snap index adc35e71b1..bc148518d5 100644 --- a/src/pages/Landing/__snapshots__/index.test.tsx.snap +++ b/src/pages/Landing/__snapshots__/index.test.tsx.snap @@ -1741,7 +1741,7 @@ exports[`disable nft on landing page does not render nft information and card 1` >

Swap Tokens Pools @@ -4315,7 +4315,7 @@ exports[`disable nft on landing page renders nft information and card 1`] = ` >

Swap Tokens NFTs Pools diff --git a/src/pages/Pool/PositionPage.tsx b/src/pages/Pool/PositionPage.tsx index 85309f9522..47bd7bc4d7 100644 --- a/src/pages/Pool/PositionPage.tsx +++ b/src/pages/Pool/PositionPage.tsx @@ -3,7 +3,7 @@ import type { TransactionResponse } from '@ethersproject/providers' import { Trans } from '@lingui/macro' import { InterfacePageName } from '@uniswap/analytics-events' import { formatPrice, NumberType } from '@uniswap/conedison/format' -import { ChainId, Currency, CurrencyAmount, Fraction, Percent, Price, Token } from '@uniswap/sdk-core' +import { Currency, CurrencyAmount, Fraction, Percent, Price, Token } from '@uniswap/sdk-core' import { NonfungiblePositionManager, Pool, Position } from '@uniswap/v3-sdk' import { useWeb3React } from '@web3-react/core' import { Trace } from 'analytics' @@ -30,12 +30,12 @@ import { useV3PositionFees } from 'hooks/useV3PositionFees' import { useV3PositionFromTokenId } from 'hooks/useV3Positions' import { useSingleCallResult } from 'lib/hooks/multicall' import useNativeCurrency from 'lib/hooks/useNativeCurrency' -import { useCallback, useMemo, useRef, useState } from 'react' +import { PropsWithChildren, useCallback, useMemo, useRef, useState } from 'react' import { Link, useParams } from 'react-router-dom' import { Bound } from 'state/mint/v3/actions' import { useIsTransactionPending, useTransactionAdder } from 'state/transactions/hooks' import styled, { useTheme } from 'styled-components/macro' -import { ExternalLink, HideExtraSmall, HideSmall, ThemedText } from 'theme' +import { ExternalLink, HideExtraSmall, HideSmall, StyledRouterLink, ThemedText } from 'theme' import { currencyId } from 'utils/currencyId' import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' import { formatTickPrice } from 'utils/formatTickPrice' @@ -52,15 +52,6 @@ import { calculateGasMargin } from '../../utils/calculateGasMargin' import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink' import { LoadingRows } from './styleds' -const getTokenLink = (chainId: ChainId, address: string) => { - if (isGqlSupportedChain(chainId)) { - const chainName = CHAIN_IDS_TO_NAMES[chainId] - return `${window.location.origin}/#/tokens/${chainName}/${address}` - } else { - return getExplorerLink(chainId, address, ExplorerDataType.TOKEN) - } -} - const PositionPageButtonPrimary = styled(ButtonPrimary)` width: 228px; height: 40px; @@ -210,17 +201,31 @@ function CurrentPriceCard({ ) } +const TokenLink = ({ + children, + chainId, + address, +}: PropsWithChildren<{ chainId: keyof typeof CHAIN_IDS_TO_NAMES; address: string }>) => { + const chainName = CHAIN_IDS_TO_NAMES[chainId] + return {children} +} + +const ExternalTokenLink = ({ children, chainId, address }: PropsWithChildren<{ chainId: number; address: string }>) => { + return {children} +} + function LinkedCurrency({ chainId, currency }: { chainId?: number; currency?: Currency }) { const address = (currency as Token)?.address if (typeof chainId === 'number' && address) { + const Link = isGqlSupportedChain(chainId) ? TokenLink : ExternalTokenLink return ( - + {currency?.symbol} ↗ - + ) } diff --git a/src/serviceWorker/document.test.ts b/src/serviceWorker/document.test.ts index 9d3f42e67b..49d7636589 100644 --- a/src/serviceWorker/document.test.ts +++ b/src/serviceWorker/document.test.ts @@ -17,15 +17,15 @@ describe('document', () => { [{ request: { mode: 'navigate' }, url: { hostname: 'example.com', pathname: '' } }, false], [{ request: {}, url: { hostname: 'app.uniswap.org', pathname: '' } }, false], [{ request: { mode: 'navigate' }, url: { hostname: 'app.uniswap.org', pathname: '' } }, true], - [{ request: { mode: 'navigate' }, url: { hostname: 'app.uniswap.org', pathname: '/#/swap' } }, true], + [{ request: { mode: 'navigate' }, url: { hostname: 'app.uniswap.org', pathname: '/swap' } }, true], [{ request: { mode: 'navigate' }, url: { hostname: 'app.uniswap.org', pathname: '/asset.gif' } }, false], [{ request: {}, url: { hostname: 'app.uniswap-staging.org', pathname: '' } }, false], [{ request: { mode: 'navigate' }, url: { hostname: 'app.uniswap-staging.org', pathname: '' } }, true], - [{ request: { mode: 'navigate' }, url: { hostname: 'app.uniswap-staging.org', pathname: '/#/swap' } }, true], + [{ request: { mode: 'navigate' }, url: { hostname: 'app.uniswap-staging.org', pathname: '/swap' } }, true], [{ request: { mode: 'navigate' }, url: { hostname: 'app.uniswap-staging.org', pathname: '/asset.gif' } }, false], [{ request: {}, url: { hostname: 'localhost', pathname: '' } }, false], [{ request: { mode: 'navigate' }, url: { hostname: 'localhost', pathname: '' } }, true], - [{ request: { mode: 'navigate' }, url: { hostname: 'localhost', pathname: '/#/swap' } }, true], + [{ request: { mode: 'navigate' }, url: { hostname: 'localhost', pathname: '/swap' } }, true], [{ request: { mode: 'navigate' }, url: { hostname: 'localhost', pathname: '/asset.gif' } }, false], ] as [RouteMatchCallbackOptions, boolean][] diff --git a/src/test-utils/render.tsx b/src/test-utils/render.tsx index dfa3265519..58feb5f976 100644 --- a/src/test-utils/render.tsx +++ b/src/test-utils/render.tsx @@ -10,7 +10,7 @@ import { en } from 'make-plural/plurals' import { ReactElement, ReactNode } from 'react' import { QueryClient, QueryClientProvider } from 'react-query' import { Provider } from 'react-redux' -import { HashRouter } from 'react-router-dom' +import { BrowserRouter } from 'react-router-dom' import store from 'state' import ThemeProvider from 'theme' @@ -30,7 +30,7 @@ const WithProviders = ({ children }: { children?: ReactNode }) => { - + {/* * Web3Provider is mocked through setupTests.ts * To test behavior that depends on Web3Provider, use jest.unmock('@web3-react/core') @@ -40,7 +40,7 @@ const WithProviders = ({ children }: { children?: ReactNode }) => { {children} - + diff --git a/src/tracing/trace.test.ts b/src/tracing/trace.test.ts index 2d6da02e4a..ffda5c5599 100644 --- a/src/tracing/trace.test.ts +++ b/src/tracing/trace.test.ts @@ -103,7 +103,7 @@ describe('trace', () => { const errorEvent: ErrorEvent = { type: undefined, request: { - url: 'https://app.uniswap.org/#/pools', + url: 'https://app.uniswap.org/pools', }, } const eventHint: EventHint = {} @@ -114,7 +114,7 @@ describe('trace', () => { const errorEvent: ErrorEvent = { type: undefined, request: { - url: 'https://app.uniswap.org/#', + url: 'https://app.uniswap.org/', }, } const eventHint: EventHint = {} diff --git a/src/utils/env.ts b/src/utils/env.ts index c982606692..7c1fc20c29 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -23,6 +23,25 @@ export function isAppUniswapStagingOrg({ hostname }: { hostname: string }): bool return hostname === 'app.uniswap-staging.org' } +export function isBrowserRouterEnabled(): boolean { + if (isProductionEnv()) { + if ( + isAppUniswapOrg(window.location) || + isAppUniswapStagingOrg(window.location) || + // Cypress tests + isLocalhost(window.location) + ) { + return true + } + return false + } + return true +} + +function isLocalhost({ hostname }: { hostname: string }): boolean { + return hostname === 'localhost' +} + export function isSentryEnabled(): boolean { // Disable in e2e test environments if (isStagingEnv() && !isAppUniswapStagingOrg(window.location)) return false diff --git a/yarn.lock b/yarn.lock index 0b3e736685..a2d9cf15c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5559,11 +5559,6 @@ dependencies: "@types/node" "*" -"@types/history@*", "@types/history@^4.7.11": - version "4.7.11" - resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" - integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== - "@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" @@ -5766,23 +5761,6 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-router-dom@^5.3.3": - version "5.3.3" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" - integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router" "*" - -"@types/react-router@*": - version "5.1.16" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.16.tgz#f3ba045fb96634e38b21531c482f9aeb37608a99" - integrity sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg== - dependencies: - "@types/history" "*" - "@types/react" "*" - "@types/react-table@^7.7.12": version "7.7.12" resolved "https://registry.yarnpkg.com/@types/react-table/-/react-table-7.7.12.tgz#628011d3cb695b07c678704a61f2f1d5b8e567fd"