Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: replace layout modals #1040

Merged
merged 4 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React from 'react'

import { ChainId } from '@dcl/schemas/dist/dapps/chain-id'
import WalletSelectorModal from 'decentraland-gatsby/dist/components/Modal/WalletSelectorModal'
import WrongNetworkModal from 'decentraland-gatsby/dist/components/Modal/WrongNetworkModal'
import useAuthContext from 'decentraland-gatsby/dist/context/Auth/useAuthContext'
import { changeLocale } from 'decentraland-gatsby/dist/plugins/intl'
import { DecentralandIntlContext } from 'decentraland-gatsby/dist/plugins/intl/types'
Expand All @@ -13,6 +11,9 @@ import { Navbar, NavbarProps } from 'decentraland-ui/dist/components/Navbar/Navb
import type { PageProps } from 'gatsby'
import type { DropdownProps } from 'semantic-ui-react/dist/commonjs/modules/Dropdown'

import WalletSelectorModal from '../Modal/WalletSelectorModal'
import WrongNetworkModal from '../Modal/WrongNetworkModal'

import './Layout.css'

const CHAIN_ID: ChainId[] = env('GATSBY_DEFAULT_CHAIN_ID', String(ChainId.ETHEREUM_MAINNET))
Expand Down Expand Up @@ -59,13 +60,14 @@ export default function Layout({ children, pageContext, ...props }: LayoutProps)
<main>{children}</main>
<WrongNetworkModal
currentNetwork={state.chainId}
expectedNetwork={getSupportedChainIds()}
expectedNetworks={getSupportedChainIds()}
onSwitchNetwork={(chainId) => state.switchTo(chainId)}
providerType={state.providerType}
/>
<WalletSelectorModal
open={state.selecting}
loading={state.loading}
chainId={getSupportedChainIds()[0]}
error={state.error}
onConnect={(providerType, chainId) => state.connect(providerType, chainId)}
onClose={() => state.select(false)}
Expand Down
18 changes: 18 additions & 0 deletions src/components/Modal/WalletSelectorModal.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.ui.modal.dcl.login-modal {
width: 90%;
max-width: 520px;
}

.ui.modal.dcl.login-modal .content {
margin: 28px 32px;
}

.ui.modal.dcl.login-modal .dcl.option {
width: 100%;
max-width: 360px;
}

.ui.modal.dcl.login-modal small p.dg.Paragraph {
font-size: 13px;
line-height: 1.5;
}
105 changes: 105 additions & 0 deletions src/components/Modal/WalletSelectorModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React, { useCallback, useEffect, useState } from 'react'

import { ChainId } from '@dcl/schemas/dist/dapps/chain-id'
import { ProviderType } from '@dcl/schemas/dist/dapps/provider-type'
import { connection } from 'decentraland-connect/dist/ConnectionManager'
import { toModalOptionType } from 'decentraland-dapps/dist/containers/LoginModal/utils'
import Markdown from 'decentraland-gatsby/dist/components/Text/Markdown'
import { useFeatureFlagContext } from 'decentraland-gatsby/dist/context/FeatureFlag'
import useAnchor from 'decentraland-gatsby/dist/hooks/useAnchor'
import useFormatMessage from 'decentraland-gatsby/dist/hooks/useFormatMessage'
import { Loader } from 'decentraland-ui/dist/components/Loader/Loader'
import { LoginModal, LoginModalOptionType } from 'decentraland-ui/dist/components/LoginModal/LoginModal'
import 'decentraland-ui/dist/components/LoginModal/LoginModal.css'
import { Modal } from 'decentraland-ui/dist/components/Modal/Modal'
import { ModalNavigation } from 'decentraland-ui/dist/components/ModalNavigation/ModalNavigation'
import ModalContent from 'semantic-ui-react/dist/commonjs/modules/Modal/ModalContent'

import './WalletSelectorModal.css'

type Props = {
open: boolean
loading: boolean
chainId: ChainId
error: string | null
onConnect: (providerType: ProviderType, chainId: ChainId) => void
onClose: () => void
}

const availableProviders = new Set(connection.getAvailableProviders())

