diff --git a/apps/web/src/components/NavBar/UkBanner.tsx b/apps/web/src/components/NavBar/UkBanner.tsx
index 76bcbce2aea..d9e12bc9288 100644
--- a/apps/web/src/components/NavBar/UkBanner.tsx
+++ b/apps/web/src/components/NavBar/UkBanner.tsx
@@ -1,16 +1,22 @@
import { t, Trans } from '@lingui/macro'
+import throttle from 'lodash/throttle'
+import { useEffect, useState } from 'react'
import { useOpenModal } from 'state/application/hooks'
import { ApplicationModal } from 'state/application/reducer'
import styled from 'styled-components'
-import { ButtonText, ThemedText } from 'theme/components'
+import { ButtonText, CloseIcon, ThemedText } from 'theme/components'
import { Z_INDEX } from 'theme/zIndex'
+import { useUkBannerState } from 'state/application/atoms'
+import { useAppSelector } from 'state/hooks'
+import { AppState } from 'state/reducer'
+import { Flex } from 'ui/src'
+
export const UK_BANNER_HEIGHT = 65
export const UK_BANNER_HEIGHT_MD = 113
export const UK_BANNER_HEIGHT_SM = 137
const BannerWrapper = styled.div`
- position: relative;
display: flex;
background-color: ${({ theme }) => theme.surface1};
padding: 20px;
@@ -19,7 +25,7 @@ const BannerWrapper = styled.div`
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-
+ width: 98%;
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
flex-direction: column;
}
@@ -66,17 +72,63 @@ export const bannerText = t`
recommendation, invitation or inducement to deal in cryptoassets.
`
+const BannerContainer = styled.div<{
+ show: boolean
+}>`
+ display: flex;
+ max-height: ${({ show }) => (show ? `${UK_BANNER_HEIGHT}px` : '0px')};
+ overflow: hidden;
+ width: 100%;
+ transition: max-height 0.35s ease-in-out;
+ position: relative;
+
+ @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
+ max-height: ${({ show }) => (show ? `${UK_BANNER_HEIGHT_MD}px` : '0px')};
+ }
+
+ @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
+ max-height: ${({ show }) => (show ? `${UK_BANNER_HEIGHT_SM}px` : '0px')};
+ }
+`
+
+export const useRenderUkBanner = () => {
+ const [show, setShow] = useState(true)
+ const [notDismissed, dismissBanner] = useUkBannerState()
+
+ const originCountry = useAppSelector((state: AppState) => state.user.originCountry)
+
+ useEffect(() => {
+ const scrollListener = () => {
+ if (window.scrollY > 0) setShow(false)
+ else setShow(true)
+ }
+ window.addEventListener('scroll', throttle(scrollListener, 200))
+ return () => window.removeEventListener('scroll', throttle(scrollListener, 200))
+ }, [])
+
+ return {
+ renderUkBanner: Boolean(originCountry) && originCountry === 'GB' && show && notDismissed,
+ dismissBanner,
+ }
+}
+
export function UkBanner() {
+ const { renderUkBanner, dismissBanner } = useRenderUkBanner()
const openDisclaimer = useOpenModal(ApplicationModal.UK_DISCLAIMER)
return (
-
- {t`UK disclaimer:` + ' ' + bannerText}
-
-
- Read more
-
-
-
+
+
+ {`${t`UK disclaimer:`} ${bannerText}`}
+
+
+ Read more
+
+
+
+
+
+
+
)
}
diff --git a/apps/web/src/pages/App.tsx b/apps/web/src/pages/App.tsx
index ffc026cd2d5..e0847401d6f 100644
--- a/apps/web/src/pages/App.tsx
+++ b/apps/web/src/pages/App.tsx
@@ -4,7 +4,13 @@ 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 {
+ UK_BANNER_HEIGHT,
+ UK_BANNER_HEIGHT_MD,
+ UK_BANNER_HEIGHT_SM,
+ UkBanner,
+ useRenderUkBanner,
+} from 'components/NavBar/UkBanner'
import { useFeatureFlagsIsLoaded, useFeatureFlagURLOverrides } from 'featureFlags'
import { useAtom } from 'jotai'
import { useBag } from 'nft/hooks/useBag'
@@ -13,7 +19,6 @@ import { Helmet } from 'react-helmet'
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 { useRouterPreference } from 'state/user/hooks'
import { StatsigProvider, StatsigUser } from 'statsig-react'
import styled from 'styled-components'
@@ -37,6 +42,7 @@ const BodyWrapper = styled.div<{ bannerIsVisible?: boolean }>`
flex-direction: column;
position: relative;
width: 100%;
+
min-height: calc(100vh - ${({ bannerIsVisible }) => (bannerIsVisible ? UK_BANNER_HEIGHT : 0)}px);
padding: ${({ theme }) => theme.navHeight}px 0px 5rem 0px;
align-items: center;
@@ -49,6 +55,7 @@ const BodyWrapper = styled.div<{ bannerIsVisible?: boolean }>`
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
min-height: calc(100vh - ${({ bannerIsVisible }) => (bannerIsVisible ? UK_BANNER_HEIGHT_SM : 0)}px);
}
+ transition: top 0.35s ease-out;
`
const MobileBottomBar = styled.div`
@@ -72,7 +79,11 @@ const MobileBottomBar = styled.div`
}
`
-const HeaderWrapper = styled.div<{ transparent?: boolean; bannerIsVisible?: boolean; scrollY: number }>`
+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}`};
@@ -89,20 +100,15 @@ const HeaderWrapper = styled.div<{ transparent?: boolean; bannerIsVisible?: bool
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
top: ${({ bannerIsVisible }) => (bannerIsVisible ? Math.max(UK_BANNER_HEIGHT_SM - scrollY, 0) : 0)}px;
}
+ transition: top 0.35s ease-out;
`
-const useRenderUkBanner = () => {
- const originCountry = useAppSelector((state: AppState) => state.user.originCountry)
- return Boolean(originCountry) && originCountry === 'GB'
-}
-
export default function App() {
const [, setShouldDisableNFTRoutes] = useAtom(shouldDisableNFTRoutesAtom)
const location = useLocation()
const { pathname } = location
const currentPage = getCurrentPageFromLocation(pathname)
- const renderUkBanner = useRenderUkBanner()
const [searchParams] = useSearchParams()
useEffect(() => {
@@ -165,7 +171,7 @@ export default function App() {
}}
>
- {renderUkBanner && }
+
@@ -181,7 +187,7 @@ export default function App() {
const Body = memo(function Body() {
const isLoaded = useFeatureFlagsIsLoaded()
const routerConfig = useRouterConfig()
- const renderUkBanner = useRenderUkBanner()
+ const { renderUkBanner } = useRenderUkBanner()
return (
@@ -235,18 +241,10 @@ const ResetPageScrollEffect = memo(function ResetPageScrollEffect() {
})
const Header = memo(function Header() {
- const [isScrolledDown, setIsScrolledDown] = useState(false)
const isBagExpanded = useBag((state) => state.bagExpanded)
- const isHeaderTransparent = !isScrolledDown && !isBagExpanded
- const renderUkBanner = useRenderUkBanner()
+ const { renderUkBanner } = useRenderUkBanner()
- useEffect(() => {
- const scrollListener = () => {
- setIsScrolledDown(window.scrollY > 0)
- }
- window.addEventListener('scroll', scrollListener)
- return () => window.removeEventListener('scroll', scrollListener)
- }, [])
+ const isHeaderTransparent = useMemo(() => Boolean(window.scrollY > 0 && !isBagExpanded), [isBagExpanded])
return (
diff --git a/apps/web/src/state/application/atoms.ts b/apps/web/src/state/application/atoms.ts
index ae271c9cf8b..c1d5a63f29b 100644
--- a/apps/web/src/state/application/atoms.ts
+++ b/apps/web/src/state/application/atoms.ts
@@ -1,3 +1,5 @@
+import dayjs from 'dayjs'
+import { atom, useAtom } from 'jotai'
import { atomWithStorage, createJSONStorage } from 'jotai/utils'
// Note:
@@ -10,3 +12,18 @@ import { atomWithStorage, createJSONStorage } from 'jotai/utils'
const storage = createJSONStorage(() => sessionStorage)
export const shouldDisableNFTRoutesAtom = atomWithStorage('shouldDisableNFTRoutes', false, storage)
+
+const UKBannerAtom = atomWithStorage('uni:uk-banner', 0)
+
+const hideUKBannerAtom = atom(
+ (get) => {
+ const now = dayjs()
+ const last = dayjs(get(UKBannerAtom))
+ return now.diff(last, 'days', true) >= 5 // option to not totally disable banner forever
+ },
+ (_, set) => set(UKBannerAtom, Date.now())
+)
+
+export function useUkBannerState() {
+ return useAtom(hideUKBannerAtom)
+}