feat: create donation banner (#3403)

* create donation banner

* update styling and copy

* only show banner on swap page

* dont use hard coded z index

* style updates
This commit is contained in:
Ian Lapham 2022-03-02 17:48:12 -05:00 committed by GitHub
parent b44eb8877c
commit 0a736b5e62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 182 additions and 3 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

@ -0,0 +1,139 @@
import { Trans } from '@lingui/macro'
import FlagImage from 'assets/images/ukraine.png'
import { AutoColumn } from 'components/Column'
import { RowBetween, RowFixed } from 'components/Row'
import { X } from 'react-feather'
import ReactGA from 'react-ga'
import { useDarkModeManager, useShowDonationLink } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { ExternalLink, ThemedText, Z_INDEX } from 'theme'
const darkGradient = `radial-gradient(87.53% 3032.45% at 5.16% 10.13%, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%),
linear-gradient(0deg, rgba(0, 91, 187, 0.35), rgba(0, 91, 187, 0.35)), #000000;`
const lightGradient = `radial-gradient(87.53% 3032.45% at 5.16% 10.13%, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%), linear-gradient(0deg, #CBE4FF, #CBE4FF), linear-gradient(0deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.09)), radial-gradient(100% 93.36% at 0% 6.64%, #8BC4FF 0%, #FFF5BF 100%);`
const Wrapper = styled(AutoColumn)<{ darkMode: boolean }>`
background: #edeef2;
position: fixed;
bottom: 40px;
border-radius: 12px;
padding: 18px;
max-width: 360px;
background: ${({ darkMode }) => (darkMode ? darkGradient : lightGradient)};
color: ${({ theme }) => theme.text1};
z-index: ${Z_INDEX.deprecated_content};
:hover {
opacity: 0.8;
}
& > * {
z-index: ${Z_INDEX.fixed};
}
overflow: hidden;
:before {
background-image: url(${FlagImage});
background-repeat: no-repeat;
overflow: hidden;
background-size: 300px;
content: '';
height: 1200px;
width: 400px;
opacity: 0.1;
position: absolute;
transform: rotate(25deg) translate(-140px, -60px);
width: 300px;
z-index: ${Z_INDEX.deprecated_zero};
}
${({ theme }) => theme.mediaWidth.upToSmall`
max-width: 100%;
`}
${({ theme }) => theme.mediaWidth.upToMedium`
position: relative;
bottom: unset;
`}
`
const WrappedCloseIcon = styled(X)`
stroke: ${({ theme }) => theme.text2};
z-index: ${Z_INDEX.tooltip};
:hover {
cursor: pointer;
opacity: 0.8;
}
`
export const StyledFlagImage = styled.div`
margin-right: 12px;
width: 18px;
height: 18px;
border-radius: 100%;
&:before,
&:after {
content: '';
width: 9px;
height: 18px;
}
&:before {
float: left;
border-top-left-radius: 9px;
border-bottom-left-radius: 9px;
background: #005bbb;
}
&:after {
float: right;
border-top-right-radius: 9px;
border-bottom-right-radius: 9px;
background: #ffd500;
}
transform: rotate(90deg);
`
const StyledLink = styled(ExternalLink)`
text-decoration: none !important;
`
export default function DonationLink() {
const [darkMode] = useDarkModeManager()
const [, setVisible] = useShowDonationLink()
return (
<Wrapper
gap="10px"
darkMode={darkMode}
as={StyledLink}
target="https://donate.uniswap.org/#/swap"
href="https://donate.uniswap.org/#/swap"
onClickCapture={() => {
ReactGA.event({
category: 'Donate',
action: 'Link to Ukraine site.',
})
}}
>
<RowBetween>
<RowFixed>
<StyledFlagImage />
<ThemedText.Body fontWeight={600} fontSize={'18px'}>
<Trans>Donate to Ukraine</Trans>
</ThemedText.Body>
</RowFixed>
<WrappedCloseIcon
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
setVisible(false)
return false
}}
/>
</RowBetween>
<ThemedText.Body fontWeight={400} fontSize="12px" color="text2">
<Trans>Directly support the Ukrainian government by donating tokens.</Trans>
</ThemedText.Body>
</Wrapper>
)
}

