feat: add token explore promo banner (#4481)

* initial design

* progress

* add background image

* add logic

* update

* delete unneed state

* more

* redux

* redux

* more redux

* rebase main

* rm unused state

* rm unused export

* relative link
This commit is contained in:
Kaylee George 2022-08-26 11:00:50 -07:00 committed by GitHub
parent c9e2f86e57
commit 6f3579acf1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 103 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

@ -0,0 +1,75 @@
import { X } from 'react-feather'
import { Link } from 'react-router-dom'
import { useShowTokensPromoBanner } from 'state/user/hooks'
import styled, { useTheme } from 'styled-components/macro'
import { opacify } from 'theme/utils'
import tokensPromoDark from '../../assets/images/tokensPromoDark.png'
import tokensPromoLight from '../../assets/images/tokensPromoLight.png'
const PopupContainer = styled.div<{ show: boolean }>`
position: absolute;
display: ${({ show }) => (show ? 'flex' : 'none')};
flex-direction: column;
padding: 12px 16px 12px 20px;
gap: 8px;
bottom: 48px;
right: 16px;
width: 320px;
height: 88px;
z-index: 5;
background-color: ${({ theme }) => (theme.darkMode ? theme.backgroundScrim : opacify(60, '#FDF0F8'))};
color: ${({ theme }) => theme.textPrimary};
border: 1px solid ${({ theme }) => theme.backgroundOutline};
border-radius: 12px;
box-shadow: ${({ theme }) => theme.deepShadow};
background-image: url(${({ theme }) => (theme.darkMode ? `${tokensPromoDark}` : `${tokensPromoLight}`)});
background-size: cover;
background-blend-mode: overlay;
transition: ${({
theme: {
transition: { duration, timing },
},
}) => `${duration.slow}ms opacity ${timing.in}`};
`
const Header = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`
const HeaderText = styled(Link)`
font-weight: 600;
font-size: 14px;
line-height: 20px;
text-decoration: none;
`
const Description = styled.span`
font-weight: 400;
font-size: 12px;
line-height: 16px;
width: 75%;
`
export default function TokensBanner() {
const theme = useTheme()
const [showTokensPromoBanner, setShowTokensPromoBanner] = useShowTokensPromoBanner()
const closeBanner = () => {
setShowTokensPromoBanner(false)
}
return (
<PopupContainer show={showTokensPromoBanner}>
<Header>
<HeaderText to={'/#/tokens'} onClick={closeBanner}>
Explore Top Tokens
</HeaderText>
<X size={20} color={theme.textSecondary} onClick={closeBanner} style={{ cursor: 'pointer' }} />
</Header>
<Description onClick={closeBanner}>Check out the new explore tab to discover and learn more</Description>
</PopupContainer>
)
}

@ -10,8 +10,10 @@ import { FlyoutAlignment, NewMenu } from 'components/Menu'
import PositionList from 'components/PositionList' import PositionList from 'components/PositionList'
import { RowBetween, RowFixed } from 'components/Row' import { RowBetween, RowFixed } from 'components/Row'
import { SwitchLocaleLink } from 'components/SwitchLocaleLink' import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
import TokensBanner from 'components/Tokens/TokensBanner'
import { isSupportedChain } from 'constants/chains' import { isSupportedChain } from 'constants/chains'
import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar' import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar'
import { TokensVariant, useTokensFlag } from 'featureFlags/flags/tokens'
import { useV3Positions } from 'hooks/useV3Positions' import { useV3Positions } from 'hooks/useV3Positions'
import { AlertTriangle, BookOpen, ChevronDown, ChevronsRight, Inbox, Layers, PlusCircle } from 'react-feather' import { AlertTriangle, BookOpen, ChevronDown, ChevronsRight, Inbox, Layers, PlusCircle } from 'react-feather'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
@ -164,8 +166,10 @@ function WrongNetworkCard() {
const navBarFlag = useNavBarFlag() const navBarFlag = useNavBarFlag()
const navBarFlagEnabled = navBarFlag === NavBarVariant.Enabled const navBarFlagEnabled = navBarFlag === NavBarVariant.Enabled
const theme = useTheme() const theme = useTheme()
const tokensFlag = useTokensFlag()
return ( return (
<> <>
{tokensFlag === TokensVariant.Enabled && <TokensBanner />}
<PageWrapper navBarFlag={navBarFlagEnabled}> <PageWrapper navBarFlag={navBarFlagEnabled}>
<AutoColumn gap="lg" justify="center"> <AutoColumn gap="lg" justify="center">
<AutoColumn gap="lg" style={{ width: '100%' }}> <AutoColumn gap="lg" style={{ width: '100%' }}>

@ -17,11 +17,13 @@ import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert'
import PriceImpactWarning from 'components/swap/PriceImpactWarning' import PriceImpactWarning from 'components/swap/PriceImpactWarning'
import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown' import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown'
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter' import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
import TokensBanner from 'components/Tokens/TokensBanner'
import TokenSafetyModal from 'components/TokenSafety/TokenSafetyModal' import TokenSafetyModal from 'components/TokenSafety/TokenSafetyModal'
import { MouseoverTooltip } from 'components/Tooltip' import { MouseoverTooltip } from 'components/Tooltip'
import { isSupportedChain } from 'constants/chains' import { isSupportedChain } from 'constants/chains'
import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar' import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar'
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign' import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
import { TokensVariant, useTokensFlag } from 'featureFlags/flags/tokens'
import { useSwapCallback } from 'hooks/useSwapCallback' import { useSwapCallback } from 'hooks/useSwapCallback'
import useTransactionDeadline from 'hooks/useTransactionDeadline' import useTransactionDeadline from 'hooks/useTransactionDeadline'
import JSBI from 'jsbi' import JSBI from 'jsbi'
@ -154,6 +156,7 @@ export default function Swap() {
const navBarFlagEnabled = navBarFlag === NavBarVariant.Enabled const navBarFlagEnabled = navBarFlag === NavBarVariant.Enabled
const redesignFlag = useRedesignFlag() const redesignFlag = useRedesignFlag()
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
const tokensFlag = useTokensFlag()
const { account, chainId } = useWeb3React() const { account, chainId } = useWeb3React()
const loadedUrlParams = useDefaultsFromURLSearch() const loadedUrlParams = useDefaultsFromURLSearch()
const [newSwapQuoteNeedsLogging, setNewSwapQuoteNeedsLogging] = useState(true) const [newSwapQuoteNeedsLogging, setNewSwapQuoteNeedsLogging] = useState(true)
@ -505,6 +508,7 @@ export default function Swap() {
return ( return (
<Trace page={PageName.SWAP_PAGE} shouldLogImpression> <Trace page={PageName.SWAP_PAGE} shouldLogImpression>
<> <>
{tokensFlag === TokensVariant.Enabled && <TokensBanner />}
{redesignFlagEnabled ? ( {redesignFlagEnabled ? (
<TokenSafetyModal <TokenSafetyModal
isOpen={importTokensNotInDefault.length > 0 && !dismissTokenWarning} isOpen={importTokensNotInDefault.length > 0 && !dismissTokenWarning}

@ -19,6 +19,7 @@ import {
removeSerializedToken, removeSerializedToken,
updateHideClosedPositions, updateHideClosedPositions,
updateShowSurveyPopup, updateShowSurveyPopup,
updateShowTokensPromoBanner,
updateUserClientSideRouter, updateUserClientSideRouter,
updateUserDarkMode, updateUserDarkMode,
updateUserDeadline, updateUserDeadline,
@ -116,6 +117,18 @@ export function useShowSurveyPopup(): [boolean | undefined, (showPopup: boolean)
return [showSurveyPopup, toggleShowSurveyPopup] return [showSurveyPopup, toggleShowSurveyPopup]
} }
export function useShowTokensPromoBanner(): [boolean, (showTokensBanner: boolean) => void] {
const dispatch = useAppDispatch()
const showTokensPromoBanner = useAppSelector((state) => state.user.showTokensPromoBanner)
const toggleShowTokensPromoBanner = useCallback(
(showTokensBanner: boolean) => {
dispatch(updateShowTokensPromoBanner({ showTokensPromoBanner: showTokensBanner }))
},
[dispatch]
)
return [showTokensPromoBanner, toggleShowTokensPromoBanner]
}
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] { export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()

@ -53,6 +53,8 @@ export interface UserState {
showSurveyPopup: boolean | undefined showSurveyPopup: boolean | undefined
showDonationLink: boolean showDonationLink: boolean
showTokensPromoBanner: boolean // show tokens promo banner for token explore
} }
function pairKey(token0Address: string, token1Address: string) { function pairKey(token0Address: string, token1Address: string) {
@ -76,6 +78,7 @@ export const initialState: UserState = {
URLWarningVisible: true, URLWarningVisible: true,
showSurveyPopup: undefined, showSurveyPopup: undefined,
showDonationLink: true, showDonationLink: true,
showTokensPromoBanner: true,
} }
const userSlice = createSlice({ const userSlice = createSlice({
@ -121,6 +124,9 @@ const userSlice = createSlice({
updateShowDonationLink(state, action) { updateShowDonationLink(state, action) {
state.showDonationLink = action.payload.showDonationLink state.showDonationLink = action.payload.showDonationLink
}, },
updateShowTokensPromoBanner(state, action) {
state.showTokensPromoBanner = action.payload.showTokensPromoBanner
},
addSerializedToken(state, { payload: { serializedToken } }) { addSerializedToken(state, { payload: { serializedToken } }) {
if (!state.tokens) { if (!state.tokens) {
state.tokens = {} state.tokens = {}
@ -210,5 +216,6 @@ export const {
updateUserExpertMode, updateUserExpertMode,
updateUserLocale, updateUserLocale,
updateUserSlippageTolerance, updateUserSlippageTolerance,
updateShowTokensPromoBanner,
} = userSlice.actions } = userSlice.actions
export default userSlice.reducer export default userSlice.reducer