import React, { useState, useEffect } from 'react' import ReactGA from 'react-ga' import styled from 'styled-components' import { isMobile } from 'react-device-detect' import { UnsupportedChainIdError, useWeb3React } from '@web3-react/core' import usePrevious from '../../hooks/usePrevious' import { useWalletModalOpen, useWalletModalToggle } from '../../state/application/hooks' import Modal from '../Modal' import AccountDetails from '../AccountDetails' import PendingView from './PendingView' import Option from './Option' import { SUPPORTED_WALLETS } from '../../constants' import { ExternalLink } from '../../theme' import MetamaskIcon from '../../assets/images/metamask.png' import { ReactComponent as Close } from '../../assets/images/x.svg' import { injected, fortmatic, portis } from '../../connectors' import { OVERLAY_READY } from '../../connectors/Fortmatic' import { WalletConnectConnector } from '@web3-react/walletconnect-connector' import { AbstractConnector } from '@web3-react/abstract-connector' const CloseIcon = styled.div` position: absolute; right: 1rem; top: 14px; &:hover { cursor: pointer; opacity: 0.6; } ` const CloseColor = styled(Close)` path { stroke: ${({ theme }) => theme.text4}; } ` const Wrapper = styled.div` ${({ theme }) => theme.flexColumnNoWrap} margin: 0; padding: 0; width: 100%; ` const HeaderRow = styled.div` ${({ theme }) => theme.flexRowNoWrap}; padding: 1rem 1rem; font-weight: 500; color: ${props => (props.color === 'blue' ? ({ theme }) => theme.primary1 : 'inherit')}; ${({ theme }) => theme.mediaWidth.upToMedium` padding: 1rem; `}; ` const ContentWrapper = styled.div` background-color: ${({ theme }) => theme.bg2}; padding: 2rem; border-bottom-left-radius: 20px; border-bottom-right-radius: 20px; ${({ theme }) => theme.mediaWidth.upToMedium`padding: 1rem`}; ` const UpperSection = styled.div` position: relative; h5 { margin: 0; margin-bottom: 0.5rem; font-size: 1rem; font-weight: 400; } h5:last-child { margin-bottom: 0px; } h4 { margin-top: 0; font-weight: 500; } ` const Blurb = styled.div` ${({ theme }) => theme.flexRowNoWrap} align-items: center; justify-content: center; flex-wrap: wrap; margin-top: 2rem; ${({ theme }) => theme.mediaWidth.upToMedium` margin: 1rem; font-size: 12px; `}; ` const OptionGrid = styled.div` display: grid; grid-gap: 10px; ${({ theme }) => theme.mediaWidth.upToMedium` grid-template-columns: 1fr; grid-gap: 10px; `}; ` const HoverText = styled.div` :hover { cursor: pointer; } ` const WALLET_VIEWS = { OPTIONS: 'options', OPTIONS_SECONDARY: 'options_secondary', ACCOUNT: 'account', PENDING: 'pending' } export default function WalletModal({ pendingTransactions, confirmedTransactions, ENSName }: { pendingTransactions: string[] // hashes of pending confirmedTransactions: string[] // hashes of confirmed ENSName?: string }) { const { active, account, connector, activate, error } = useWeb3React() const [walletView, setWalletView] = useState(WALLET_VIEWS.ACCOUNT) const [pendingWallet, setPendingWallet] = useState() const [pendingError, setPendingError] = useState() const walletModalOpen = useWalletModalOpen() const toggleWalletModal = useWalletModalToggle() const previousAccount = usePrevious(account) // close on connection, when logged out before useEffect(() => { if (account && !previousAccount && walletModalOpen) { toggleWalletModal() } }, [account, previousAccount, toggleWalletModal, walletModalOpen]) // always reset to account view useEffect(() => { if (walletModalOpen) { setPendingError(false) setWalletView(WALLET_VIEWS.ACCOUNT) } }, [walletModalOpen]) // close modal when a connection is successful const activePrevious = usePrevious(active) const connectorPrevious = usePrevious(connector) useEffect(() => { if (walletModalOpen && ((active && !activePrevious) || (connector && connector !== connectorPrevious && !error))) { setWalletView(WALLET_VIEWS.ACCOUNT) } }, [setWalletView, active, error, connector, walletModalOpen, activePrevious, connectorPrevious]) const tryActivation = async (connector: AbstractConnector | undefined) => { let name = '' Object.keys(SUPPORTED_WALLETS).map(key => { if (connector === SUPPORTED_WALLETS[key].connector) { return (name = SUPPORTED_WALLETS[key].name) } return true }) // log selected wallet ReactGA.event({ category: 'Wallet', action: 'Change Wallet', label: name }) setPendingWallet(connector) // set wallet for pending view setWalletView(WALLET_VIEWS.PENDING) // if the connector is walletconnect and the user has already tried to connect, manually reset the connector if (connector instanceof WalletConnectConnector && connector.walletConnectProvider?.wc?.uri) { connector.walletConnectProvider = undefined } connector && activate(connector, undefined, true).catch(error => { if (error instanceof UnsupportedChainIdError) { activate(connector) // a little janky...can't use setError because the connector isn't set } else { setPendingError(true) } }) } // close wallet modal if fortmatic modal is active useEffect(() => { fortmatic.on(OVERLAY_READY, () => { toggleWalletModal() }) }, [toggleWalletModal]) // get wallets user can switch too, depending on device/browser function getOptions() { const isMetamask = window.ethereum && window.ethereum.isMetaMask return Object.keys(SUPPORTED_WALLETS).map(key => { const option = SUPPORTED_WALLETS[key] // check for mobile options if (isMobile) { //disable portis on mobile for now if (option.connector === portis) { return null } if (!window.web3 && !window.ethereum && option.mobile) { return (