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.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 ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
|
||||
import FiatOnrampModal from 'components/FiatOnrampModal'
|
||||
import { UkDisclaimerModal } from 'components/NavBar/UkDisclaimerModal'
|
||||
import DevFlagsBox from 'dev/DevFlagsBox'
|
||||
import useAccountRiskCheck from 'hooks/useAccountRiskCheck'
|
||||
import Bag from 'nft/components/bag/Bag'
|
||||
@ -34,6 +35,7 @@ export default function TopLevelModals() {
|
||||
<TransactionCompleteModal />
|
||||
<AirdropModal />
|
||||
<FiatOnrampModal />
|
||||
<UkDisclaimerModal />
|
||||
{shouldShowDevFlags && <DevFlagsBox />}
|
||||
</>
|
||||
)
|
||||
|
@ -4,6 +4,7 @@ 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 { useUniswapXDefaultEnabled } from 'featureFlags/flags/uniswapXDefault'
|
||||
import { useAtom } from 'jotai'
|
||||
@ -11,6 +12,8 @@ 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 { 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'
|
||||
@ -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};
|
||||
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;
|
||||
}
|
||||
`
|
||||
|
||||
export default function App() {
|
||||
@ -80,14 +91,18 @@ export default function App() {
|
||||
const currentPage = getCurrentPageFromLocation(pathname)
|
||||
const isDarkMode = useIsDarkMode()
|
||||
const [routerPreference] = useRouterPreference()
|
||||
const [scrolledState, setScrolledState] = useState(false)
|
||||
const [scrollY, setScrollY] = useState(0)
|
||||
const scrolledState = scrollY > 0
|
||||
const isUniswapXDefaultEnabled = useUniswapXDefaultEnabled()
|
||||
const userOptedOutOfUniswapX = useUserOptedOutOfUniswapX()
|
||||
const routerConfig = useRouterConfig()
|
||||
|
||||
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()
|
||||
@ -148,7 +163,7 @@ export default function App() {
|
||||
|
||||
useEffect(() => {
|
||||
const scrollListener = () => {
|
||||
setScrolledState(window.scrollY > 0)
|
||||
setScrollY(window.scrollY)
|
||||
}
|
||||
window.addEventListener('scroll', scrollListener)
|
||||
return () => window.removeEventListener('scroll', scrollListener)
|
||||
@ -198,7 +213,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…
Reference in New Issue
Block a user