Commit 0b8026e6 authored by Jordan Frankfurt's avatar Jordan Frankfurt Committed by GitHub

feat: add base promotional advert (#7124)

* feat: add base promotional advert

add mobile layout

tweak text container size

only show new banner on Base

fix import

update to new state structure

* Update src/components/Banner/BaseAnnouncementBanner/index.tsx
Co-authored-by: default avatarCharles Bachmeier <charles@bachmeier.io>

* pr feedback

---------
Co-authored-by: default avatarCharles Bachmeier <charles@bachmeier.io>
parent b14831be
<svg width="119" height="99" viewBox="0 0 119 99" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M118.097 29.6061C117.891 67.6376 86.8404 98.3016 48.7425 98.0958C12.5975 97.9006 -16.9048 69.9894 -19.659 34.6507L71.5199 35.1431L71.5825 23.5662L-19.5965 23.0738C-16.4608 -12.2332 13.3412 -39.824 49.4863 -39.6288C87.5842 -39.423 118.302 -8.4256 118.097 29.6061Z" fill="white" fill-opacity="0.1"/>
</svg>
import { Trans } from '@lingui/macro'
import { InterfaceElementName } from '@uniswap/analytics-events'
import walletBannerPhoneImageSrc from 'assets/images/wallet_banner_phone_image.png'
import { ChainId } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { ReactComponent as AppleLogo } from 'assets/svg/apple_logo.svg'
import { BaseButton } from 'components/Button'
import { AutoColumn } from 'components/Column'
import { OpacityHoverState } from 'components/Common'
import Row from 'components/Row'
import baseLogoUrl from 'assets/svg/base_background_icon.svg'
import { useScreenSize } from 'hooks/useScreenSize'
import { X } from 'react-feather'
import { useLocation } from 'react-router-dom'
import { useHideUniswapWalletBanner } from 'state/user/hooks'
import styled from 'styled-components'
import { useHideBaseWalletBanner } from 'state/user/hooks'
import { ThemedText } from 'theme'
import { Z_INDEX } from 'theme/zIndex'
import { openDownloadApp, openWalletMicrosite } from 'utils/openDownloadApp'
import { isIOS, isMobileSafari } from 'utils/userAgent'
const PopupContainer = styled.div<{ show: boolean }>`
display: flex;
flex-direction: column;
justify-content: space-between;
import { BannerButton, BaseBackgroundImage, ButtonRow, PopupContainer, StyledXButton } from './styled'
${({ show }) => !show && 'display: none'};
background: url(${walletBannerPhoneImageSrc});
background-repeat: no-repeat;
background-position: top 18px right 15px;
background-size: 166px;
:hover {
background-size: 170px;
}
transition: background-size ${({ theme }) => theme.transition.duration.medium}
${({ theme }) => theme.transition.timing.inOut};
background-color: ${({ theme }) => theme.promotional};
color: ${({ theme }) => theme.textPrimary};
position: fixed;
z-index: ${Z_INDEX.sticky};
padding: 24px 16px 16px;
border-radius: 20px;
bottom: 20px;
right: 20px;
width: 390px;
height: 164px;
border: 1px solid ${({ theme }) => theme.backgroundOutline};
box-shadow: ${({ theme }) => theme.deepShadow};
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
bottom: 62px;
}
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
width: unset;
right: 10px;
left: 10px;
}
user-select: none;
`
const ButtonRow = styled(Row)`
gap: 16px;
`
const StyledXButton = styled(X)`
cursor: pointer;
position: absolute;
top: 21px;
right: 17px;
color: ${({ theme }) => theme.white};
${OpacityHoverState};
`
const BannerButton = styled(BaseButton)`
height: 40px;
border-radius: 16px;
padding: 10px;
${OpacityHoverState};
`
export default function UniswapWalletBanner() {
const [hideUniswapWalletBanner, toggleHideUniswapWalletBanner] = useHideUniswapWalletBanner()
export default function BaseWalletBanner() {
const { chainId } = useWeb3React()
const [hideBaseWalletBanner, toggleHideBaseWalletBanner] = useHideBaseWalletBanner()
const location = useLocation()
const isLandingScreen = location.search === '?intro=true' || location.pathname === '/'
const shouldDisplay = Boolean(!hideUniswapWalletBanner && !isLandingScreen)
const shouldDisplay = Boolean(!hideBaseWalletBanner && !isLandingScreen && chainId === ChainId.BASE)
const screenSize = useScreenSize()
......@@ -104,15 +34,26 @@ export default function UniswapWalletBanner() {
// prevent click from bubbling to UI on the page underneath, i.e. clicking a token row
e.preventDefault()
e.stopPropagation()
toggleHideUniswapWalletBanner()
toggleHideBaseWalletBanner()
}}
/>
<AutoColumn gap="8px">
<ThemedText.HeadlineMedium fontSize="24px" lineHeight="28px" color="white" maxWidth="60%">
<Trans>Uniswap in your pocket</Trans>
</ThemedText.HeadlineMedium>
</AutoColumn>
<BaseBackgroundImage src={baseLogoUrl} alt="transparent base background logo" />
<ThemedText.HeadlineMedium fontSize="24px" lineHeight="28px" color="white" maxWidth="224px">
<Trans>
Swap on{' '}
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M19.5689 10C19.5689 15.4038 15.1806 19.7845 9.76737 19.7845C4.63163 19.7845 0.418433 15.8414 0 10.8225H12.9554V9.17755H0C0.418433 4.15863 4.63163 0.215576 9.76737 0.215576C15.1806 0.215576 19.5689 4.59621 19.5689 10Z"
fill="white"
/>
</svg>{' '}
BASE in the Uniswap wallet
</Trans>
</ThemedText.HeadlineMedium>
<ButtonRow>
{isIOS ? (
......@@ -122,6 +63,7 @@ export default function UniswapWalletBanner() {
onClick={() =>
openDownloadApp({
element: InterfaceElementName.UNISWAP_WALLET_BANNER_DOWNLOAD_BUTTON,
appStoreParams: 'pt=123625782&ct=base-app-banner&mt=8',
})
}
>
......
import walletBannerPhoneImageSrc from 'assets/images/wallet_banner_phone_image.png'
import { BaseButton } from 'components/Button'
import { OpacityHoverState } from 'components/Common'
import Row from 'components/Row'
import { X } from 'react-feather'
import styled from 'styled-components'
import { Z_INDEX } from 'theme/zIndex'
export const PopupContainer = styled.div<{ show: boolean }>`
display: flex;
flex-direction: column;
justify-content: space-between;
${({ show }) => !show && 'display: none'};
background: url(${walletBannerPhoneImageSrc});
background-repeat: no-repeat;
background-position: top 18px right 15px;
background-size: 166px;
:hover {
background-size: 170px;
}
transition: background-size ${({ theme }) => theme.transition.duration.medium}
${({ theme }) => theme.transition.timing.inOut};
background-color: ${({ theme }) => theme.chain_84531};
color: ${({ theme }) => theme.textPrimary};
position: fixed;
z-index: ${Z_INDEX.sticky};
padding: 24px 16px 16px;
border-radius: 20px;
bottom: 20px;
right: 20px;
width: 390px;
height: 164px;
border: 1px solid ${({ theme }) => theme.backgroundOutline};
box-shadow: ${({ theme }) => theme.deepShadow};
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
bottom: 62px;
}
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
background-position: top 32px right -10px;
width: unset;
right: 10px;
left: 10px;
height: 144px;
}
user-select: none;
`
export const BaseBackgroundImage = styled.img`
position: absolute;
top: 0;
left: 0;
height: 138px;
width: 138px;
`
export const ButtonRow = styled(Row)`
gap: 16px;
`
export const StyledXButton = styled(X)`
cursor: pointer;
position: absolute;
top: 21px;
right: 17px;
color: ${({ theme }) => theme.white};
${OpacityHoverState};
`
export const BannerButton = styled(BaseButton)`
height: 40px;
border-radius: 16px;
padding: 10px;
${OpacityHoverState};
`
import { useWeb3React } from '@web3-react/core'
import { OffchainActivityModal } from 'components/AccountDrawer/MiniPortfolio/Activity/OffchainActivityModal'
import UniwalletModal from 'components/AccountDrawer/UniwalletModal'
import UniswapWalletBanner from 'components/Banner/UniswapWalletBanner'
import BaseAnnouncementBanner from 'components/Banner/BaseAnnouncementBanner'
import AddressClaimModal from 'components/claim/AddressClaimModal'
import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
import FiatOnrampModal from 'components/FiatOnrampModal'
......@@ -28,7 +28,7 @@ export default function TopLevelModals() {
<ConnectedAccountBlocked account={account} isOpen={accountBlocked} />
<Bag />
<UniwalletModal />
<UniswapWalletBanner />
<BaseAnnouncementBanner />
<OffchainActivityModal />
<TransactionCompleteModal />
<AirdropModal />
......
......@@ -16,8 +16,8 @@ import { AppState } from '../types'
import {
addSerializedPair,
addSerializedToken,
updateHideBaseWalletBanner,
updateHideClosedPositions,
updateHideUniswapWalletBanner,
updateUserDeadline,
updateUserLocale,
updateUserRouterPreference,
......@@ -211,15 +211,15 @@ export function useURLWarningVisible(): boolean {
return useAppSelector((state: AppState) => state.user.URLWarningVisible)
}
export function useHideUniswapWalletBanner(): [boolean, () => void] {
export function useHideBaseWalletBanner(): [boolean, () => void] {
const dispatch = useAppDispatch()
const hideUniswapWalletBanner = useAppSelector((state) => state.user.hideUniswapWalletBanner)
const hideBaseWalletBanner = useAppSelector((state) => state.user.hideBaseWalletBanner)
const toggleHideUniswapWalletBanner = useCallback(() => {
dispatch(updateHideUniswapWalletBanner({ hideUniswapWalletBanner: true }))
const toggleHideBaseWalletBanner = useCallback(() => {
dispatch(updateHideBaseWalletBanner({ hideBaseWalletBanner: true }))
}, [dispatch])
return [hideUniswapWalletBanner, toggleHideUniswapWalletBanner]
return [hideBaseWalletBanner, toggleHideBaseWalletBanner]
}
export function useUserDisabledUniswapX(): boolean {
......
......@@ -7,8 +7,8 @@ import reducer, {
addSerializedPair,
addSerializedToken,
initialState,
updateHideBaseWalletBanner,
updateHideClosedPositions,
updateHideUniswapWalletBanner,
updateSelectedWallet,
updateUserDeadline,
updateUserLocale,
......@@ -110,10 +110,10 @@ describe('swap reducer', () => {
})
})
describe('updateHideUniswapWalletBanner', () => {
it('updates the hideUniswapWalletBanner', () => {
store.dispatch(updateHideUniswapWalletBanner({ hideUniswapWalletBanner: true }))
expect(store.getState().hideUniswapWalletBanner).toEqual(true)
describe('updateHideBaseWalletBanner', () => {
it('updates the updateHideBaseWalletBanner', () => {
store.dispatch(updateHideBaseWalletBanner({ hideBaseWalletBanner: true }))
expect(store.getState().hideBaseWalletBanner).toEqual(true)
})
})
......
......@@ -47,7 +47,7 @@ export interface UserState {
timestamp: number
URLWarningVisible: boolean
hideUniswapWalletBanner: boolean
hideBaseWalletBanner: boolean
disabledUniswapX?: boolean
// undefined means has not gone through A/B split yet
showSurveyPopup?: boolean
......@@ -69,7 +69,7 @@ export const initialState: UserState = {
pairs: {},
timestamp: currentTimestamp(),
URLWarningVisible: true,
hideUniswapWalletBanner: false,
hideBaseWalletBanner: false,
showSurveyPopup: undefined,
}
......@@ -98,8 +98,8 @@ const userSlice = createSlice({
updateHideClosedPositions(state, action) {
state.userHideClosedPositions = action.payload.userHideClosedPositions
},
updateHideUniswapWalletBanner(state, action) {
state.hideUniswapWalletBanner = action.payload.hideUniswapWalletBanner
updateHideBaseWalletBanner(state, action) {
state.hideBaseWalletBanner = action.payload.hideBaseWalletBanner
},
updateDisabledUniswapX(state, action) {
state.disabledUniswapX = action.payload.disabledUniswapX
......@@ -214,7 +214,7 @@ export const {
updateUserDeadline,
updateUserLocale,
updateUserSlippageTolerance,
updateHideUniswapWalletBanner,
updateHideBaseWalletBanner,
updateDisabledUniswapX,
} = userSlice.actions
export default userSlice.reducer
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment