Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Commit

Permalink
[Claim] check other chains for claimable amts + click to change netwo…
Browse files Browse the repository at this point in the history
…rks (#2313)

* create updater

* add actions/reducers

* hooks

* add updater

* export type

* make component

* update chains

* useChangeNetwork hook

* add claims banner to claim modal

* styles

* banner styles and change network hook

* fix showing claim on same chain

* [Fixes] Fixes for #2313  (#2318)

* saving

* fix modals and broken network change

* remove debug code

* [CLAIM] Fixes consumed claims check for other chains (#2320)

* check consumed claims using modded hooks

* number > SupportedChainId

* Claim check other chains fixes (#2330)

* use NotificationBanner instead of PhishAlert

* styles

* fix toggleWalletModal broken (#2332)
  • Loading branch information
W3stside authored Jan 27, 2022
1 parent 918b4ad commit 0aa36e0
Show file tree
Hide file tree
Showing 11 changed files with 326 additions and 117 deletions.
81 changes: 14 additions & 67 deletions src/custom/components/Header/NetworkSelector/NetworkSelectorMod.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,12 @@ import // ARBITRUM_HELP_CENTER_LINK,
// SupportedL2ChainId,
// SupportedChainId
'@src/constants/chains'
import { supportedChainId } from 'utils/supportedChainId'
import { SupportedChainId, CHAIN_INFO, ALL_SUPPORTED_CHAIN_IDS } from 'constants/chains'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import { useActiveWeb3React } from 'hooks/web3'
import { useCallback, useRef, useEffect, useState, useMemo } from 'react'
import { CHAIN_INFO, ALL_SUPPORTED_CHAIN_IDS } from 'constants/chains'
import { /* ArrowDownCircle, */ ChevronDown } from 'react-feather'
import { useModalOpen, useToggleModal, useWalletModalToggle } from 'state/application/hooks'
import { ApplicationModal } from 'state/application/reducer'
import { useAppSelector } from 'state/hooks'
import styled from 'styled-components/macro'
import { /* ExternalLink, */ MEDIA_WIDTHS } from 'theme'
import { switchToNetwork } from 'utils/switchToNetwork'
import { UnsupportedChainIdError, useWeb3React } from '@web3-react/core'
import useChangeNetworks from 'hooks/useChangeNetworks'
import { useActiveWeb3React } from 'hooks/web3'

// const ActiveRowLinkList = styled.div`
// display: flex;
Expand Down Expand Up @@ -174,63 +167,17 @@ const StyledChevronDown = styled(ChevronDown)`
// }

export default function NetworkSelector() {
const { chainId: preChainId, library, account } = useActiveWeb3React()
const { error } = useWeb3React() // MOD: check unsupported network
const node = useRef<HTMLDivElement>()
const open = useModalOpen(ApplicationModal.NETWORK_SELECTOR)
const toggle = useToggleModal(ApplicationModal.NETWORK_SELECTOR)
const toggleWalletModal = useWalletModalToggle() // MOD
useOnClickOutside(node, open ? toggle : undefined)
const implements3085 = useAppSelector((state) => state.application.implements3085)

// MOD: checks if a requested network switch was sent
// used for when user disconnected and selects a network internally
// if 3085 supported, will connect wallet and change network
const [queuedNetworkSwitch, setQueuedNetworkSwitch] = useState<null | number>(null)

// MOD: get supported chain and check unsupported
const [chainId, isUnsupportedChain] = useMemo(() => {
const chainId = supportedChainId(preChainId)

return [chainId, error instanceof UnsupportedChainIdError] // Mod - return if chainId is unsupported
}, [preChainId, error])

const info = chainId ? CHAIN_INFO[chainId] : undefined

// const isOnL2 = chainId ? L2_CHAIN_IDS.includes(chainId) : false
// const showSelector = Boolean(!account || implements3085 || isOnL2)
const showSelector = Boolean(!account || implements3085)
const mainnetInfo = CHAIN_INFO[SupportedChainId.MAINNET]

const conditionalToggle = useCallback(() => {
if (showSelector) {
toggle()
}
}, [showSelector, toggle])

const networkCallback = useCallback(
(supportedChainId) => {
if (!account) {
toggleWalletModal()
return setQueuedNetworkSwitch(supportedChainId)
} else if (implements3085 && library && supportedChainId) {
switchToNetwork({ library, chainId: supportedChainId })
return open && toggle()
}

return
},
[account, implements3085, library, open, toggle, toggleWalletModal]
)

// MOD: used with mod hook - used to connect disconnected wallet to selected network
// if wallet supports 3085
useEffect(() => {
if (queuedNetworkSwitch && account && chainId && implements3085) {
networkCallback(queuedNetworkSwitch)
setQueuedNetworkSwitch(null)
}
}, [networkCallback, queuedNetworkSwitch, chainId, account, implements3085])
const { account, chainId, library } = useActiveWeb3React()
const {
callback: networkCallback,
conditionalToggle,
chainInfo: info,
mainnetInfo,
isUnsupportedChain,
showSelector,
nodeRef: node,
isModalOpen: open,
} = useChangeNetworks({ account, chainId, library })

if (!chainId || !info || !library || isUnsupportedChain) {
return null
Expand Down
1 change: 1 addition & 0 deletions src/custom/components/NotificationBanner/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Level = 'info' | 'warning' | 'error'

export interface BannerProps {
children: React.ReactNode
className?: string
level: Level
isVisible: boolean
id?: string
Expand Down
94 changes: 94 additions & 0 deletions src/custom/hooks/useChangeNetworks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { UnsupportedChainIdError, useWeb3React } from '@web3-react/core'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import { useActiveWeb3React } from 'hooks/web3'
import { useAppSelector } from 'state/hooks'
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
import { switchToNetwork } from 'utils/switchToNetwork'
import { supportedChainId } from 'utils/supportedChainId'
import { useWalletModalToggle } from '../state/application/hooks'

type ChangeNetworksParams = Pick<ReturnType<typeof useActiveWeb3React>, 'account' | 'chainId' | 'library'>

export default function useChangeNetworks({ account, chainId: preChainId, library }: ChangeNetworksParams) {
const { error } = useWeb3React() // MOD: check unsupported network
const nodeRef = useRef<HTMLDivElement>()

const [localOpen, setLocalOpen] = useState(false)
const isModalOpen = localOpen

const toggleWalletModal = useWalletModalToggle()
const closeModal = useCallback(() => setLocalOpen(false), [])
const openModal = useCallback(() => setLocalOpen(true), [])
const toggleModal = useCallback(() => {
if (isModalOpen) {
closeModal()
} else {
openModal()
}
}, [closeModal, isModalOpen, openModal])

useOnClickOutside(nodeRef, isModalOpen ? closeModal : undefined)

const implements3085 = useAppSelector((state) => state.application.implements3085)

// MOD: get supported chain and check unsupported
const [chainId, isUnsupportedChain] = useMemo(() => {
const chainId = supportedChainId(preChainId)

return [chainId, error instanceof UnsupportedChainIdError] // Mod - return if chainId is unsupported
}, [preChainId, error])

const info = chainId ? CHAIN_INFO[chainId] : undefined

const showSelector = Boolean(!account || implements3085)
const mainnetInfo = CHAIN_INFO[SupportedChainId.MAINNET]

const conditionalToggle = useCallback(() => {
if (showSelector) {
toggleModal()
}
}, [showSelector, toggleModal])

// MOD: checks if a requested network switch was sent
// used for when user disconnected and selects a network internally
// if 3085 supported, will connect wallet and change network
const [queuedNetworkSwitch, setQueuedNetworkSwitch] = useState<null | number>(null)

const networkCallback = useCallback(
(supportedChainId) => {
if (!account) {
toggleWalletModal()
return setQueuedNetworkSwitch(supportedChainId)
} else if (implements3085 && library && supportedChainId) {
switchToNetwork({ library, chainId: supportedChainId })

return isModalOpen && closeModal()
}

return
},
[account, implements3085, library, toggleWalletModal, isModalOpen, closeModal]
)

// if wallet supports 3085
useEffect(() => {
if (queuedNetworkSwitch && account && chainId && implements3085) {
networkCallback(queuedNetworkSwitch)
setQueuedNetworkSwitch(null)
}
}, [networkCallback, queuedNetworkSwitch, chainId, account, implements3085])

return {
callback: networkCallback,
conditionalToggle,
openModal,
closeModal,
isModalOpen,
isUnsupportedChain,
chainInfo: info,
mainnetInfo,
showSelector,
nodeRef,
}
}
95 changes: 95 additions & 0 deletions src/custom/pages/Claim/ClaimsOnOtherChainsBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useMemo } from 'react'
import styled from 'styled-components/macro'
import { NETWORK_LABELS, SupportedChainId } from 'constants/chains'
import { useClaimState } from 'state/claim/hooks'
import useChangeNetworks from 'hooks/useChangeNetworks'
import { useActiveWeb3React } from 'hooks/web3'
import NotificationBanner from '@src/custom/components/NotificationBanner'
import { AlertTriangle } from 'react-feather'

const ChainSpan = styled.span``
const Wrapper = styled.div`
display: flex;
align-items: center;
justify-content: center;
margin: auto;
flex-flow: row wrap;
> svg {
margin-right: 5px;
}
> div {
flex: 1 1 auto;
&:last-child {
> span {
margin-left: 4px;
font-weight: 600;
white-space: nowrap;
cursor: pointer;
text-decoration: underline;
&:last-child {
&:after {
content: '!';
}
}
&:not(:last-child) {
&:after {
content: ',';
}
}
}
}
}
`

function ClaimsOnOtherChainsBanner({ className }: { className?: string }) {
const { account, library, chainId } = useActiveWeb3React()
const { callback } = useChangeNetworks({ account, library, chainId })

const { hasClaimsOnOtherChains } = useClaimState()
const chainsWithClaims: SupportedChainId[] = useMemo(
() =>
Object.keys(hasClaimsOnOtherChains).reduce((acc, chain) => {
const checkedChain = chain as unknown as SupportedChainId
const chainHasClaim = hasClaimsOnOtherChains[checkedChain]
if (!chainHasClaim || checkedChain == chainId) return acc

acc.push(checkedChain)
return acc
}, [] as SupportedChainId[]),
[chainId, hasClaimsOnOtherChains]
)

if (chainsWithClaims.length === 0) {
return null
}

return (
<NotificationBanner className={className} isVisible id={account ?? undefined} level="info">
<Wrapper>
<AlertTriangle />
<div>You have other available claims on</div>
<div>
{chainsWithClaims.map((chainId, index, array) => {
const changeNetworksCallback = () => callback(chainId)
const isLastInMultiple = index === array.length - 1 && array.length > 1
return (
<>
{isLastInMultiple && ' and'}
<ChainSpan key={chainId} onClick={changeNetworksCallback}>
{NETWORK_LABELS[chainId]}
</ChainSpan>
</>
)
})}
</div>
</Wrapper>
</NotificationBanner>
)
}

export default styled(ClaimsOnOtherChainsBanner)``
Loading

0 comments on commit 0aa36e0

Please sign in to comment.