@ -1,12 +1,14 @@
import { SupportedChainId } from 'constants/chains' import { SupportedChainId } from 'constants/chains'
import useActiveWeb3React from 'hooks/useActiveWeb3React' import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useLocation } from 'react-router-dom'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
import { MEDIA_WIDTHS } from 'theme' import { MEDIA_WIDTHS } from 'theme'
import { useActivePopups } from '../../state/application/hooks' import { useActivePopups } from '../../state/application/hooks'
import { useURLWarningVisible } from '../../state/user/hooks' import { useShowDonationLink, useURLWarningVisible } from '../../state/user/hooks'
import { AutoColumn } from '../Column' import { AutoColumn } from '../Column'
import ClaimPopup from './ClaimPopup' import ClaimPopup from './ClaimPopup'
import DonationLink from './DonationLink'
import PopupItem from './PopupItem' import PopupItem from './PopupItem'
const MobilePopupWrapper = styled.div<{ height: string | number }>` const MobilePopupWrapper = styled.div<{ height: string | number }>`
@ -14,11 +16,12 @@ const MobilePopupWrapper = styled.div<{ height: string | number }>`
max-width: 100%; max-width: 100%;
height: ${({ height }) => height}; height: ${({ height }) => height};
margin: ${({ height }) => (height ? '0 auto;' : 0)}; margin: ${({ height }) => (height ? '0 auto;' : 0)};
margin-bottom: ${({ height }) => (height ? '20px' : 0)}}; margin-bottom: ${({ height }) => (height ? '20px' : 0)};
display: none; display: none;
${({ theme }) => theme.mediaWidth.upToSmall` ${({ theme }) => theme.mediaWidth.upToSmall`
display: block; display: block;
padding-top: 20px;
`}; `};
` `
@ -65,6 +68,11 @@ export default function Popups() {
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
const isNotOnMainnet = Boolean(chainId && chainId !== SupportedChainId.MAINNET) const isNotOnMainnet = Boolean(chainId && chainId !== SupportedChainId.MAINNET)
const location = useLocation()
const isOnSwapPage = location.pathname.includes('swap')
const [donationVisible] = useShowDonationLink()
const showDonation = donationVisible && isOnSwapPage
return ( return (
<> <>
<FixedPopupColumn gap="20px" extraPadding={urlWarningActive} xlPadding={isNotOnMainnet}> <FixedPopupColumn gap="20px" extraPadding={urlWarningActive} xlPadding={isNotOnMainnet}>
@ -72,9 +80,11 @@ export default function Popups() {
{activePopups.map((item) => ( {activePopups.map((item) => (
<PopupItem key={item.key} content={item.content} popKey={item.key} removeAfterMs={item.removeAfterMs} /> <PopupItem key={item.key} content={item.content} popKey={item.key} removeAfterMs={item.removeAfterMs} />
))} ))}
{showDonation ? <DonationLink /> : null}
</FixedPopupColumn> </FixedPopupColumn>
<MobilePopupWrapper height={activePopups?.length > 0 ? 'fit-content' : 0}> <MobilePopupWrapper height={activePopups?.length > 0 || showDonation ? 'fit-content' : 0}>
<MobilePopupInner> <MobilePopupInner>
{showDonation ? <DonationLink /> : null}
{activePopups // reverse so new items up front {activePopups // reverse so new items up front
.slice(0) .slice(0)
.reverse() .reverse()

@ -19,6 +19,7 @@ export const updateUserDarkMode = createAction<{ userDarkMode: boolean }>('user/
export const updateUserExpertMode = createAction<{ userExpertMode: boolean }>('user/updateUserExpertMode') export const updateUserExpertMode = createAction<{ userExpertMode: boolean }>('user/updateUserExpertMode')
export const updateUserLocale = createAction<{ userLocale: SupportedLocale }>('user/updateUserLocale') export const updateUserLocale = createAction<{ userLocale: SupportedLocale }>('user/updateUserLocale')
export const updateShowSurveyPopup = createAction<{ showSurveyPopup: boolean }>('user/updateShowSurveyPopup') export const updateShowSurveyPopup = createAction<{ showSurveyPopup: boolean }>('user/updateShowSurveyPopup')
export const updateShowDonationLink = createAction<{ showDonationLink: boolean }>('user/updateShowDonationLink')
export const updateUserClientSideRouter = createAction<{ userClientSideRouter: boolean }>( export const updateUserClientSideRouter = createAction<{ userClientSideRouter: boolean }>(
'user/updateUserClientSideRouter' 'user/updateUserClientSideRouter'
) )

@ -4,6 +4,7 @@ import { L2_CHAIN_IDS } from 'constants/chains'
import { SupportedLocale } from 'constants/locales' import { SupportedLocale } from 'constants/locales'
import { L2_DEADLINE_FROM_NOW } from 'constants/misc' import { L2_DEADLINE_FROM_NOW } from 'constants/misc'
import useActiveWeb3React from 'hooks/useActiveWeb3React' import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { useCallback, useMemo } from 'react' import { useCallback, useMemo } from 'react'
import { shallowEqual } from 'react-redux' import { shallowEqual } from 'react-redux'
@ -20,6 +21,7 @@ import {
SerializedPair, SerializedPair,
SerializedToken, SerializedToken,
updateHideClosedPositions, updateHideClosedPositions,
updateShowDonationLink,
updateShowSurveyPopup, updateShowSurveyPopup,
updateUserClientSideRouter, updateUserClientSideRouter,
updateUserDarkMode, updateUserDarkMode,
@ -117,6 +119,26 @@ export function useShowSurveyPopup(): [boolean | undefined, (showPopup: boolean)
return [showSurveyPopup, toggleShowSurveyPopup] return [showSurveyPopup, toggleShowSurveyPopup]
} }
const DONATION_END_TIMESTAMP = 1646864954 // Jan 15th
export function useShowDonationLink(): [boolean | undefined, (showDonationLink: boolean) => void] {
const dispatch = useAppDispatch()
const showDonationLink = useAppSelector((state) => state.user.showDonationLink)
const toggleShowDonationLink = useCallback(
(showPopup: boolean) => {
dispatch(updateShowDonationLink({ showDonationLink: showPopup }))
},
[dispatch]
)
const timestamp = useCurrentBlockTimestamp()
const durationOver = timestamp ? timestamp.toNumber() > DONATION_END_TIMESTAMP : false
const donationVisible = showDonationLink !== false && !durationOver
return [donationVisible, toggleShowDonationLink]
}
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] { export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()

@ -12,6 +12,7 @@ import {
SerializedToken, SerializedToken,
updateHideClosedPositions, updateHideClosedPositions,
updateMatchesDarkMode, updateMatchesDarkMode,
updateShowDonationLink,
updateShowSurveyPopup, updateShowSurveyPopup,
updateUserClientSideRouter, updateUserClientSideRouter,
updateUserDarkMode, updateUserDarkMode,
@ -64,6 +65,8 @@ export interface UserState {
// undefined means has not gone through A/B split yet // undefined means has not gone through A/B split yet
showSurveyPopup: boolean | undefined showSurveyPopup: boolean | undefined
showDonationLink: boolean
} }
function pairKey(token0Address: string, token1Address: string) { function pairKey(token0Address: string, token1Address: string) {
@ -85,6 +88,7 @@ export const initialState: UserState = {
timestamp: currentTimestamp(), timestamp: currentTimestamp(),
URLWarningVisible: true, URLWarningVisible: true,
showSurveyPopup: undefined, showSurveyPopup: undefined,
showDonationLink: true,
} }
export default createReducer(initialState, (builder) => export default createReducer(initialState, (builder) =>
@ -155,6 +159,9 @@ export default createReducer(initialState, (builder) =>
.addCase(updateShowSurveyPopup, (state, action) => { .addCase(updateShowSurveyPopup, (state, action) => {
state.showSurveyPopup = action.payload.showSurveyPopup state.showSurveyPopup = action.payload.showSurveyPopup
}) })
.addCase(updateShowDonationLink, (state, action) => {
state.showDonationLink = action.payload.showDonationLink
})
.addCase(addSerializedToken, (state, { payload: { serializedToken } }) => { .addCase(addSerializedToken, (state, { payload: { serializedToken } }) => {
if (!state.tokens) { if (!state.tokens) {
state.tokens = {} state.tokens = {}