Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9ccbdc5e2 | ||
|
|
e36b72eb82 | ||
|
|
b173d00dae | ||
|
|
c3b02d7c8d | ||
|
|
bff177d3f1 |
1
CODEOWNERS
Normal file
1
CODEOWNERS
Normal file
@ -0,0 +1 @@
|
||||
* @uniswap/web-admins
|
||||
@ -39,4 +39,30 @@ describe('Landing Page', () => {
|
||||
cy.get(getTestSelector('pool-nav-link')).last().click()
|
||||
cy.url().should('include', '/pools')
|
||||
})
|
||||
|
||||
it('does not render uk compliance banner in US', () => {
|
||||
cy.visit('/swap')
|
||||
cy.contains('UK disclaimer').should('not.exist')
|
||||
})
|
||||
|
||||
it('renders uk compliance banner in uk', () => {
|
||||
cy.intercept('https://api.uniswap.org/v1/amplitude-proxy', (req) => {
|
||||
const requestBody = JSON.stringify(req.body)
|
||||
const byteSize = new Blob([requestBody]).size
|
||||
req.alias = 'amplitude'
|
||||
req.reply(
|
||||
JSON.stringify({
|
||||
code: 200,
|
||||
server_upload_time: Date.now(),
|
||||
payload_size_bytes: byteSize,
|
||||
events_ingested: req.body.events.length,
|
||||
}),
|
||||
{
|
||||
'origin-country': 'GB',
|
||||
}
|
||||
)
|
||||
})
|
||||
cy.visit('/swap')
|
||||
cy.contains('UK disclaimer')
|
||||
})
|
||||
})
|
||||
|
||||
@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ request, next }) => {
|
||||
}
|
||||
const res = next()
|
||||
try {
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(data)).transform(await res)
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(data, request)).transform(await res)
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@ -6,12 +6,15 @@ test('should append meta tag to element', () => {
|
||||
} as unknown as Element
|
||||
const property = 'property'
|
||||
const content = 'content'
|
||||
const injector = new MetaTagInjector({
|
||||
title: 'test',
|
||||
url: 'testUrl',
|
||||
image: 'testImage',
|
||||
description: 'testDescription',
|
||||
})
|
||||
const injector = new MetaTagInjector(
|
||||
{
|
||||
title: 'test',
|
||||
url: 'testUrl',
|
||||
image: 'testImage',
|
||||
description: 'testDescription',
|
||||
},
|
||||
new Request('http://localhost')
|
||||
)
|
||||
injector.append(element, property, content)
|
||||
expect(element.append).toHaveBeenCalledWith(`<meta property="${property}" content="${content}"/>`, { html: true })
|
||||
|
||||
@ -36,3 +39,22 @@ test('should append meta tag to element', () => {
|
||||
|
||||
expect(element.append).toHaveBeenCalledTimes(13)
|
||||
})
|
||||
|
||||
test('should pass through header blocked paths', () => {
|
||||
const element = {
|
||||
append: jest.fn(),
|
||||
} as unknown as Element
|
||||
const request = new Request('http://localhost')
|
||||
request.headers.set('x-blocked-paths', '/')
|
||||
const injector = new MetaTagInjector(
|
||||
{
|
||||
title: 'test',
|
||||
url: 'testUrl',
|
||||
image: 'testImage',
|
||||
description: 'testDescription',
|
||||
},
|
||||
request
|
||||
)
|
||||
injector.element(element)
|
||||
expect(element.append).toHaveBeenCalledWith(`<meta property="x:blocked-paths" content="/"/>`, { html: true })
|
||||
})
|
||||
|
||||
@ -10,7 +10,7 @@ type MetaTagInjectorInput = {
|
||||
* to inject meta tags into the <head> of an HTML document.
|
||||
*/
|
||||
export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
||||
constructor(private input: MetaTagInjectorInput) {}
|
||||
constructor(private input: MetaTagInjectorInput, private request: Request) {}
|
||||
|
||||
append(element: Element, property: string, content: string) {
|
||||
element.append(`<meta property="${property}" content="${content}"/>`, { html: true })
|
||||
@ -38,5 +38,10 @@ export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
||||
this.append(element, 'twitter:image', this.input.image)
|
||||
this.append(element, 'twitter:image:alt', this.input.title)
|
||||
}
|
||||
|
||||
const blockedPaths = this.request.headers.get('x-blocked-paths')
|
||||
if (blockedPaths) {
|
||||
this.append(element, 'x:blocked-paths', blockedPaths)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
const { index } = params
|
||||
const collectionAddress = index[0]?.toString()
|
||||
const tokenId = index[1]?.toString()
|
||||
return getMetadataRequest(res, request.url, () => getAsset(collectionAddress, tokenId, request.url))
|
||||
return getMetadataRequest(res, request, () => getAsset(collectionAddress, tokenId, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
try {
|
||||
const { index } = params
|
||||
const collectionAddress = index?.toString()
|
||||
return getMetadataRequest(res, request.url, () => getCollection(collectionAddress, request.url))
|
||||
return getMetadataRequest(res, request, () => getCollection(collectionAddress, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
if (!tokenAddress) {
|
||||
return res
|
||||
}
|
||||
return getMetadataRequest(res, request.url, () => getToken(networkName, tokenAddress, request.url))
|
||||
return getMetadataRequest(res, request, () => getToken(networkName, tokenAddress, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@ -4,13 +4,13 @@ import { Data } from './cache'
|
||||
|
||||
export async function getMetadataRequest(
|
||||
res: Promise<Response>,
|
||||
url: string,
|
||||
request: Request,
|
||||
getData: () => Promise<Data | undefined>
|
||||
) {
|
||||
try {
|
||||
const cachedData = await getRequest(url, getData, (data): data is Data => true)
|
||||
const cachedData = await getRequest(request.url, getData, (data): data is Data => true)
|
||||
if (cachedData) {
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData)).transform(await res)
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData, request)).transform(await res)
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
|
||||
82
src/components/NavBar/UkBanner.tsx
Normal file
82
src/components/NavBar/UkBanner.tsx
Normal file
@ -0,0 +1,82 @@
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { useOpenModal } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import styled from 'styled-components'
|
||||
import { ButtonText, ThemedText } from 'theme/components'
|
||||
import { Z_INDEX } from 'theme/zIndex'
|
||||
|
||||
export const UK_BANNER_HEIGHT = 64
|
||||
export const UK_BANNER_HEIGHT_MD = 112
|
||||
export const UK_BANNER_HEIGHT_SM = 136
|
||||
|
||||
const BannerWrapper = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
background-color: ${({ theme }) => theme.surface1};
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid ${({ theme }) => theme.surface3};
|
||||
z-index: ${Z_INDEX.fixed};
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
|
||||
flex-direction: column;
|
||||
}
|
||||
`
|
||||
|
||||
const BannerTextWrapper = styled(ThemedText.BodySecondary)`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
|
||||
@supports (-webkit-line-clamp: 2) {
|
||||
white-space: initial;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
|
||||
@supports (-webkit-line-clamp: 3) {
|
||||
white-space: initial;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const ReadMoreWrapper = styled(ButtonText)`
|
||||
flex-shrink: 0;
|
||||
width: max-content;
|
||||
|
||||
:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
`
|
||||
|
||||
export const bannerText = t`
|
||||
This web application is provided as a tool for users to interact with the Uniswap Protocol on
|
||||
their own initiative, with no endorsement or recommendation of cryptocurrency trading activities. In doing so,
|
||||
Uniswap is not recommending that users or potential users engage in cryptoasset trading activity, and users or
|
||||
potential users of the web application should not regard this webpage or its contents as involving any form of
|
||||
recommendation, invitation or inducement to deal in cryptoassets.
|
||||
`
|
||||
|
||||
export function UkBanner() {
|
||||
const openDisclaimer = useOpenModal(ApplicationModal.UK_DISCLAIMER)
|
||||
|
||||
return (
|
||||
<BannerWrapper>
|
||||
<BannerTextWrapper lineHeight="24px">{t`UK disclaimer:` + ' ' + bannerText}</BannerTextWrapper>
|
||||
<ReadMoreWrapper>
|
||||
<ThemedText.BodySecondary lineHeight="24px" color="accent1" onClick={openDisclaimer}>
|
||||
<Trans>Read more</Trans>
|
||||
</ThemedText.BodySecondary>
|
||||
</ReadMoreWrapper>
|
||||
</BannerWrapper>
|
||||
)
|
||||
}
|
||||
62
src/components/NavBar/UkDisclaimerModal.tsx
Normal file
62
src/components/NavBar/UkDisclaimerModal.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button'
|
||||
import Column from 'components/Column'
|
||||
import Modal from 'components/Modal'
|
||||
import { X } from 'react-feather'
|
||||
import { useCloseModal, useModalIsOpen } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import styled from 'styled-components'
|
||||
import { ButtonText, ThemedText } from 'theme/components'
|
||||
|
||||
import { bannerText } from './UkBanner'
|
||||
|
||||
const Wrapper = styled(Column)`
|
||||
padding: 8px;
|
||||
`
|
||||
|
||||
const ButtonContainer = styled(Column)`
|
||||
padding: 8px 12px 4px;
|
||||
`
|
||||
|
||||
const CloseIconWrapper = styled(ButtonText)`
|
||||
display: flex;
|
||||
color: ${({ theme }) => theme.neutral1};
|
||||
justify-content: flex-end;
|
||||
padding: 8px 0px 4px;
|
||||
|
||||
:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
`
|
||||
|
||||
const StyledThemeButton = styled(ThemeButton)`
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
export function UkDisclaimerModal() {
|
||||
const isOpen = useModalIsOpen(ApplicationModal.UK_DISCLAIMER)
|
||||
const closeModal = useCloseModal()
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onDismiss={closeModal}>
|
||||
<Wrapper gap="md">
|
||||
<CloseIconWrapper onClick={() => closeModal()}>
|
||||
<X size={24} />
|
||||
</CloseIconWrapper>
|
||||
<Column gap="sm">
|
||||
<ThemedText.HeadlineLarge padding="0px 8px" fontSize="24px" lineHeight="32px">
|
||||
<Trans>Disclaimer for UK residents</Trans>
|
||||
</ThemedText.HeadlineLarge>
|
||||
<ThemedText.BodyPrimary padding="8px 8px 12px" lineHeight="24px">
|
||||
{bannerText}
|
||||
</ThemedText.BodyPrimary>
|
||||
</Column>
|
||||
<ButtonContainer gap="md">
|
||||
<StyledThemeButton size={ButtonSize.large} emphasis={ButtonEmphasis.medium} onClick={() => closeModal()}>
|
||||
<Trans>Dismiss</Trans>
|
||||
</StyledThemeButton>
|
||||
</ButtonContainer>
|
||||
</Wrapper>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
@ -6,6 +6,7 @@ import BaseAnnouncementBanner from 'components/Banner/BaseAnnouncementBanner'
|
||||
import AddressClaimModal from 'components/claim/AddressClaimModal'
|
||||
import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
|
||||
import FiatOnrampModal from 'components/FiatOnrampModal'
|
||||
import { UkDisclaimerModal } from 'components/NavBar/UkDisclaimerModal'
|
||||
import useAccountRiskCheck from 'hooks/useAccountRiskCheck'
|
||||
import Bag from 'nft/components/bag/Bag'
|
||||
import TransactionCompleteModal from 'nft/components/collection/TransactionCompleteModal'
|
||||
@ -31,6 +32,7 @@ export default function TopLevelModals() {
|
||||
<TransactionCompleteModal />
|
||||
<AirdropModal />
|
||||
<FiatOnrampModal />
|
||||
<UkDisclaimerModal />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ export function useUniswapXSwapCallback({
|
||||
const { domain, types, values } = updatedOrder.permitData()
|
||||
|
||||
const signature = await signTypedData(provider.getSigner(account), domain, types, values)
|
||||
if (startTime < Math.floor(Date.now() / 1000)) {
|
||||
if (deadline < Math.floor(Date.now() / 1000)) {
|
||||
throw new SignatureExpiredError()
|
||||
}
|
||||
return { signature, updatedOrder }
|
||||
|
||||
3678
src/locales/af-ZA.po
Normal file
3678
src/locales/af-ZA.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/ar-SA.po
Normal file
3678
src/locales/ar-SA.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/ca-ES.po
Normal file
3678
src/locales/ca-ES.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/cs-CZ.po
Normal file
3678
src/locales/cs-CZ.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/da-DK.po
Normal file
3678
src/locales/da-DK.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/de-DE.po
Normal file
3678
src/locales/de-DE.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/el-GR.po
Normal file
3678
src/locales/el-GR.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/es-ES.po
Normal file
3678
src/locales/es-ES.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/fi-FI.po
Normal file
3678
src/locales/fi-FI.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/fr-FR.po
Normal file
3678
src/locales/fr-FR.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/he-IL.po
Normal file
3678
src/locales/he-IL.po
Normal file
File diff suppressed because it is too large
Load Diff
3679
src/locales/hu-HU.po
Normal file
3679
src/locales/hu-HU.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/id-ID.po
Normal file
3678
src/locales/id-ID.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/it-IT.po
Normal file
3678
src/locales/it-IT.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/ja-JP.po
Normal file
3678
src/locales/ja-JP.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/ko-KR.po
Normal file
3678
src/locales/ko-KR.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/nl-NL.po
Normal file
3678
src/locales/nl-NL.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/no-NO.po
Normal file
3678
src/locales/no-NO.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/pl-PL.po
Normal file
3678
src/locales/pl-PL.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/pt-BR.po
Normal file
3678
src/locales/pt-BR.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/pt-PT.po
Normal file
3678
src/locales/pt-PT.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/ro-RO.po
Normal file
3678
src/locales/ro-RO.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/ru-RU.po
Normal file
3678
src/locales/ru-RU.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/sl-SI.po
Normal file
3678
src/locales/sl-SI.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/sr-SP.po
Normal file
3678
src/locales/sr-SP.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/sv-SE.po
Normal file
3678
src/locales/sv-SE.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/sw-TZ.po
Normal file
3678
src/locales/sw-TZ.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/th-TH.po
Normal file
3678
src/locales/th-TH.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/tr-TR.po
Normal file
3678
src/locales/tr-TR.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/uk-UA.po
Normal file
3678
src/locales/uk-UA.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/vi-VN.po
Normal file
3678
src/locales/vi-VN.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/zh-CN.po
Normal file
3678
src/locales/zh-CN.po
Normal file
File diff suppressed because it is too large
Load Diff
3678
src/locales/zh-TW.po
Normal file
3678
src/locales/zh-TW.po
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,14 +4,19 @@ import { getDeviceId, sendAnalyticsEvent, sendInitializationEvent, Trace, user }
|
||||
import ErrorBoundary from 'components/ErrorBoundary'
|
||||
import Loader from 'components/Icons/LoadingSpinner'
|
||||
import NavBar, { PageTabs } from 'components/NavBar'
|
||||
import { UK_BANNER_HEIGHT, UK_BANNER_HEIGHT_MD, UK_BANNER_HEIGHT_SM, UkBanner } from 'components/NavBar/UkBanner'
|
||||
import { useFeatureFlagsIsLoaded } from 'featureFlags'
|
||||
import { useInfoPoolPageEnabled } from 'featureFlags/flags/infoPoolPage'
|
||||
import { useUniswapXDefaultEnabled } from 'featureFlags/flags/uniswapXDefault'
|
||||
import { useAtom } from 'jotai'
|
||||
import { useBag } from 'nft/hooks/useBag'
|
||||
import { lazy, Suspense, useEffect, useLayoutEffect, useMemo, useState } from 'react'
|
||||
import { Navigate, Route, Routes, useLocation, useSearchParams } from 'react-router-dom'
|
||||
import { shouldDisableNFTRoutesAtom } from 'state/application/atoms'
|
||||
import { useRouterPreference } from 'state/user/hooks'
|
||||
import { useAppSelector } from 'state/hooks'
|
||||
import { AppState } from 'state/reducer'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { useRouterPreference, useUserOptedOutOfUniswapX } from 'state/user/hooks'
|
||||
import { StatsigProvider, StatsigUser } from 'statsig-react'
|
||||
import styled from 'styled-components'
|
||||
import { SpinnerSVG } from 'theme/components'
|
||||
@ -82,15 +87,23 @@ const MobileBottomBar = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
const HeaderWrapper = styled.div<{ transparent?: boolean }>`
|
||||
const HeaderWrapper = styled.div<{ transparent?: boolean; bannerIsVisible?: boolean; scrollY: number }>`
|
||||
${flexRowNoWrap};
|
||||
background-color: ${({ theme, transparent }) => !transparent && theme.surface1};
|
||||
border-bottom: ${({ theme, transparent }) => !transparent && `1px solid ${theme.surface3}`};
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
top: ${({ bannerIsVisible }) => (bannerIsVisible ? Math.max(UK_BANNER_HEIGHT - scrollY, 0) : 0)}px;
|
||||
z-index: ${Z_INDEX.dropdown};
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
|
||||
top: ${({ bannerIsVisible }) => (bannerIsVisible ? Math.max(UK_BANNER_HEIGHT_MD - scrollY, 0) : 0)}px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
|
||||
top: ${({ bannerIsVisible }) => (bannerIsVisible ? Math.max(UK_BANNER_HEIGHT_SM - scrollY, 0) : 0)}px;
|
||||
}
|
||||
`
|
||||
|
||||
// this is the same svg defined in assets/images/blue-loader.svg
|
||||
@ -117,12 +130,18 @@ export default function App() {
|
||||
const currentPage = getCurrentPageFromLocation(pathname)
|
||||
const isDarkMode = useIsDarkMode()
|
||||
const [routerPreference] = useRouterPreference()
|
||||
const [scrolledState, setScrolledState] = useState(false)
|
||||
const infoPoolPageEnabled = useInfoPoolPageEnabled()
|
||||
const [scrollY, setScrollY] = useState(0)
|
||||
const scrolledState = scrollY > 0
|
||||
const isUniswapXDefaultEnabled = useUniswapXDefaultEnabled()
|
||||
const userOptedOutOfUniswapX = useUserOptedOutOfUniswapX()
|
||||
|
||||
const originCountry = useAppSelector((state: AppState) => state.user.originCountry)
|
||||
const renderUkBannner = Boolean(originCountry) && originCountry === 'GB'
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0)
|
||||
setScrolledState(false)
|
||||
setScrollY(0)
|
||||
}, [pathname])
|
||||
|
||||
const [searchParams] = useSearchParams()
|
||||
@ -165,12 +184,25 @@ export default function App() {
|
||||
}, [isDarkMode])
|
||||
|
||||
useEffect(() => {
|
||||
// If we're not in the transition period to UniswapX opt-out, set the router preference to whatever is specified.
|
||||
if (!isUniswapXDefaultEnabled) {
|
||||
user.set(CustomUserProperties.ROUTER_PREFERENCE, routerPreference)
|
||||
return
|
||||
}
|
||||
|
||||
// In the transition period, override the stored API preference to UniswapX if the user hasn't opted out.
|
||||
if (routerPreference === RouterPreference.API && !userOptedOutOfUniswapX) {
|
||||
user.set(CustomUserProperties.ROUTER_PREFERENCE, RouterPreference.X)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, the user has opted out or their preference is UniswapX/client, so set the preference to whatever is specified.
|
||||
user.set(CustomUserProperties.ROUTER_PREFERENCE, routerPreference)
|
||||
}, [routerPreference])
|
||||
}, [routerPreference, isUniswapXDefaultEnabled, userOptedOutOfUniswapX])
|
||||
|
||||
useEffect(() => {
|
||||
const scrollListener = () => {
|
||||
setScrolledState(window.scrollY > 0)
|
||||
setScrollY(window.scrollY)
|
||||
}
|
||||
window.addEventListener('scroll', scrollListener)
|
||||
return () => window.removeEventListener('scroll', scrollListener)
|
||||
@ -200,6 +232,12 @@ export default function App() {
|
||||
return null
|
||||
}
|
||||
|
||||
const blockedPaths = document.querySelector('meta[property="x:blocked-paths"]')?.getAttribute('content')?.split(',')
|
||||
const shouldBlockPath = blockedPaths?.includes(pathname) ?? false
|
||||
if (shouldBlockPath && pathname !== '/swap') {
|
||||
return <Navigate to="/swap" replace />
|
||||
}
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<DarkModeQueryParamReader />
|
||||
@ -214,7 +252,8 @@ export default function App() {
|
||||
api: process.env.REACT_APP_STATSIG_PROXY_URL,
|
||||
}}
|
||||
>
|
||||
<HeaderWrapper transparent={isHeaderTransparent}>
|
||||
{renderUkBannner && <UkBanner />}
|
||||
<HeaderWrapper transparent={isHeaderTransparent} bannerIsVisible={renderUkBannner} scrollY={scrollY}>
|
||||
<NavBar blur={isHeaderTransparent} />
|
||||
</HeaderWrapper>
|
||||
<BodyWrapper>
|
||||
|
||||
@ -43,6 +43,7 @@ export enum ApplicationModal {
|
||||
TAX_SERVICE,
|
||||
TIME_SELECTOR,
|
||||
VOTE,
|
||||
UK_DISCLAIMER,
|
||||
UNISWAP_NFT_AIRDROP_CLAIM,
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user