feat: add query param to disable the nft sections of the app (#6225)
* feat: add queryparam to disable the nft sections of the app * fix * include mini portfolio * add comments explaining nft disable atom usage and suggesting future work * add subtitle exception to landing page and correct the bool * update comment * comment syntax nits
This commit is contained in:
parent
a0f20c54d8
commit
048607080c
@ -6,6 +6,7 @@ import { useMGTMMicrositeEnabled } from 'featureFlags/flags/mgtm'
|
|||||||
import { chainIdToBackendName } from 'graphql/data/util'
|
import { chainIdToBackendName } from 'graphql/data/util'
|
||||||
import { useIsNftPage } from 'hooks/useIsNftPage'
|
import { useIsNftPage } from 'hooks/useIsNftPage'
|
||||||
import { useIsPoolsPage } from 'hooks/useIsPoolsPage'
|
import { useIsPoolsPage } from 'hooks/useIsPoolsPage'
|
||||||
|
import { useAtomValue } from 'jotai/utils'
|
||||||
import { Box } from 'nft/components/Box'
|
import { Box } from 'nft/components/Box'
|
||||||
import { Row } from 'nft/components/Flex'
|
import { Row } from 'nft/components/Flex'
|
||||||
import { UniIcon } from 'nft/components/icons'
|
import { UniIcon } from 'nft/components/icons'
|
||||||
@ -13,6 +14,7 @@ import { useProfilePageState } from 'nft/hooks'
|
|||||||
import { ProfilePageStateType } from 'nft/types'
|
import { ProfilePageStateType } from 'nft/types'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import { NavLink, NavLinkProps, useLocation, useNavigate } from 'react-router-dom'
|
import { NavLink, NavLinkProps, useLocation, useNavigate } from 'react-router-dom'
|
||||||
|
import { shouldDisableNFTRoutesAtom } from 'state/application/atoms'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
|
|
||||||
import { Bag } from './Bag'
|
import { Bag } from './Bag'
|
||||||
@ -60,6 +62,8 @@ export const PageTabs = () => {
|
|||||||
const isNftPage = useIsNftPage()
|
const isNftPage = useIsNftPage()
|
||||||
const micrositeEnabled = useMGTMMicrositeEnabled()
|
const micrositeEnabled = useMGTMMicrositeEnabled()
|
||||||
|
|
||||||
|
const shouldDisableNFTRoutes = useAtomValue(shouldDisableNFTRoutesAtom)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MenuItem href="/swap" isActive={pathname.startsWith('/swap')}>
|
<MenuItem href="/swap" isActive={pathname.startsWith('/swap')}>
|
||||||
@ -68,9 +72,11 @@ export const PageTabs = () => {
|
|||||||
<MenuItem href={`/tokens/${chainName.toLowerCase()}`} isActive={pathname.startsWith('/tokens')}>
|
<MenuItem href={`/tokens/${chainName.toLowerCase()}`} isActive={pathname.startsWith('/tokens')}>
|
||||||
<Trans>Tokens</Trans>
|
<Trans>Tokens</Trans>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem dataTestId="nft-nav" href="/nfts" isActive={isNftPage}>
|
{!shouldDisableNFTRoutes && (
|
||||||
<Trans>NFTs</Trans>
|
<MenuItem dataTestId="nft-nav" href="/nfts" isActive={isNftPage}>
|
||||||
</MenuItem>
|
<Trans>NFTs</Trans>
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
<Box display={{ sm: 'flex', lg: 'none', xxl: 'flex' }} width="full">
|
<Box display={{ sm: 'flex', lg: 'none', xxl: 'flex' }} width="full">
|
||||||
<MenuItem href="/pools" dataTestId="pool-nav-link" isActive={isPoolActive}>
|
<MenuItem href="/pools" dataTestId="pool-nav-link" isActive={isPoolActive}>
|
||||||
<Trans>Pools</Trans>
|
<Trans>Pools</Trans>
|
||||||
|
@ -12,12 +12,14 @@ import { formatDelta } from 'components/Tokens/TokenDetails/PriceChart'
|
|||||||
import Tooltip from 'components/Tooltip'
|
import Tooltip from 'components/Tooltip'
|
||||||
import { useGetConnection } from 'connection'
|
import { useGetConnection } from 'connection'
|
||||||
import { usePortfolioBalancesQuery } from 'graphql/data/__generated__/types-and-hooks'
|
import { usePortfolioBalancesQuery } from 'graphql/data/__generated__/types-and-hooks'
|
||||||
|
import { useAtomValue } from 'jotai/utils'
|
||||||
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, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
import { ArrowDownRight, ArrowUpRight, Copy, CreditCard, IconProps, Info, Power, Settings } from 'react-feather'
|
import { ArrowDownRight, ArrowUpRight, Copy, CreditCard, IconProps, Info, Power, Settings } from 'react-feather'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { shouldDisableNFTRoutesAtom } from 'state/application/atoms'
|
||||||
import { useAppDispatch } from 'state/hooks'
|
import { useAppDispatch } from 'state/hooks'
|
||||||
import { updateSelectedWallet } from 'state/user/reducer'
|
import { updateSelectedWallet } from 'state/user/reducer'
|
||||||
import styled, { useTheme } from 'styled-components/macro'
|
import styled, { useTheme } from 'styled-components/macro'
|
||||||
@ -166,6 +168,8 @@ export default function AuthenticatedHeader({ account, openSettings }: { account
|
|||||||
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
|
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
|
||||||
const isClaimAvailable = useIsNftClaimAvailable((state) => state.isClaimAvailable)
|
const isClaimAvailable = useIsNftClaimAvailable((state) => state.isClaimAvailable)
|
||||||
|
|
||||||
|
const shouldDisableNFTRoutes = useAtomValue(shouldDisableNFTRoutesAtom)
|
||||||
|
|
||||||
const unclaimedAmount: CurrencyAmount<Token> | undefined = useUserUnclaimedAmount(account)
|
const unclaimedAmount: CurrencyAmount<Token> | undefined = useUserUnclaimedAmount(account)
|
||||||
const isUnclaimed = useUserHasAvailableClaim(account)
|
const isUnclaimed = useUserHasAvailableClaim(account)
|
||||||
const getConnection = useGetConnection()
|
const getConnection = useGetConnection()
|
||||||
@ -302,14 +306,16 @@ export default function AuthenticatedHeader({ account, openSettings }: { account
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</HeaderButton>
|
</HeaderButton>
|
||||||
<HeaderButton
|
{!shouldDisableNFTRoutes && (
|
||||||
data-testid="nft-view-self-nfts"
|
<HeaderButton
|
||||||
onClick={navigateToProfile}
|
data-testid="nft-view-self-nfts"
|
||||||
size={ButtonSize.medium}
|
onClick={navigateToProfile}
|
||||||
emphasis={ButtonEmphasis.medium}
|
size={ButtonSize.medium}
|
||||||
>
|
emphasis={ButtonEmphasis.medium}
|
||||||
<Trans>View and sell NFTs</Trans>
|
>
|
||||||
</HeaderButton>
|
<Trans>View and sell NFTs</Trans>
|
||||||
|
</HeaderButton>
|
||||||
|
)}
|
||||||
{Boolean(!fiatOnrampAvailable && fiatOnrampAvailabilityChecked) && (
|
{Boolean(!fiatOnrampAvailable && fiatOnrampAvailabilityChecked) && (
|
||||||
<FiatOnrampNotAvailableText marginTop="8px">
|
<FiatOnrampNotAvailableText marginTop="8px">
|
||||||
<Trans>Not available in your region</Trans>
|
<Trans>Not available in your region</Trans>
|
||||||
|
@ -5,7 +5,9 @@ import Column from 'components/Column'
|
|||||||
import { AutoRow } from 'components/Row'
|
import { AutoRow } from 'components/Row'
|
||||||
import { useMiniPortfolioEnabled } from 'featureFlags/flags/miniPortfolio'
|
import { useMiniPortfolioEnabled } from 'featureFlags/flags/miniPortfolio'
|
||||||
import { useIsNftPage } from 'hooks/useIsNftPage'
|
import { useIsNftPage } from 'hooks/useIsNftPage'
|
||||||
|
import { useAtomValue } from 'jotai/utils'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import { shouldDisableNFTRoutesAtom } from 'state/application/atoms'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { ThemedText } from 'theme'
|
import { ThemedText } from 'theme'
|
||||||
|
|
||||||
@ -75,27 +77,31 @@ const Pages: Array<Page> = [
|
|||||||
function MiniPortfolio({ account }: { account: string }) {
|
function MiniPortfolio({ account }: { account: string }) {
|
||||||
const isNftPage = useIsNftPage()
|
const isNftPage = useIsNftPage()
|
||||||
const [currentPage, setCurrentPage] = useState(isNftPage ? 1 : 0)
|
const [currentPage, setCurrentPage] = useState(isNftPage ? 1 : 0)
|
||||||
|
const shouldDisableNFTRoutes = useAtomValue(shouldDisableNFTRoutesAtom)
|
||||||
|
|
||||||
const Page = Pages[currentPage].component
|
const Page = Pages[currentPage].component
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<Nav>
|
<Nav>
|
||||||
{Pages.map(({ title }, index) => (
|
{Pages.map(({ title, loggingElementName }, index) => {
|
||||||
<TraceEvent
|
if (shouldDisableNFTRoutes && loggingElementName.includes('nft')) return null
|
||||||
events={[BrowserEvent.onClick]}
|
return (
|
||||||
name={SharedEventName.NAVBAR_CLICKED}
|
<TraceEvent
|
||||||
element={Pages[index].loggingElementName}
|
events={[BrowserEvent.onClick]}
|
||||||
key={index}
|
name={SharedEventName.NAVBAR_CLICKED}
|
||||||
>
|
element={loggingElementName}
|
||||||
<NavItem
|
key={index}
|
||||||
onClick={() => setCurrentPage(index)}
|
|
||||||
active={currentPage === index}
|
|
||||||
key={`Mini Portfolio page ${index}`}
|
|
||||||
>
|
>
|
||||||
{title}
|
<NavItem
|
||||||
</NavItem>
|
onClick={() => setCurrentPage(index)}
|
||||||
</TraceEvent>
|
active={currentPage === index}
|
||||||
))}
|
key={`Mini Portfolio page ${index}`}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</NavItem>
|
||||||
|
</TraceEvent>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</Nav>
|
</Nav>
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
<Page account={account} />
|
<Page account={account} />
|
||||||
|
@ -6,9 +6,11 @@ import TopLevelModals from 'components/TopLevelModals'
|
|||||||
import { useFeatureFlagsIsLoaded } from 'featureFlags'
|
import { useFeatureFlagsIsLoaded } from 'featureFlags'
|
||||||
import { useMGTMMicrositeEnabled } from 'featureFlags/flags/mgtm'
|
import { useMGTMMicrositeEnabled } from 'featureFlags/flags/mgtm'
|
||||||
import ApeModeQueryParamReader from 'hooks/useApeModeQueryParamReader'
|
import ApeModeQueryParamReader from 'hooks/useApeModeQueryParamReader'
|
||||||
|
import { useAtom } from 'jotai'
|
||||||
import { useBag } from 'nft/hooks/useBag'
|
import { useBag } from 'nft/hooks/useBag'
|
||||||
import { lazy, Suspense, useEffect, useMemo, useState } from 'react'
|
import { lazy, Suspense, useEffect, useMemo, useState } from 'react'
|
||||||
import { Navigate, Route, Routes, useLocation } from 'react-router-dom'
|
import { Navigate, Route, Routes, useLocation, useSearchParams } from 'react-router-dom'
|
||||||
|
import { shouldDisableNFTRoutesAtom } from 'state/application/atoms'
|
||||||
import { StatsigProvider, StatsigUser } from 'statsig-react'
|
import { StatsigProvider, StatsigUser } from 'statsig-react'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { SpinnerSVG } from 'theme/components'
|
import { SpinnerSVG } from 'theme/components'
|
||||||
@ -132,6 +134,7 @@ const LazyLoadSpinner = () => (
|
|||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const isLoaded = useFeatureFlagsIsLoaded()
|
const isLoaded = useFeatureFlagsIsLoaded()
|
||||||
|
const [shouldDisableNFTRoutes, setShouldDisableNFTRoutes] = useAtom(shouldDisableNFTRoutesAtom)
|
||||||
|
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const currentPage = getCurrentPageFromLocation(pathname)
|
const currentPage = getCurrentPageFromLocation(pathname)
|
||||||
@ -146,6 +149,15 @@ export default function App() {
|
|||||||
setScrolledState(false)
|
setScrolledState(false)
|
||||||
}, [pathname])
|
}, [pathname])
|
||||||
|
|
||||||
|
const [searchParams] = useSearchParams()
|
||||||
|
useEffect(() => {
|
||||||
|
if (searchParams.get('disableNFTs') === 'true') {
|
||||||
|
setShouldDisableNFTRoutes(true)
|
||||||
|
} else if (searchParams.get('disableNFTs') === 'false') {
|
||||||
|
setShouldDisableNFTRoutes(false)
|
||||||
|
}
|
||||||
|
}, [searchParams, setShouldDisableNFTRoutes])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// User properties *must* be set before sending corresponding event properties,
|
// User properties *must* be set before sending corresponding event properties,
|
||||||
// so that the event contains the correct and up-to-date user properties.
|
// so that the event contains the correct and up-to-date user properties.
|
||||||
@ -271,46 +283,54 @@ export default function App() {
|
|||||||
<Route path="migrate/v2" element={<MigrateV2 />} />
|
<Route path="migrate/v2" element={<MigrateV2 />} />
|
||||||
<Route path="migrate/v2/:address" element={<MigrateV2Pair />} />
|
<Route path="migrate/v2/:address" element={<MigrateV2Pair />} />
|
||||||
|
|
||||||
<Route
|
{!shouldDisableNFTRoutes && (
|
||||||
path="/nfts"
|
<>
|
||||||
element={
|
<Route
|
||||||
<Suspense fallback={null}>
|
path="/nfts"
|
||||||
<NftExplore />
|
element={
|
||||||
</Suspense>
|
<Suspense fallback={null}>
|
||||||
}
|
<NftExplore />
|
||||||
/>
|
</Suspense>
|
||||||
<Route
|
}
|
||||||
path="/nfts/asset/:contractAddress/:tokenId"
|
/>
|
||||||
element={
|
|
||||||
<Suspense fallback={null}>
|
<Route
|
||||||
<Asset />
|
path="/nfts/asset/:contractAddress/:tokenId"
|
||||||
</Suspense>
|
element={
|
||||||
}
|
<Suspense fallback={null}>
|
||||||
/>
|
<Asset />
|
||||||
<Route
|
</Suspense>
|
||||||
path="/nfts/profile"
|
}
|
||||||
element={
|
/>
|
||||||
<Suspense fallback={null}>
|
|
||||||
<Profile />
|
<Route
|
||||||
</Suspense>
|
path="/nfts/profile"
|
||||||
}
|
element={
|
||||||
/>
|
<Suspense fallback={null}>
|
||||||
<Route
|
<Profile />
|
||||||
path="/nfts/collection/:contractAddress"
|
</Suspense>
|
||||||
element={
|
}
|
||||||
<Suspense fallback={null}>
|
/>
|
||||||
<Collection />
|
|
||||||
</Suspense>
|
<Route
|
||||||
}
|
path="/nfts/collection/:contractAddress"
|
||||||
/>
|
element={
|
||||||
<Route
|
<Suspense fallback={null}>
|
||||||
path="/nfts/collection/:contractAddress/activity"
|
<Collection />
|
||||||
element={
|
</Suspense>
|
||||||
<Suspense fallback={null}>
|
}
|
||||||
<Collection />
|
/>
|
||||||
</Suspense>
|
|
||||||
}
|
<Route
|
||||||
/>
|
path="/nfts/collection/:contractAddress/activity"
|
||||||
|
element={
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<Collection />
|
||||||
|
</Suspense>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<Route path="*" element={<Navigate to="/not-found" replace />} />
|
<Route path="*" element={<Navigate to="/not-found" replace />} />
|
||||||
<Route path="/not-found" element={<NotFound />} />
|
<Route path="/not-found" element={<NotFound />} />
|
||||||
|
@ -7,12 +7,14 @@ import { MAIN_CARDS, MORE_CARDS } from 'components/About/constants'
|
|||||||
import ProtocolBanner from 'components/About/ProtocolBanner'
|
import ProtocolBanner from 'components/About/ProtocolBanner'
|
||||||
import { BaseButton } from 'components/Button'
|
import { BaseButton } from 'components/Button'
|
||||||
import { useSwapWidgetEnabled } from 'featureFlags/flags/swapWidget'
|
import { useSwapWidgetEnabled } from 'featureFlags/flags/swapWidget'
|
||||||
|
import { useAtomValue } from 'jotai/utils'
|
||||||
import Swap from 'pages/Swap'
|
import Swap from 'pages/Swap'
|
||||||
import { parse } from 'qs'
|
import { parse } from 'qs'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { ArrowDownCircle } from 'react-feather'
|
import { ArrowDownCircle } from 'react-feather'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { Link as NativeLink } from 'react-router-dom'
|
import { Link as NativeLink } from 'react-router-dom'
|
||||||
|
import { shouldDisableNFTRoutesAtom } from 'state/application/atoms'
|
||||||
import { useAppSelector } from 'state/hooks'
|
import { useAppSelector } from 'state/hooks'
|
||||||
import styled, { css } from 'styled-components/macro'
|
import styled, { css } from 'styled-components/macro'
|
||||||
import { BREAKPOINTS } from 'theme'
|
import { BREAKPOINTS } from 'theme'
|
||||||
@ -316,6 +318,8 @@ export default function Landing() {
|
|||||||
}
|
}
|
||||||
}, [navigate, selectedWallet, queryParams.intro])
|
}, [navigate, selectedWallet, queryParams.intro])
|
||||||
|
|
||||||
|
const shouldDisableNFTRoutes = useAtomValue(shouldDisableNFTRoutesAtom)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Trace page={InterfacePageName.LANDING_PAGE} shouldLogImpression>
|
<Trace page={InterfacePageName.LANDING_PAGE} shouldLogImpression>
|
||||||
{showContent && (
|
{showContent && (
|
||||||
@ -342,9 +346,21 @@ export default function Landing() {
|
|||||||
<Glow />
|
<Glow />
|
||||||
</GlowContainer>
|
</GlowContainer>
|
||||||
<ContentContainer isDarkMode={isDarkMode}>
|
<ContentContainer isDarkMode={isDarkMode}>
|
||||||
<TitleText isDarkMode={isDarkMode}>Trade crypto & NFTs with confidence</TitleText>
|
<TitleText isDarkMode={isDarkMode}>
|
||||||
|
{shouldDisableNFTRoutes ? (
|
||||||
|
<Trans>Trade crypto with confidence</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>Trade crypto and NFTs with confidence</Trans>
|
||||||
|
)}
|
||||||
|
</TitleText>
|
||||||
<SubTextContainer>
|
<SubTextContainer>
|
||||||
<SubText>Buy, sell, and explore tokens and NFTs</SubText>
|
<SubText>
|
||||||
|
{shouldDisableNFTRoutes ? (
|
||||||
|
<Trans>Buy, sell, and explore tokens</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>Buy, sell, and explore tokens and NFTs</Trans>
|
||||||
|
)}
|
||||||
|
</SubText>
|
||||||
</SubTextContainer>
|
</SubTextContainer>
|
||||||
<ActionsContainer>
|
<ActionsContainer>
|
||||||
<TraceEvent
|
<TraceEvent
|
||||||
|
14
src/state/application/atoms.ts
Normal file
14
src/state/application/atoms.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { atomWithStorage, createJSONStorage } from 'jotai/utils'
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note:
|
||||||
|
We should consider a generic sessionStorage abstraction if this pattern becomes common. (i.e., Future promo dismissals like the tax service discounts or Fiat Onramp launch notification may use this.)
|
||||||
|
This would be something similar to the current feature flag implementation, but utilizing session instead
|
||||||
|
|
||||||
|
Motivation:
|
||||||
|
some dapp browsers need to be able to disable the NFT portion of the app in order to pass Apple's app store review
|
||||||
|
this atom persists the inclusion of the `disableNFTs=boolean` query parameter via the webview's session storage
|
||||||
|
*/
|
||||||
|
const storage = createJSONStorage(() => sessionStorage)
|
||||||
|
|
||||||
|
export const shouldDisableNFTRoutesAtom = atomWithStorage('shouldDisableNFTRoutes', false, storage)
|
Loading…
Reference in New Issue
Block a user