Commit 6f2d6e31 authored by vignesh mohankumar's avatar vignesh mohankumar Committed by GitHub

feat: add "approve in wallet" prompt on chain selector (#4673)

* logic

* working

* grid

* some file renaming

* Move to ChainSelectorRow.tsx

* remove flex

* more renames

* more styles

* fixes

* local imports

* more styling changes

* style

* fix mobile

* toggle open on open

* setIsOpen
parent 944939a2
import { style } from '@vanilla-extract/css' import { style } from '@vanilla-extract/css'
import { lightGrayOverlayOnHover } from 'nft/css/common.css' import { lightGrayOverlayOnHover } from 'nft/css/common.css'
import { breakpoints, sprinkles } from '../../nft/css/sprinkles.css' import { sprinkles } from '../../nft/css/sprinkles.css'
export const ChainSwitcher = style([ export const ChainSelector = style([
lightGrayOverlayOnHover, lightGrayOverlayOnHover,
sprinkles({ sprinkles({
borderRadius: '8', borderRadius: '8',
paddingX: '12',
height: '40', height: '40',
cursor: 'pointer', cursor: 'pointer',
border: 'none', border: 'none',
...@@ -16,38 +15,9 @@ export const ChainSwitcher = style([ ...@@ -16,38 +15,9 @@ export const ChainSwitcher = style([
}), }),
]) ])
export const ChainSwitcherRow = style([
lightGrayOverlayOnHover,
sprinkles({
border: 'none',
justifyContent: 'space-between',
paddingX: '8',
paddingY: '8',
cursor: 'pointer',
color: 'blackBlue',
borderRadius: '12',
width: { sm: 'full' },
}),
{
lineHeight: '24px',
'@media': {
[`screen and (min-width: ${breakpoints.sm}px)`]: {
width: '204px',
},
},
},
])
export const Image = style([ export const Image = style([
sprinkles({ sprinkles({
width: '20', width: '20',
height: '20', height: '20',
}), }),
]) ])
export const Icon = style([
Image,
sprinkles({
marginRight: '12',
}),
])
...@@ -8,46 +8,16 @@ import useSyncChainQuery from 'hooks/useSyncChainQuery' ...@@ -8,46 +8,16 @@ import useSyncChainQuery from 'hooks/useSyncChainQuery'
import { Box } from 'nft/components/Box' import { Box } from 'nft/components/Box'
import { Portal } from 'nft/components/common/Portal' import { Portal } from 'nft/components/common/Portal'
import { Column, Row } from 'nft/components/Flex' import { Column, Row } from 'nft/components/Flex'
import { CheckMarkIcon, TokenWarningRedIcon } from 'nft/components/icons' import { TokenWarningRedIcon } from 'nft/components/icons'
import { subhead } from 'nft/css/common.css' import { subhead } from 'nft/css/common.css'
import { themeVars, vars } from 'nft/css/sprinkles.css' import { themeVars } from 'nft/css/sprinkles.css'
import { useIsMobile } from 'nft/hooks' import { useIsMobile } from 'nft/hooks'
import { ReactNode, useReducer, useRef } from 'react' import { useCallback, useRef, useState } from 'react'
import * as styles from './ChainSwitcher.css' import * as styles from './ChainSelector.css'
import ChainSelectorRow from './ChainSelectorRow'
import { NavDropdown } from './NavDropdown' import { NavDropdown } from './NavDropdown'
const ChainRow = ({
targetChain,
onSelectChain,
}: {
targetChain: SupportedChainId
onSelectChain: (targetChain: number) => void
}) => {
const { chainId } = useWeb3React()
const active = chainId === targetChain
const { label, logoUrl } = getChainInfo(targetChain)
return (
<Column borderRadius="12">
<Row
as="button"
background="none"
className={`${styles.ChainSwitcherRow} ${subhead}`}
onClick={() => onSelectChain(targetChain)}
>
<ChainDetails>
<img src={logoUrl} alt={label} className={styles.Icon} />
{label}
</ChainDetails>
{active && <CheckMarkIcon width={20} height={20} color={vars.color.blue400} />}
</Row>
</Column>
)
}
const ChainDetails = ({ children }: { children: ReactNode }) => <Row>{children}</Row>
const NETWORK_SELECTOR_CHAINS = [ const NETWORK_SELECTOR_CHAINS = [
SupportedChainId.MAINNET, SupportedChainId.MAINNET,
SupportedChainId.POLYGON, SupportedChainId.POLYGON,
...@@ -56,24 +26,36 @@ const NETWORK_SELECTOR_CHAINS = [ ...@@ -56,24 +26,36 @@ const NETWORK_SELECTOR_CHAINS = [
SupportedChainId.CELO, SupportedChainId.CELO,
] ]
interface ChainSwitcherProps { interface ChainSelectorProps {
leftAlign?: boolean leftAlign?: boolean
} }
export const ChainSwitcher = ({ leftAlign }: ChainSwitcherProps) => { export const ChainSelector = ({ leftAlign }: ChainSelectorProps) => {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const [isOpen, toggleOpen] = useReducer((s) => !s, false) const [isOpen, setIsOpen] = useState<boolean>(false)
const isMobile = useIsMobile() const isMobile = useIsMobile()
const ref = useRef<HTMLDivElement>(null) const ref = useRef<HTMLDivElement>(null)
const modalRef = useRef<HTMLDivElement>(null) const modalRef = useRef<HTMLDivElement>(null)
useOnClickOutside(ref, isOpen ? toggleOpen : undefined, [modalRef]) useOnClickOutside(ref, () => setIsOpen(false), [modalRef])
const info = chainId ? getChainInfo(chainId) : undefined const info = chainId ? getChainInfo(chainId) : undefined
const selectChain = useSelectChain() const selectChain = useSelectChain()
useSyncChainQuery() useSyncChainQuery()
const [pendingChainId, setPendingChainId] = useState<SupportedChainId | undefined>(undefined)
const onSelectChain = useCallback(
async (targetChainId: SupportedChainId) => {
setPendingChainId(targetChainId)
await selectChain(targetChainId)
setPendingChainId(undefined)
setIsOpen(false)
},
[selectChain, setIsOpen]
)
if (!chainId) { if (!chainId) {
return null return null
} }
...@@ -82,15 +64,13 @@ export const ChainSwitcher = ({ leftAlign }: ChainSwitcherProps) => { ...@@ -82,15 +64,13 @@ export const ChainSwitcher = ({ leftAlign }: ChainSwitcherProps) => {
const dropdown = ( const dropdown = (
<NavDropdown top="56" left={leftAlign ? '0' : 'auto'} right={leftAlign ? 'auto' : '0'} ref={modalRef}> <NavDropdown top="56" left={leftAlign ? '0' : 'auto'} right={leftAlign ? 'auto' : '0'} ref={modalRef}>
<Column marginX="8"> <Column paddingX="8">
{NETWORK_SELECTOR_CHAINS.map((chainId: SupportedChainId) => ( {NETWORK_SELECTOR_CHAINS.map((chainId: SupportedChainId) => (
<ChainRow <ChainSelectorRow
onSelectChain={async (targetChainId: SupportedChainId) => { onSelectChain={onSelectChain}
await selectChain(targetChainId)
toggleOpen()
}}
targetChain={chainId} targetChain={chainId}
key={chainId} key={chainId}
isPending={chainId === pendingChainId}
/> />
))} ))}
</Column> </Column>
...@@ -102,9 +82,9 @@ export const ChainSwitcher = ({ leftAlign }: ChainSwitcherProps) => { ...@@ -102,9 +82,9 @@ export const ChainSwitcher = ({ leftAlign }: ChainSwitcherProps) => {
<Row <Row
as="button" as="button"
gap="8" gap="8"
className={styles.ChainSwitcher} className={styles.ChainSelector}
background={isOpen ? 'accentActiveSoft' : 'none'} background={isOpen ? 'accentActiveSoft' : 'none'}
onClick={toggleOpen} onClick={() => setIsOpen(!isOpen)}
> >
{!isSupported ? ( {!isSupported ? (
<> <>
......
import { useWeb3React } from '@web3-react/core'
import Loader from 'components/Loader'
import { getChainInfo } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import { CheckMarkIcon } from 'nft/components/icons'
import styled, { useTheme } from 'styled-components/macro'
const LOGO_SIZE = 20
const Container = styled.button`
display: grid;
background: none;
grid-template-columns: min-content 1fr min-content;
align-items: center;
text-align: left;
line-height: 24px;
border: none;
justify-content: space-between;
padding: 10px 8px;
cursor: pointer;
border-radius: 12px;
color: ${({ theme }) => theme.textPrimary};
width: 240px;
transition: ${({ theme }) => theme.transition.duration.medium} ${({ theme }) => theme.transition.timing.ease}
background-color;
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
width: 100%;
}
&:hover {
background-color: ${({ theme }) => theme.backgroundOutline};
}
`
const Label = styled.div`
grid-column: 2;
grid-row: 1;
font-size: 16px;
`
const Status = styled.div`
grid-column: 3;
grid-row: 1;
display: flex;
align-items: center;
width: ${LOGO_SIZE}px;
`
const ApproveText = styled.div`
color: ${({ theme }) => theme.textSecondary};
font-size: 12px;
grid-column: 2;
grid-row: 2;
`
const Logo = styled.img`
height: ${LOGO_SIZE}px;
width: ${LOGO_SIZE}px;
margin-right: 12px;
`
export default function ChainSelectorRow({
targetChain,
onSelectChain,
isPending,
}: {
targetChain: SupportedChainId
onSelectChain: (targetChain: number) => void
isPending: boolean
}) {
const { chainId } = useWeb3React()
const active = chainId === targetChain
const { label, logoUrl } = getChainInfo(targetChain)
const theme = useTheme()
return (
<Container onClick={() => onSelectChain(targetChain)}>
<Logo src={logoUrl} alt={label} />
<Label>{label}</Label>
{isPending && <ApproveText>Approve in wallet</ApproveText>}
<Status>
{active && <CheckMarkIcon width={LOGO_SIZE} height={LOGO_SIZE} color={theme.accentActive} />}
{isPending && <Loader width={LOGO_SIZE} height={LOGO_SIZE} />}
</Status>
</Container>
)
}
import Navbar from './Navbar'
export default Navbar
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { ChainSwitcher } from 'components/NavBar/ChainSwitcher'
import { MenuDropdown } from 'components/NavBar/MenuDropdown'
import * as styles from 'components/NavBar/Navbar.css'
import { SearchBar } from 'components/NavBar/SearchBar'
import { ShoppingBag } from 'components/NavBar/ShoppingBag'
import Web3Status from 'components/Web3Status' import Web3Status from 'components/Web3Status'
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft' import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
import { Box } from 'nft/components/Box' import { Box } from 'nft/components/Box'
...@@ -12,6 +7,12 @@ import { UniIcon } from 'nft/components/icons' ...@@ -12,6 +7,12 @@ import { UniIcon } from 'nft/components/icons'
import { ReactNode } from 'react' import { ReactNode } from 'react'
import { NavLink, NavLinkProps, useLocation } from 'react-router-dom' import { NavLink, NavLinkProps, useLocation } from 'react-router-dom'
import { ChainSelector } from './ChainSelector'
import { MenuDropdown } from './MenuDropdown'
import { SearchBar } from './SearchBar'
import { ShoppingBag } from './ShoppingBag'
import * as styles from './style.css'
interface MenuItemProps { interface MenuItemProps {
href: string href: string
id?: NavLinkProps['id'] id?: NavLinkProps['id']
...@@ -76,7 +77,7 @@ const Navbar = () => { ...@@ -76,7 +77,7 @@ const Navbar = () => {
<UniIcon width="48" height="48" className={styles.logo} /> <UniIcon width="48" height="48" className={styles.logo} />
</Box> </Box>
<Box display={{ sm: 'flex', lg: 'none' }}> <Box display={{ sm: 'flex', lg: 'none' }}>
<ChainSwitcher leftAlign={true} /> <ChainSelector leftAlign={true} />
</Box> </Box>
<Row gap="8" display={{ sm: 'none', lg: 'flex' }}> <Row gap="8" display={{ sm: 'none', lg: 'flex' }}>
<PageTabs /> <PageTabs />
...@@ -95,7 +96,7 @@ const Navbar = () => { ...@@ -95,7 +96,7 @@ const Navbar = () => {
</Box> </Box>
{isNftPage && <ShoppingBag />} {isNftPage && <ShoppingBag />}
<Box display={{ sm: 'none', lg: 'flex' }}> <Box display={{ sm: 'none', lg: 'flex' }}>
<ChainSwitcher /> <ChainSelector />
</Box> </Box>
<Web3Status /> <Web3Status />
......
...@@ -21,7 +21,7 @@ import { useAnalyticsReporter } from '../components/analytics' ...@@ -21,7 +21,7 @@ import { useAnalyticsReporter } from '../components/analytics'
import ErrorBoundary from '../components/ErrorBoundary' import ErrorBoundary from '../components/ErrorBoundary'
import Header from '../components/Header' import Header from '../components/Header'
import Polling from '../components/Header/Polling' import Polling from '../components/Header/Polling'
import Navbar from '../components/NavBar' import NavBar from '../components/NavBar'
import Popups from '../components/Popups' import Popups from '../components/Popups'
import { LoadingTokenDetails } from '../components/Tokens/TokenDetails/LoadingTokenDetails' import { LoadingTokenDetails } from '../components/Tokens/TokenDetails/LoadingTokenDetails'
import { useIsExpertMode } from '../state/user/hooks' import { useIsExpertMode } from '../state/user/hooks'
...@@ -153,7 +153,7 @@ export default function App() { ...@@ -153,7 +153,7 @@ export default function App() {
<ApeModeQueryParamReader /> <ApeModeQueryParamReader />
<AppWrapper> <AppWrapper>
<Trace page={currentPage}> <Trace page={currentPage}>
<HeaderWrapper>{navBarFlag === NavBarVariant.Enabled ? <Navbar /> : <Header />}</HeaderWrapper> <HeaderWrapper>{navBarFlag === NavBarVariant.Enabled ? <NavBar /> : <Header />}</HeaderWrapper>
<BodyWrapper navBarFlag={navBarFlag}> <BodyWrapper navBarFlag={navBarFlag}>
<Popups /> <Popups />
<Polling /> <Polling />
......
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