Commit 8757e413 authored by lynn's avatar lynn Committed by GitHub

feat: tax service toast + modal (#6101)

* working

* unused export

* remove fiat on ramp toast

* design feedback tweaks

* add test + final design tweaks from fred

* add back fiat on ramp modal

* temp

* remove temp

* remove fiat on ramp stuff

* add back modal

* remove fiat on ramp ack from reducer

* respond to jordan

* mobile full width

* add feature flag

* fixes

* TESTING FEATURE FLAG

* testing w blair

* add stat sig server to prod env

* testing stat sig, wait for initialization

* revert stat sig testing stuff

* fix
parent 78ac7650
...@@ -5,9 +5,7 @@ const BONSAI_COLLECTION_ADDRESS = '0xec9c519d49856fd2f8133a0741b4dbe002ce211b' ...@@ -5,9 +5,7 @@ const BONSAI_COLLECTION_ADDRESS = '0xec9c519d49856fd2f8133a0741b4dbe002ce211b'
describe('Testing nfts', () => { describe('Testing nfts', () => {
beforeEach(() => { beforeEach(() => {
cy.visit('/').then(() => { cy.visit('/')
cy.get(getTestSelector('FiatOnrampAnnouncement-close')).first().click()
})
}) })
it('should load nft leaderboard', () => { it('should load nft leaderboard', () => {
......
import { getTestSelector } from '../utils'
describe('Pool', () => { describe('Pool', () => {
beforeEach(() => { beforeEach(() => {
cy.visit('/pool').then(() => { cy.visit('/pool').then(() => {
...@@ -8,13 +6,7 @@ describe('Pool', () => { ...@@ -8,13 +6,7 @@ describe('Pool', () => {
}) })
it('add liquidity links to /add/ETH', () => { it('add liquidity links to /add/ETH', () => {
cy.get('body') cy.get('body').then(() => {
.then((body) => {
if (body.find(getTestSelector('FiatOnrampAnnouncement-close')).length > 0) {
cy.get(getTestSelector('FiatOnrampAnnouncement-close')).click()
}
})
.then(() => {
cy.get('#join-pool-button') cy.get('#join-pool-button')
.click() .click()
.then(() => { .then(() => {
......
...@@ -402,7 +402,7 @@ function pickThemeButtonBackgroundColor({ theme, emphasis }: { theme: DefaultThe ...@@ -402,7 +402,7 @@ function pickThemeButtonBackgroundColor({ theme, emphasis }: { theme: DefaultThe
case ButtonEmphasis.high: case ButtonEmphasis.high:
return theme.accentAction return theme.accentAction
case ButtonEmphasis.promotional: case ButtonEmphasis.promotional:
return theme.accentTextLightPrimary return theme.accentActionSoft
case ButtonEmphasis.highSoft: case ButtonEmphasis.highSoft:
return theme.accentActionSoft return theme.accentActionSoft
case ButtonEmphasis.low: case ButtonEmphasis.low:
...@@ -456,7 +456,7 @@ function pickThemeButtonTextColor({ theme, emphasis }: { theme: DefaultTheme; em ...@@ -456,7 +456,7 @@ function pickThemeButtonTextColor({ theme, emphasis }: { theme: DefaultTheme; em
switch (emphasis) { switch (emphasis) {
case ButtonEmphasis.high: case ButtonEmphasis.high:
case ButtonEmphasis.promotional: case ButtonEmphasis.promotional:
return theme.accentTextLightPrimary return theme.accentAction
case ButtonEmphasis.highSoft: case ButtonEmphasis.highSoft:
return theme.accentAction return theme.accentAction
case ButtonEmphasis.low: case ButtonEmphasis.low:
......
...@@ -3,6 +3,7 @@ import { GqlRoutingVariant, useGqlRoutingFlag } from 'featureFlags/flags/gqlRout ...@@ -3,6 +3,7 @@ import { GqlRoutingVariant, useGqlRoutingFlag } from 'featureFlags/flags/gqlRout
import { NftGraphqlVariant, useNftGraphqlFlag } from 'featureFlags/flags/nftlGraphql' import { NftGraphqlVariant, useNftGraphqlFlag } from 'featureFlags/flags/nftlGraphql'
import { PayWithAnyTokenVariant, usePayWithAnyTokenFlag } from 'featureFlags/flags/payWithAnyToken' import { PayWithAnyTokenVariant, usePayWithAnyTokenFlag } from 'featureFlags/flags/payWithAnyToken'
import { SwapWidgetVariant, useSwapWidgetFlag } from 'featureFlags/flags/swapWidget' import { SwapWidgetVariant, useSwapWidgetFlag } from 'featureFlags/flags/swapWidget'
import { TaxServiceVariant, useTaxServiceBannerFlag } from 'featureFlags/flags/taxServiceBanner'
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc' import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
import { useAtomValue, useUpdateAtom } from 'jotai/utils' import { useAtomValue, useUpdateAtom } from 'jotai/utils'
import { Children, PropsWithChildren, ReactElement, ReactNode, useCallback, useState } from 'react' import { Children, PropsWithChildren, ReactElement, ReactNode, useCallback, useState } from 'react'
...@@ -229,6 +230,12 @@ export default function FeatureFlagModal() { ...@@ -229,6 +230,12 @@ export default function FeatureFlagModal() {
featureFlag={FeatureFlag.nftGraphql} featureFlag={FeatureFlag.nftGraphql}
label="Migrate NFT read endpoints to GQL" label="Migrate NFT read endpoints to GQL"
/> />
<FeatureFlagOption
variant={TaxServiceVariant}
value={useTaxServiceBannerFlag()}
featureFlag={FeatureFlag.taxService}
label="Tax Service Banner"
/>
<FeatureFlagGroup name="Debug"> <FeatureFlagGroup name="Debug">
<FeatureFlagOption <FeatureFlagOption
variant={TraceJsonRpcVariant} variant={TraceJsonRpcVariant}
......
import { Trans } from '@lingui/macro'
import { sendAnalyticsEvent } from '@uniswap/analytics'
import { InterfaceEventName } from '@uniswap/analytics-events'
import { useWeb3React } from '@web3-react/core'
import fiatMaskUrl from 'assets/svg/fiat_mask.svg'
import { useCallback, useEffect, useState } from 'react'
import { X } from 'react-feather'
import { useToggleWalletDropdown } from 'state/application/hooks'
import { useAppSelector } from 'state/hooks'
import { useFiatOnrampAck } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { ThemedText } from 'theme'
import { isMobile } from 'utils/userAgent'
const Arrow = styled.div`
top: -4px;
height: 16px;
position: absolute;
right: 16px;
width: 16px;
::before {
background: hsl(315.75, 93%, 83%);
border-top: none;
border-left: none;
box-sizing: border-box;
content: '';
height: 16px;
position: absolute;
transform: rotate(45deg);
width: 16px;
}
`
const ArrowWrapper = styled.div`
position: absolute;
right: 16px;
top: 90%;
width: 100%;
max-width: 320px;
min-height: 92px;
@media screen and (min-width: ${({ theme }) => theme.breakpoint.lg}px) {
right: 36px;
}
`
const CloseIcon = styled(X)`
color: white;
cursor: pointer;
position: absolute;
top: 8px;
right: 8px;
z-index: 1;
`
const Wrapper = styled.button`
background: radial-gradient(105% 250% at 100% 5%, hsla(318, 95%, 85%) 1%, hsla(331, 80%, 75%, 0.1) 84%),
linear-gradient(180deg, hsla(296, 92%, 67%, 0.5) 0%, hsla(313, 96%, 60%, 0.5) 130%);
background-color: hsla(297, 93%, 68%, 1);
border-radius: 12px;
border: none;
cursor: pointer;
outline: none;
overflow: hidden;
position: relative;
text-align: start;
max-width: 320px;
min-height: 92px;
width: 100%;
:before {
background-image: url(${fiatMaskUrl});
background-repeat: no-repeat;
content: '';
height: 100%;
position: absolute;
right: -154px; // roughly width of fiat mask image
top: 0;
width: 100%;
}
`
const Header = styled(ThemedText.SubHeader)`
color: white;
margin: 0;
padding: 12px 12px 4px;
position: relative;
`
const Body = styled(ThemedText.BodySmall)`
color: white;
margin: 0 12px 12px 12px !important;
position: relative;
`
const ANNOUNCEMENT_RENDERED = 'FiatOnrampAnnouncement-rendered'
const ANNOUNCEMENT_DISMISSED = 'FiatOnrampAnnouncement-dismissed'
const MAX_RENDER_COUNT = 3
export function FiatOnrampAnnouncement() {
const { account } = useWeb3React()
const [acks, acknowledge] = useFiatOnrampAck()
const [localClose, setLocalClose] = useState(false)
useEffect(() => {
if (!sessionStorage.getItem(ANNOUNCEMENT_RENDERED)) {
acknowledge({ renderCount: acks?.renderCount + 1 })
sessionStorage.setItem(ANNOUNCEMENT_RENDERED, 'true')
}
}, [acknowledge, acks])
const handleClose = useCallback(() => {
setLocalClose(true)
localStorage.setItem(ANNOUNCEMENT_DISMISSED, 'true')
}, [])
const toggleWalletDropdown = useToggleWalletDropdown()
const handleClick = useCallback(() => {
sendAnalyticsEvent(InterfaceEventName.FIAT_ONRAMP_BANNER_CLICKED)
toggleWalletDropdown()
acknowledge({ user: true })
}, [acknowledge, toggleWalletDropdown])
const openModal = useAppSelector((state) => state.application.openModal)
if (
!account ||
acks?.user ||
localStorage.getItem(ANNOUNCEMENT_DISMISSED) ||
acks?.renderCount >= MAX_RENDER_COUNT ||
isMobile ||
openModal !== null ||
localClose
) {
return null
}
return (
<ArrowWrapper>
<Arrow />
<CloseIcon onClick={handleClose} data-testid="FiatOnrampAnnouncement-close" />
<Wrapper onClick={handleClick}>
<Header>
<Trans>Buy crypto</Trans>
</Header>
<Body>
<Trans>Get tokens at the best prices in web3 on Uniswap, powered by Moonpay.</Trans>
</Body>
</Wrapper>
</ArrowWrapper>
)
}
import { Trans } from '@lingui/macro'
import { TraceEvent } from '@uniswap/analytics'
import { BrowserEvent, InterfaceElementName, SharedEventName } from '@uniswap/analytics-events'
import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button'
import { bodySmall, subhead } from 'nft/css/common.css'
import { useState } from 'react'
import { useCallback } from 'react'
import { X } from 'react-feather'
import { useIsDarkMode } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { opacify } from 'theme/utils'
import { Z_INDEX } from 'theme/zIndex'
import TaxServiceModal from '.'
import CointrackerLogo from './CointrackerLogo.png'
import TokenTaxLogo from './TokenTaxLogo.png'
const PopupContainer = styled.div<{ show: boolean; isDarkMode: boolean }>`
box-shadow: ${({ theme }) => theme.deepShadow};
border: 1px solid ${({ theme }) => theme.backgroundOutline};
background-color: ${({ theme }) => theme.backgroundSurface};
border-radius: 13px;
cursor: pointer;
color: ${({ theme }) => theme.textPrimary};
display: ${({ show }) => (show ? 'flex' : 'none')};
flex-direction: column;
position: fixed;
right: clamp(0px, 1vw, 16px);
z-index: ${Z_INDEX.sticky};
transition: ${({
theme: {
transition: { duration, timing },
},
}) => `${duration.slow} opacity ${timing.in}`};
width: 320px;
height: 156px;
bottom: 50px;
@media screen and (max-width: ${({ theme }) => theme.breakpoint.sm}px) {
width: 100%;
}
::before {
content: '';
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
background-image: url(${CointrackerLogo}), url(${TokenTaxLogo});
background-size: 15%, 20%;
background-repeat: no-repeat;
background-position: top right 75px, bottom 5px right 7px;
@media screen and (max-width: ${({ theme }) => theme.breakpoint.sm}px) {
background-size: 48px, 64px;
background-position: top right 75px, bottom 20px right 7px;
}
opacity: ${({ isDarkMode }) => (isDarkMode ? '0.9' : '0.25')};
}
`
const InnerContainer = styled.div<{ isDarkMode: boolean }>`
border-radius: 12px;
cursor: auto;
overflow: hidden;
display: flex;
flex-direction: column;
position: relative;
gap: 8px;
padding: 16px;
background-color: ${({ isDarkMode, theme }) =>
isDarkMode ? opacify(10, theme.accentAction) : opacify(4, theme.accentAction)};
`
const Button = styled(ThemeButton)`
margin-top: auto;
margin-right: auto;
padding: 8px 24px;
gap: 8px;
border-radius: 12px;
`
const TextContainer = styled.div`
user-select: none;
display: flex;
flex-direction: column;
width: 70%;
justify-content: center;
`
export const StyledXButton = styled(X)`
color: ${({ theme }) => theme.textPrimary};
cursor: pointer;
&:hover {
opacity: ${({ theme }) => theme.opacity.hover};
}
&:active {
opacity: ${({ theme }) => theme.opacity.click};
}
`
const TAX_SERVICE_DISMISSED = 'TaxServiceToast-dismissed'
export default function TaxServiceBanner() {
const isDarkMode = useIsDarkMode()
const [modalOpen, setModalOpen] = useState(false)
const sessionStorageTaxServiceDismissed = sessionStorage.getItem(TAX_SERVICE_DISMISSED)
if (!sessionStorageTaxServiceDismissed) {
sessionStorage.setItem(TAX_SERVICE_DISMISSED, 'false')
}
const [bannerOpen, setBannerOpen] = useState(sessionStorageTaxServiceDismissed !== 'true')
const onDismiss = useCallback(() => {
setModalOpen(false)
}, [])
const openTaxModal = useCallback(() => {
setModalOpen(true)
}, [])
const handleClose = useCallback(() => {
sessionStorage.setItem(TAX_SERVICE_DISMISSED, 'true')
setBannerOpen(false)
}, [])
return (
<PopupContainer show={bannerOpen} isDarkMode={isDarkMode}>
<InnerContainer isDarkMode={isDarkMode}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<TextContainer data-testid="tax-service-description">
<div className={subhead} style={{ paddingBottom: '12px' }}>
<Trans>Save on your crypto taxes</Trans>
</div>
<div className={bodySmall} style={{ paddingBottom: '12px' }}>
<Trans>Get up to a 20% discount on CoinTracker or TokenTax.</Trans>{' '}
</div>
</TextContainer>
<StyledXButton size={20} onClick={handleClose} />
</div>
<TraceEvent
events={[BrowserEvent.onClick]}
name={SharedEventName.ELEMENT_CLICKED}
element={InterfaceElementName.TAX_SERVICE_BANNER_CTA_BUTTON}
>
<Button
size={ButtonSize.small}
emphasis={ButtonEmphasis.promotional}
onClick={openTaxModal}
data-testid="learn-more-button"
>
<Trans>Learn more</Trans>
</Button>
</TraceEvent>
</InnerContainer>
<TaxServiceModal isOpen={modalOpen} onDismiss={onDismiss} />
</PopupContainer>
)
}
import { render, screen } from '../../test-utils'
import TaxServiceModal from './'
import TaxServiceBanner from './TaxServiceBanner'
it('renders Tax Service Modal content', async () => {
render(<TaxServiceModal isOpen={true} onDismiss={() => null} />)
expect(screen.getByText('Save 10% on all plans')).toBeInTheDocument()
expect(screen.getByText('New and existing users save up to 20%')).toBeInTheDocument()
expect(screen.getAllByTestId('tax-service-option-button')).toHaveLength(2)
})
it('renders Tax Service Banner', async () => {
render(<TaxServiceBanner />)
expect(screen.getByText('Save on your crypto taxes')).toBeInTheDocument()
expect(screen.getAllByTestId('learn-more-button')).toHaveLength(1)
expect(screen.getByText('Get up to a 20% discount on CoinTracker or TokenTax.')).toBeInTheDocument()
})
import { Trans } from '@lingui/macro'
import { TraceEvent } from '@uniswap/analytics'
import { BrowserEvent, InterfaceElementName, SharedEventName } from '@uniswap/analytics-events'
import { ButtonEmphasis } from 'components/Button'
import { ButtonSize, ThemeButton } from 'components/Button'
import { Box } from 'nft/components/Box'
import { bodySmall, subhead } from 'nft/css/common.css'
import { memo } from 'react'
import styled from 'styled-components/macro'
import Modal from '../Modal'
import CointrackerFullLogo from './CointrackerFullLogo.png'
import { StyledXButton } from './TaxServiceBanner'
import TokenTaxFullLogo from './TokenTaxFullLogo.png'
interface TaxServiceModalProps {
isOpen: boolean
onDismiss: () => void
}
interface TaxServiceOptionProps {
logo: any
description: string
url: string
}
const InnerContainer = styled.div`
background-color: ${({ theme }) => theme.backgroundSurface};
overflow: hidden;
display: flex;
width: 420px;
height: 268px;
flex-direction: column;
position: relative;
gap: 20px;
padding: 16px;
`
const TaxOptionContainer = styled.div`
display: flex;
flex: 1;
gap: 16px;
justify-content: center;
`
const TaxOptionDescription = styled.div`
display: flex;
height: 100%;
justify-content: center;
user-select: none;
text-align: center;
`
const TaxOption = styled.div`
align-items: center;
background-color: ${({ theme }) => theme.backgroundModule};
border-radius: 12px;
cursor: auto;
display: flex;
flex-direction: column;
flex: 1;
justify-content: space-between;
padding: 12px;
gap: 16px;
`
const StyledImageContainer = styled(Box)`
width: 75%;
height: 80%;
cursor: auto;
object-fit: contain;
`
const Button = styled(ThemeButton)`
cursor: pointer;
width: 100%;
margin-right: auto;
`
const TOKEN_TAX_URL = 'https://tokentax.co/uniswap?via=uniswap'
const COINTRACKER_URL = 'https://www.cointracker.io/partner/uniswap?utm_source=uniswap'
const TOKEN_TAX_DESCRIPTION = 'Save 10% on all plans'
const COINTRACKER_DESCRIPTION = 'New and existing users save up to 20%'
function TaxServiceOption({ description, logo, url }: TaxServiceOptionProps) {
const openTaxServiceLink = () => {
window.open(url, '_blank')
}
return (
<TaxOption tabIndex={0}>
<StyledImageContainer as="img" src={logo} draggable={false} />
<TaxOptionDescription className={bodySmall}>{description}</TaxOptionDescription>
<TraceEvent
events={[BrowserEvent.onClick]}
name={SharedEventName.ELEMENT_CLICKED}
element={
url.includes('tokentax')
? InterfaceElementName.TAX_SERVICE_TOKENTAX_BUTTON
: InterfaceElementName.TAX_SERVICE_COINTRACKER_BUTTON
}
>
<Button
size={ButtonSize.medium}
emphasis={ButtonEmphasis.medium}
onClick={openTaxServiceLink}
data-testid="tax-service-option-button"
>
Get started
</Button>
</TraceEvent>
</TaxOption>
)
}
export default memo(function TaxServiceModal({ isOpen, onDismiss }: TaxServiceModalProps) {
return (
<Modal isOpen={isOpen} onDismiss={onDismiss} maxHeight={90} minHeight={false}>
<InnerContainer>
<div style={{ display: 'flex', justifyContent: 'space-between', userSelect: 'none' }}>
<div className={subhead}>
<Trans>Save on your crypto taxes</Trans>
</div>
<StyledXButton size={20} onClick={onDismiss} />
</div>
<TaxOptionContainer>
<TaxServiceOption description={COINTRACKER_DESCRIPTION} logo={CointrackerFullLogo} url={COINTRACKER_URL} />
<TaxServiceOption description={TOKEN_TAX_DESCRIPTION} logo={TokenTaxFullLogo} url={TOKEN_TAX_URL} />
</TaxOptionContainer>
</InnerContainer>
</Modal>
)
})
...@@ -4,4 +4,3 @@ export const LARGE_MEDIA_BREAKPOINT = '840px' ...@@ -4,4 +4,3 @@ export const LARGE_MEDIA_BREAKPOINT = '840px'
export const MEDIUM_MEDIA_BREAKPOINT = '720px' export const MEDIUM_MEDIA_BREAKPOINT = '720px'
export const SMALL_MEDIA_BREAKPOINT = '540px' export const SMALL_MEDIA_BREAKPOINT = '540px'
export const MOBILE_MEDIA_BREAKPOINT = '420px' export const MOBILE_MEDIA_BREAKPOINT = '420px'
// export const SMALL_MOBILE_MEDIA_BREAKPOINT = '390px'
...@@ -2,6 +2,8 @@ import { useWeb3React } from '@web3-react/core' ...@@ -2,6 +2,8 @@ import { useWeb3React } from '@web3-react/core'
import AddressClaimModal from 'components/claim/AddressClaimModal' import AddressClaimModal from 'components/claim/AddressClaimModal'
import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked' import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
import FiatOnrampModal from 'components/FiatOnrampModal' import FiatOnrampModal from 'components/FiatOnrampModal'
import TaxServiceBanner from 'components/TaxServiceModal/TaxServiceBanner'
import { useTaxServiceBannerEnabled } from 'featureFlags/flags/taxServiceBanner'
import useAccountRiskCheck from 'hooks/useAccountRiskCheck' import useAccountRiskCheck from 'hooks/useAccountRiskCheck'
import { lazy } from 'react' import { lazy } from 'react'
import { useModalIsOpen, useToggleModal } from 'state/application/hooks' import { useModalIsOpen, useToggleModal } from 'state/application/hooks'
...@@ -18,6 +20,7 @@ export default function TopLevelModals() { ...@@ -18,6 +20,7 @@ export default function TopLevelModals() {
const { account } = useWeb3React() const { account } = useWeb3React()
useAccountRiskCheck(account) useAccountRiskCheck(account)
const accountBlocked = Boolean(blockedAccountModalOpen && account) const accountBlocked = Boolean(blockedAccountModalOpen && account)
const taxServiceEnabled = useTaxServiceBannerEnabled()
return ( return (
<> <>
...@@ -27,6 +30,7 @@ export default function TopLevelModals() { ...@@ -27,6 +30,7 @@ export default function TopLevelModals() {
<TransactionCompleteModal /> <TransactionCompleteModal />
<AirdropModal /> <AirdropModal />
<FiatOnrampModal /> <FiatOnrampModal />
{taxServiceEnabled && <TaxServiceBanner />}
</> </>
) )
} }
...@@ -12,16 +12,14 @@ import { SupportedChainId } from 'constants/chains' ...@@ -12,16 +12,14 @@ import { SupportedChainId } from 'constants/chains'
import useCopyClipboard from 'hooks/useCopyClipboard' import useCopyClipboard from 'hooks/useCopyClipboard'
import useStablecoinPrice from 'hooks/useStablecoinPrice' import useStablecoinPrice from 'hooks/useStablecoinPrice'
import useNativeCurrency from 'lib/hooks/useNativeCurrency' import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import ms from 'ms.macro'
import { useProfilePageState, useSellAsset, useWalletCollections } from 'nft/hooks' import { useProfilePageState, useSellAsset, useWalletCollections } from 'nft/hooks'
import { useIsNftClaimAvailable } from 'nft/hooks/useIsNftClaimAvailable' import { useIsNftClaimAvailable } from 'nft/hooks/useIsNftClaimAvailable'
import { ProfilePageStateType } from 'nft/types' import { ProfilePageStateType } from 'nft/types'
import { useCallback, useEffect, useMemo, useState } from 'react' import { useCallback, useMemo, useState } from 'react'
import { Copy, CreditCard, ExternalLink as ExternalLinkIcon, Info, Power } from 'react-feather' import { Copy, CreditCard, ExternalLink as ExternalLinkIcon, Info, Power } from 'react-feather'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useCurrencyBalanceString } from 'state/connection/hooks' import { useCurrencyBalanceString } from 'state/connection/hooks'
import { useAppDispatch } from 'state/hooks' import { useAppDispatch } from 'state/hooks'
import { useFiatOnrampAck } from 'state/user/hooks'
import { updateSelectedWallet } from 'state/user/reducer' import { updateSelectedWallet } from 'state/user/reducer'
import styled, { css, keyframes } from 'styled-components/macro' import styled, { css, keyframes } from 'styled-components/macro'
import { ExternalLink, ThemedText } from 'theme' import { ExternalLink, ThemedText } from 'theme'
...@@ -48,7 +46,7 @@ const BuyCryptoButtonBorderKeyframes = keyframes` ...@@ -48,7 +46,7 @@ const BuyCryptoButtonBorderKeyframes = keyframes`
} }
` `
const BuyCryptoButton = styled(ThemeButton)<{ $animateBorder: boolean }>` const BuyCryptoButton = styled(ThemeButton)`
border-color: transparent; border-color: transparent;
border-radius: 12px; border-radius: 12px;
border-style: solid; border-style: solid;
...@@ -60,7 +58,6 @@ const BuyCryptoButton = styled(ThemeButton)<{ $animateBorder: boolean }>` ...@@ -60,7 +58,6 @@ const BuyCryptoButton = styled(ThemeButton)<{ $animateBorder: boolean }>`
animation-fill-mode: none; animation-fill-mode: none;
animation-iteration-count: 2; animation-iteration-count: 2;
animation-name: ${BuyCryptoButtonBorderKeyframes}; animation-name: ${BuyCryptoButtonBorderKeyframes};
animation-play-state: ${({ $animateBorder }) => ($animateBorder ? 'running' : 'paused')};
animation-timing-function: ${({ theme }) => theme.transition.timing.inOut}; animation-timing-function: ${({ theme }) => theme.transition.timing.inOut};
` `
const WalletButton = styled(ThemeButton)` const WalletButton = styled(ThemeButton)`
...@@ -223,26 +220,6 @@ const AuthenticatedHeader = () => { ...@@ -223,26 +220,6 @@ const AuthenticatedHeader = () => {
closeModal() closeModal()
}, [clearCollectionFilters, closeModal, navigate, resetSellAssets, setSellPageState]) }, [clearCollectionFilters, closeModal, navigate, resetSellAssets, setSellPageState])
// animate the border of the buy crypto button when a user navigates here from the feature announcement
// can be removed when components/FiatOnrampAnnouncment.tsx is no longer used
const [acknowledgements, acknowledge] = useFiatOnrampAck()
const animateBuyCryptoButtonBorder = acknowledgements?.user && !acknowledgements.system
useEffect(() => {
let stale = false
let timeoutId = 0
if (animateBuyCryptoButtonBorder) {
timeoutId = setTimeout(() => {
if (stale) return
acknowledge({ system: true })
}, ms`2 seconds`) as unknown as number
// as unknown as number is necessary so it's not incorrectly typed as a NodeJS.Timeout
}
return () => {
stale = true
clearTimeout(timeoutId)
}
}, [acknowledge, animateBuyCryptoButtonBorder])
const openFiatOnrampModal = useOpenModal(ApplicationModal.FIAT_ONRAMP) const openFiatOnrampModal = useOpenModal(ApplicationModal.FIAT_ONRAMP)
const openFoRModalWithAnalytics = useCallback(() => { const openFoRModalWithAnalytics = useCallback(() => {
sendAnalyticsEvent(InterfaceEventName.FIAT_ONRAMP_WIDGET_OPENED) sendAnalyticsEvent(InterfaceEventName.FIAT_ONRAMP_WIDGET_OPENED)
...@@ -314,7 +291,6 @@ const AuthenticatedHeader = () => { ...@@ -314,7 +291,6 @@ const AuthenticatedHeader = () => {
<Trans>View and sell NFTs</Trans> <Trans>View and sell NFTs</Trans>
</ProfileButton> </ProfileButton>
<BuyCryptoButton <BuyCryptoButton
$animateBorder={animateBuyCryptoButtonBorder}
size={ButtonSize.medium} size={ButtonSize.medium}
emphasis={ButtonEmphasis.medium} emphasis={ButtonEmphasis.medium}
onClick={handleBuyCryptoClick} onClick={handleBuyCryptoClick}
......
...@@ -2,7 +2,6 @@ import { t, Trans } from '@lingui/macro' ...@@ -2,7 +2,6 @@ import { t, Trans } from '@lingui/macro'
import { sendAnalyticsEvent, TraceEvent } from '@uniswap/analytics' import { sendAnalyticsEvent, TraceEvent } from '@uniswap/analytics'
import { BrowserEvent, InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' import { BrowserEvent, InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { FiatOnrampAnnouncement } from 'components/FiatOnrampAnnouncement'
import { IconWrapper } from 'components/Identicon/StatusIcon' import { IconWrapper } from 'components/Identicon/StatusIcon'
import WalletDropdown from 'components/WalletDropdown' import WalletDropdown from 'components/WalletDropdown'
import { getConnection } from 'connection/utils' import { getConnection } from 'connection/utils'
...@@ -318,7 +317,6 @@ export default function Web3Status() { ...@@ -318,7 +317,6 @@ export default function Web3Status() {
return ( return (
<span ref={ref}> <span ref={ref}>
<Web3StatusInner /> <Web3StatusInner />
<FiatOnrampAnnouncement />
<WalletModal ENSName={ENSName ?? undefined} pendingTransactions={pending} confirmedTransactions={confirmed} /> <WalletModal ENSName={ENSName ?? undefined} pendingTransactions={pending} confirmedTransactions={confirmed} />
<Portal> <Portal>
<span ref={walletRef}> <span ref={walletRef}>
......
...@@ -9,4 +9,5 @@ export enum FeatureFlag { ...@@ -9,4 +9,5 @@ export enum FeatureFlag {
gqlRouting = 'gqlRouting', gqlRouting = 'gqlRouting',
statsigDummy = 'web_dummy_gate_amplitude_id', statsigDummy = 'web_dummy_gate_amplitude_id',
nftGraphql = 'nft_graphql_migration', nftGraphql = 'nft_graphql_migration',
taxService = 'tax_service_banner',
} }
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
export function useTaxServiceBannerFlag(): BaseVariant {
return useBaseFlag(FeatureFlag.taxService, BaseVariant.Control)
}
export function useTaxServiceBannerEnabled(): boolean {
return useTaxServiceBannerFlag() === BaseVariant.Enabled
}
export { BaseVariant as TaxServiceVariant }
...@@ -17,7 +17,6 @@ import { AppState } from '../types' ...@@ -17,7 +17,6 @@ import { AppState } from '../types'
import { import {
addSerializedPair, addSerializedPair,
addSerializedToken, addSerializedToken,
updateFiatOnrampAcknowledgments,
updateHideClosedPositions, updateHideClosedPositions,
updateUserClientSideRouter, updateUserClientSideRouter,
updateUserDarkMode, updateUserDarkMode,
...@@ -104,26 +103,6 @@ export function useExpertModeManager(): [boolean, () => void] { ...@@ -104,26 +103,6 @@ export function useExpertModeManager(): [boolean, () => void] {
return [expertMode, toggleSetExpertMode] return [expertMode, toggleSetExpertMode]
} }
interface FiatOnrampAcknowledgements {
renderCount: number
system: boolean
user: boolean
}
export function useFiatOnrampAck(): [
FiatOnrampAcknowledgements,
(acknowledgements: Partial<FiatOnrampAcknowledgements>) => void
] {
const dispatch = useAppDispatch()
const fiatOnrampAcknowledgments = useAppSelector((state) => state.user.fiatOnrampAcknowledgments)
const setAcknowledgements = useCallback(
(acks: Partial<FiatOnrampAcknowledgements>) => {
dispatch(updateFiatOnrampAcknowledgments(acks))
},
[dispatch]
)
return [fiatOnrampAcknowledgments, setAcknowledgements]
}
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] { export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
......
...@@ -82,12 +82,6 @@ const userSlice = createSlice({ ...@@ -82,12 +82,6 @@ const userSlice = createSlice({
name: 'user', name: 'user',
initialState, initialState,
reducers: { reducers: {
updateFiatOnrampAcknowledgments(
state,
{ payload }: { payload: Partial<{ renderCount: number; user: boolean; system: boolean }> }
) {
state.fiatOnrampAcknowledgments = { ...state.fiatOnrampAcknowledgments, ...payload }
},
updateSelectedWallet(state, { payload: { wallet } }) { updateSelectedWallet(state, { payload: { wallet } }) {
state.selectedWallet = wallet state.selectedWallet = wallet
}, },
...@@ -181,7 +175,6 @@ const userSlice = createSlice({ ...@@ -181,7 +175,6 @@ const userSlice = createSlice({
export const { export const {
addSerializedPair, addSerializedPair,
addSerializedToken, addSerializedToken,
updateFiatOnrampAcknowledgments,
updateSelectedWallet, updateSelectedWallet,
updateHideClosedPositions, updateHideClosedPositions,
updateMatchesDarkMode, updateMatchesDarkMode,
......
...@@ -198,7 +198,7 @@ export const lightTheme: Theme = { ...@@ -198,7 +198,7 @@ export const lightTheme: Theme = {
accentFailure: colors.red400, accentFailure: colors.red400,
accentCritical: colors.red400, accentCritical: colors.red400,
accentActionSoft: opacify(24, colors.pink400), accentActionSoft: opacify(12, colors.pink400),
accentActiveSoft: opacify(24, colors.blue400), accentActiveSoft: opacify(24, colors.blue400),
accentSuccessSoft: opacify(24, colors.green300), accentSuccessSoft: opacify(24, colors.green300),
accentWarningSoft: opacify(24, colors.gold200), accentWarningSoft: opacify(24, colors.gold200),
......
...@@ -4989,10 +4989,10 @@ ...@@ -4989,10 +4989,10 @@
"@typescript-eslint/types" "5.47.0" "@typescript-eslint/types" "5.47.0"
eslint-visitor-keys "^3.3.0" eslint-visitor-keys "^3.3.0"
"@uniswap/analytics-events@^2.5.1": "@uniswap/analytics-events@^2.6.0":
version "2.5.1" version "2.6.0"
resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-2.5.1.tgz#26095391518954dd3c1248703b3996f07f034579" resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-2.6.0.tgz#c6d21830f46b450f7f633d2c8e832d3531c00f24"
integrity sha512-CkatfcWlKZFIQat+/j53AuxhpVntwrgizBYiUgnxcjVQ0Qh87XrCFqgwfTq44QD5bYwgbYjjw263MXujdEqUYg== integrity sha512-8+El5RKKKs9CXRwRaIZ5t4onlnaTOZThBeO+vSTdr1KtYLp/updtwTR59wE7Yjb5Hj5I6OVKJwiPqAHxja/H4Q==
"@uniswap/analytics@^1.3.1": "@uniswap/analytics@^1.3.1":
version "1.3.1" version "1.3.1"
......
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