export default function WalletSelectorModal({ chainId, onConnect, onClose, error, open, loading }: Props) {
const t = useFormatMessage()
const [provider, setProvider] = useState(LoginModalOptionType.METAMASK)
const [ff] = useFeatureFlagContext()

useEffect(() => {
setProvider(toModalOptionType(ProviderType.INJECTED) || LoginModalOptionType.METAMASK)
}, [])

const handleConnect = useCallback(
(providerType: ProviderType, chainId: ChainId) => {
if (onConnect) {
onConnect(providerType, chainId)
}
},
[onConnect]
)

const handleDownloadMetamaskClick = useAnchor('https://metamask.io/download.html')
const handleConnectInjected = useCallback(() => {
if (availableProviders.has(ProviderType.INJECTED)) {
handleConnect(ProviderType.INJECTED, chainId)
} else {
handleDownloadMetamaskClick()
}
}, [handleConnect, handleDownloadMetamaskClick, chainId])
const handleConnectFortmatic = useCallback(
() => handleConnect(ProviderType.FORTMATIC, chainId),
[chainId, handleConnect]
)
const handleConnectWalletConnect = useCallback(
() =>
handleConnect(
ff.enabled('dapps-wallet-connect-v2') ? ProviderType.WALLET_CONNECT_V2 : ProviderType.WALLET_CONNECT,
chainId
),
[ff, chainId, handleConnect]
)
const handleConnectWalletLink = useCallback(
() => handleConnect(ProviderType.WALLET_LINK, chainId),
[chainId, handleConnect]
)

return (
<Modal open={open} className="dcl login-modal">
<ModalNavigation
title={t('modal.wallet_selector.title')}
subtitle={t('modal.wallet_selector.subtitle')}
onClose={onClose}
/>
<ModalContent>
<LoginModal.Option type={provider} onClick={handleConnectInjected} />
{availableProviders.has(ProviderType.FORTMATIC) && (
<LoginModal.Option type={LoginModalOptionType.FORTMATIC} onClick={handleConnectFortmatic} />
)}
{availableProviders.has(ProviderType.WALLET_CONNECT) && (
<LoginModal.Option type={LoginModalOptionType.WALLET_CONNECT} onClick={handleConnectWalletConnect} />
)}
{availableProviders.has(ProviderType.WALLET_LINK) && (
<LoginModal.Option type={LoginModalOptionType.WALLET_LINK} onClick={handleConnectWalletLink} />
)}
<small className="message">
<Markdown>{t('modal.wallet_selector.trezor')}</Markdown>
</small>
</ModalContent>
{error && <p className="error visible">{error}</p>}
{loading ? (
<>
<Loader size="big" active />
<div className="loader-background"></div>
</>
) : null}
</Modal>
)
}
81 changes: 81 additions & 0 deletions src/components/Modal/WrongNetworkModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useMemo } from 'react'

import { ChainId, getChainName } from '@dcl/schemas/dist/dapps/chain-id'
import { ProviderType } from '@dcl/schemas/dist/dapps/provider-type'
import useFormatMessage from 'decentraland-gatsby/dist/hooks/useFormatMessage'
import { Button } from 'decentraland-ui/dist/components/Button/Button'
import { Modal } from 'decentraland-ui/dist/components/Modal/Modal'
import { ModalNavigation } from 'decentraland-ui/dist/components/ModalNavigation/ModalNavigation'

type Props = {
currentNetwork: ChainId | null
expectedNetworks: ChainId[]
onSwitchNetwork: (chainId: ChainId) => void
providerType: ProviderType | null
}

export default function WrongNetworkModal({ currentNetwork, expectedNetworks, onSwitchNetwork, providerType }: Props) {
const t = useFormatMessage()

const isOpen = useMemo(
() => !!currentNetwork && !expectedNetworks.includes(currentNetwork),
[currentNetwork, expectedNetworks]
)

const expectedChainName = useMemo(() => {
switch (expectedNetworks.length) {
case 0:
return <b />
case 1:
return <b>{getChainName(expectedNetworks[0])}</b>
default:
return (
<span>
{expectedNetworks.map((chainId, i, list) => (
<span key={chainId}>
<b>{getChainName(chainId)}</b>
{i === list.length - 1 ? ', ' : t('modal.wrong_network.separator')}
</span>
))}
</span>
)
}
}, [t, expectedNetworks])

const chainName = currentNetwork ? getChainName(currentNetwork) : undefined
const currentChainName = <b>{chainName || t('modal.wrong_network.unknown_chain')}</b>

const allowNetworkSwitch = providerType === ProviderType.INJECTED

return (
<Modal size="tiny" open={isOpen}>
<ModalNavigation title={t('modal.wrong_network.header')} />
<Modal.Content>
{t('modal.wrong_network.message', {
currentChainName,
expectedChainName,
})}
</Modal.Content>
{allowNetworkSwitch && expectedNetworks.length > 0 && (
<Modal.Content>
{expectedNetworks.map((chainId: ChainId, index: number) => {
return (
<Button
fluid
key={chainId}
basic={index !== 0}
primary={index === 0}
style={index === 0 ? {} : { marginTop: '1em' }}
onClick={() => onSwitchNetwork && onSwitchNetwork(chainId)}
>
{t('modal.wrong_network.change_chain', {
expectedChainName: <b>{getChainName(chainId)}</b>,
})}
</Button>
)
})}
</Modal.Content>
)}
</Modal>
)
}
12 changes: 12 additions & 0 deletions src/intl/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,18 @@
"card_description": "Let the world know that you are behind those witty tweets about the Metaverse."
},
"soon": "Soon"
},
"wallet_selector": {
"title": "Sign In",
"subtitle": "Choose a method to connect",
"trezor": "Trezor and smart contract wallets (like Dapper or Argent) cannot interact Polygon. Read more about the Trezor support status [here](https://github.com/trezor/trezor-firmware/pull/1568)"
},
"wrong_network": {
"header": "Wrong Network",
"message": "You need to be connected to {expectedChainName} to use this app, but you are currently connected to {currentChainName}.",
"change_chain": "switch to {expectedChainName}",
"separator": " or ",
"unknown_chain": "Unknown"
}
},
"component": {
Expand Down