feat: uk disclaimer banner (#7428)
* feat: uk disclaimer banner * bad merge with sitemap * button * cypress test * intercept ordering * comments * sitemap was committed idk why * font weights * moving uk disclaimer * removing trash
This commit is contained in:
parent
48379c66ce
commit
6e4746a7fe
@ -39,4 +39,30 @@ describe('Landing Page', () => {
|
|||||||
cy.get(getTestSelector('pool-nav-link')).last().click()
|
cy.get(getTestSelector('pool-nav-link')).last().click()
|
||||||
cy.url().should('include', '/pools')
|
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')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
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 AddressClaimModal from 'components/claim/AddressClaimModal'
|
||||||
import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
|
import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
|
||||||
import FiatOnrampModal from 'components/FiatOnrampModal'
|
import FiatOnrampModal from 'components/FiatOnrampModal'
|
||||||
|
import { UkDisclaimerModal } from 'components/NavBar/UkDisclaimerModal'
|
||||||
import DevFlagsBox from 'dev/DevFlagsBox'
|
import DevFlagsBox from 'dev/DevFlagsBox'
|
||||||
import useAccountRiskCheck from 'hooks/useAccountRiskCheck'
|
import useAccountRiskCheck from 'hooks/useAccountRiskCheck'
|
||||||
import Bag from 'nft/components/bag/Bag'
|
import Bag from 'nft/components/bag/Bag'
|
||||||
@ -34,6 +35,7 @@ export default function TopLevelModals() {
|
|||||||
<TransactionCompleteModal />
|
<TransactionCompleteModal />
|
||||||
<AirdropModal />
|
<AirdropModal />
|
||||||
<FiatOnrampModal />
|
<FiatOnrampModal />
|
||||||
|
<UkDisclaimerModal />
|
||||||
{shouldShowDevFlags && <DevFlagsBox />}
|
{shouldShowDevFlags && <DevFlagsBox />}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -4,6 +4,7 @@ import { getDeviceId, sendAnalyticsEvent, sendInitializationEvent, Trace, user }
|
|||||||
import ErrorBoundary from 'components/ErrorBoundary'
|
import ErrorBoundary from 'components/ErrorBoundary'
|
||||||
import Loader from 'components/Icons/LoadingSpinner'
|
import Loader from 'components/Icons/LoadingSpinner'
|
||||||
import NavBar, { PageTabs } from 'components/NavBar'
|
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 { useFeatureFlagsIsLoaded } from 'featureFlags'
|
||||||
import { useUniswapXDefaultEnabled } from 'featureFlags/flags/uniswapXDefault'
|
import { useUniswapXDefaultEnabled } from 'featureFlags/flags/uniswapXDefault'
|
||||||
import { useAtom } from 'jotai'
|
import { useAtom } from 'jotai'
|
||||||
@ -11,6 +12,8 @@ import { useBag } from 'nft/hooks/useBag'
|
|||||||
import { lazy, Suspense, useEffect, useLayoutEffect, useMemo, useState } from 'react'
|
import { lazy, Suspense, useEffect, useLayoutEffect, useMemo, useState } from 'react'
|
||||||
import { Navigate, Route, Routes, useLocation, useSearchParams } from 'react-router-dom'
|
import { Navigate, Route, Routes, useLocation, useSearchParams } from 'react-router-dom'
|
||||||
import { shouldDisableNFTRoutesAtom } from 'state/application/atoms'
|
import { shouldDisableNFTRoutesAtom } from 'state/application/atoms'
|
||||||
|
import { useAppSelector } from 'state/hooks'
|
||||||
|
import { AppState } from 'state/reducer'
|
||||||
import { RouterPreference } from 'state/routing/types'
|
import { RouterPreference } from 'state/routing/types'
|
||||||
import { useRouterPreference, useUserOptedOutOfUniswapX } from 'state/user/hooks'
|
import { useRouterPreference, useUserOptedOutOfUniswapX } from 'state/user/hooks'
|
||||||
import { StatsigProvider, StatsigUser } from 'statsig-react'
|
import { StatsigProvider, StatsigUser } from 'statsig-react'
|
||||||
@ -60,15 +63,23 @@ const MobileBottomBar = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const HeaderWrapper = styled.div<{ transparent?: boolean }>`
|
const HeaderWrapper = styled.div<{ transparent?: boolean; bannerIsVisible?: boolean; scrollY: number }>`
|
||||||
${flexRowNoWrap};
|
${flexRowNoWrap};
|
||||||
background-color: ${({ theme, transparent }) => !transparent && theme.surface1};
|
background-color: ${({ theme, transparent }) => !transparent && theme.surface1};
|
||||||
border-bottom: ${({ theme, transparent }) => !transparent && `1px solid ${theme.surface3}`};
|
border-bottom: ${({ theme, transparent }) => !transparent && `1px solid ${theme.surface3}`};
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: ${({ bannerIsVisible }) => (bannerIsVisible ? Math.max(UK_BANNER_HEIGHT - scrollY, 0) : 0)}px;
|
||||||
z-index: ${Z_INDEX.dropdown};
|
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;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
@ -80,14 +91,18 @@ export default function App() {
|
|||||||
const currentPage = getCurrentPageFromLocation(pathname)
|
const currentPage = getCurrentPageFromLocation(pathname)
|
||||||
const isDarkMode = useIsDarkMode()
|
const isDarkMode = useIsDarkMode()
|
||||||
const [routerPreference] = useRouterPreference()
|
const [routerPreference] = useRouterPreference()
|
||||||
const [scrolledState, setScrolledState] = useState(false)
|
const [scrollY, setScrollY] = useState(0)
|
||||||
|
const scrolledState = scrollY > 0
|
||||||
const isUniswapXDefaultEnabled = useUniswapXDefaultEnabled()
|
const isUniswapXDefaultEnabled = useUniswapXDefaultEnabled()
|
||||||
const userOptedOutOfUniswapX = useUserOptedOutOfUniswapX()
|
const userOptedOutOfUniswapX = useUserOptedOutOfUniswapX()
|
||||||
const routerConfig = useRouterConfig()
|
const routerConfig = useRouterConfig()
|
||||||
|
|
||||||
|
const originCountry = useAppSelector((state: AppState) => state.user.originCountry)
|
||||||
|
const renderUkBannner = Boolean(originCountry) && originCountry === 'GB'
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.scrollTo(0, 0)
|
window.scrollTo(0, 0)
|
||||||
setScrolledState(false)
|
setScrollY(0)
|
||||||
}, [pathname])
|
}, [pathname])
|
||||||
|
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
@ -148,7 +163,7 @@ export default function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const scrollListener = () => {
|
const scrollListener = () => {
|
||||||
setScrolledState(window.scrollY > 0)
|
setScrollY(window.scrollY)
|
||||||
}
|
}
|
||||||
window.addEventListener('scroll', scrollListener)
|
window.addEventListener('scroll', scrollListener)
|
||||||
return () => window.removeEventListener('scroll', scrollListener)
|
return () => window.removeEventListener('scroll', scrollListener)
|
||||||
@ -198,7 +213,8 @@ export default function App() {
|
|||||||
api: process.env.REACT_APP_STATSIG_PROXY_URL,
|
api: process.env.REACT_APP_STATSIG_PROXY_URL,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<HeaderWrapper transparent={isHeaderTransparent}>
|
{renderUkBannner && <UkBanner />}
|
||||||
|
<HeaderWrapper transparent={isHeaderTransparent} bannerIsVisible={renderUkBannner} scrollY={scrollY}>
|
||||||
<NavBar blur={isHeaderTransparent} />
|
<NavBar blur={isHeaderTransparent} />
|
||||||
</HeaderWrapper>
|
</HeaderWrapper>
|
||||||
<BodyWrapper>
|
<BodyWrapper>
|
||||||
|
@ -43,6 +43,7 @@ export enum ApplicationModal {
|
|||||||
TAX_SERVICE,
|
TAX_SERVICE,
|
||||||
TIME_SELECTOR,
|
TIME_SELECTOR,
|
||||||
VOTE,
|
VOTE,
|
||||||
|
UK_DISCLAIMER,
|
||||||
UNISWAP_NFT_AIRDROP_CLAIM,
|
UNISWAP_NFT_AIRDROP_CLAIM,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user