Add network list dropdown in UI (#330)

This commit is contained in:
Gerardo Nardelli 2020-05-18 17:39:39 -03:00 committed by GitHub
parent 62f9a080c9
commit d3576f5a79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 271 additions and 40 deletions

@ -24,3 +24,4 @@
@import "components/mobile-menu";
@import "components/mobile-menu-button";
@import "components/social-icons";
@import "components/NetworkSelect";

@ -0,0 +1,164 @@
.NetworkSelect {
display: flex;
@media (min-width: $tablet-width) {
position: relative;
margin-left: 10px;
&:hover {
.NetworkSelect_List {
display: block;
}
}
}
}
.sw-Header_Content .NetworkSelect {
display: none;
@media (min-width: $tablet-width) {
display: flex;
}
}
.NetworkSelect_Top {
display: flex;
align-items: center;
opacity: 1;
transition: .15s ease-in;
height: 50px;
width: 100%;
justify-content: center;
cursor: pointer;
@media screen and (max-width: $mobile-width) {
height: 20px;
}
&:hover {
opacity: 1;
@media (min-width: $tablet-width) {
.nl-IconNetwork_Arrow {
transform: rotate(180deg);
}
}
}
}
.nl-NavigationLinks_Link.opacityFull {
opacity: 1;
flex-direction: column;
height: auto !important;
}
.nl-IconNetwork_Arrow {
margin-left: 10px;
transition: .15s ease-in;
path {
fill: #fff;
opacity: .52;
}
}
.NetworkSelect_List {
z-index: 999;
list-style: none;
padding-left: 0;
width: 100%;
margin: 0;
@media (min-width: $tablet-width) {
display: none;
position: absolute;
top: 100%;
right: 0;
background-color: #fff;
width: 160px;
border-radius: 4px 0 4px 4px;
box-shadow: 0 5px 10px rgba(#000, .05);
padding-top: 8px;
padding-bottom: 8px;
}
li.currentNetwork {
@media (max-width: $tablet-width) {
display: none;
}
}
button {
display: flex;
width: 100%;
align-items: center;
justify-content: center;
text-decoration: none;
color: #fff;
transition: .15s ease-in;
height: 50px;
background-color: transparent;
border: none;
cursor: pointer;
@media (min-width: $tablet-width) {
padding: 8px 18px;
height: auto;
color: $text-color;
justify-content: flex-start;
&:hover {
background-color: #f7f7f7;
}
}
}
}
.nl-NavigationLinks {
display: flex;
.hd-MobileMenuLinks & {
align-items: center;
flex-direction: column;
margin-bottom: 10px;
}
}
.nl-NavigationLinks_Link {
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
user-select: none;
align-items: center;
color: #fff;
display: flex;
font-weight: bold;
height: 18px;
line-height: 18px;
margin-left: 0;
opacity: 0.7;
text-decoration: none;
transition: opacity ease-in 0.15s, background-color ease-in 0.15s;
&:active,
&:hover,
&.active {
opacity: 1;
}
&.active {
cursor: default;
pointer-events: none;
}
.hd-MobileMenuLinks & {
display: flex;
flex-grow: 1;
height: 50px;
justify-content: center;
width: 100%;
}
@media (min-width: $tablet-width) {
margin-left: 10px;
}
}
.nl-NavigationLinks_Text {
margin-left: 10px;
text-decoration: none;
}
.nl-IconNetwork_Path {
fill: #60db97;
}

@ -2,7 +2,6 @@
align-items: center;
display: flex;
justify-content: space-between;
max-width: 700px;
@media screen and (max-width: $mobile-width) {
display: none;
}
@ -10,4 +9,4 @@
justify-content: flex-end;
width: auto;
}
}
}

@ -23,4 +23,4 @@
path {
fill: $header-menu-icon-color;
}
}
}

@ -1,7 +1,7 @@
.mobile-menu {
@media screen and (max-width: $mobile-width) {
background-color: $mobile-menu-background-color;
height: 172px;
height: 272px;
}
}
@ -30,4 +30,4 @@
min-height: 100%;
position: fixed;
width: 100%;
}
}

@ -19,7 +19,6 @@ import { toDecimals } from '../stores/utils/decimals'
@observer
export class Bridge extends React.Component {
state = {
reverse: false,
amount: '',
modalData: {},
confirmationData: {},
@ -38,25 +37,6 @@ export class Bridge extends React.Component {
web3Store.getWeb3Promise.then(() => {
if (!web3Store.metamaskNet.id || !web3Store.foreignNet.id) {
this.forceUpdate()
} else {
const reverse = web3Store.metamaskNet.id.toString() === web3Store.foreignNet.id.toString()
if (reverse) {
this.setState({
reverse
})
}
}
})
}
componentDidUpdate() {
const { web3Store } = this.props.RootStore
web3Store.getWeb3Promise.then(() => {
const reverse = web3Store.metamaskNet.id.toString() === web3Store.foreignNet.id.toString()
if (reverse !== this.state.reverse) {
this.setState({
reverse
})
}
})
}
@ -202,7 +182,7 @@ export class Bridge extends React.Component {
return
}
const { reverse } = this.state
const { reverse } = web3Store
const homeDisplayName = homeStore.networkName
const foreignDisplayName = foreignStore.networkName
@ -230,8 +210,8 @@ export class Bridge extends React.Component {
}
onTransferConfirmation = async () => {
const { alertStore } = this.props.RootStore
const { reverse } = this.state
const { alertStore, web3Store } = this.props.RootStore
const { reverse } = web3Store
this.setState({ showConfirmation: false, confirmationData: {} })
const amount = this.state.amount.trim()
@ -333,7 +313,8 @@ export class Bridge extends React.Component {
render() {
const { web3Store, foreignStore, homeStore } = this.props.RootStore
const { reverse, showModal, modalData, showConfirmation, confirmationData } = this.state
const { showModal, modalData, showConfirmation, confirmationData } = this.state
const { reverse } = web3Store
const formCurrency = reverse ? foreignStore.symbol : homeStore.symbol
if (showModal && Object.keys(modalData).length !== 0) {

@ -30,7 +30,7 @@ export class DailyQuotaModal extends React.Component {
const { web3Store, homeStore, foreignStore } = this.props.RootStore
const { left, top } = this.state
const isHome = web3Store.metamaskNet.id.toString() === web3Store.homeNet.id.toString()
const isHome = web3Store.isSelectedNetwork(web3Store.homeNet.id)
const value = isHome ? homeStore.maxCurrentDeposit : foreignStore.maxCurrentDeposit
const limit = isHome ? homeStore.maxPerTx : foreignStore.maxPerTx
const from = isHome ? homeStore.symbol : foreignStore.symbol

@ -17,7 +17,7 @@ export class Header extends React.Component {
RootStore: { alertStore, web3Store }
} = this.props
const { REACT_APP_UI_HOME_WITHOUT_EVENTS: HOME, REACT_APP_UI_FOREIGN_WITHOUT_EVENTS: FOREIGN } = process.env
const withoutEvents = web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
const withoutEvents = web3Store.isSelectedNetwork(web3Store.homeNet.id) ? yn(HOME) : yn(FOREIGN)
return (
<header className="header">

@ -1,10 +1,12 @@
import React from 'react'
import { MenuItems } from './MenuItems'
import { Wallet } from './Wallet'
import NetworkSelect from './NetworkSelect'
export const HeaderMenu = ({ withoutEvents }) => (
<div className="header-menu">
<MenuItems withoutEvents={withoutEvents} />
<Wallet />
<NetworkSelect />
</div>
)

@ -1,10 +1,12 @@
import React from 'react'
import { MenuItems } from './MenuItems'
import NetworkSelect from './NetworkSelect'
export const MobileMenu = ({ onMenuToggle, withoutEvents }) => (
<div className="mobile-menu">
<div className="mobile-menu-links">
<MenuItems withoutEvents={withoutEvents} onMenuToggle={onMenuToggle} />
<NetworkSelect />
</div>
</div>
)

@ -0,0 +1,62 @@
import React, { Component } from 'react'
import { inject, observer } from 'mobx-react'
@inject('RootStore')
@observer
export default class NetworkSelect extends Component {
changeNetworkRPC(e) {
const { web3Store } = this.props.RootStore
const newNetworkName = e.target.innerHTML
web3Store.setSelectedNetwork(newNetworkName)
}
render() {
const { web3Store } = this.props.RootStore
let currentNetworkFullName = ''
const networks = web3Store.homeNet.id && web3Store.foreignNet.id ? [web3Store.homeNet, web3Store.foreignNet] : []
let selectedNetworkIndex = -1
networks.forEach((network, i) => {
if (web3Store.isSelectedNetwork(network.id)) {
currentNetworkFullName = network.name
selectedNetworkIndex = i
}
})
if (selectedNetworkIndex === -1) {
selectedNetworkIndex = 0
currentNetworkFullName = networks[0] ? networks[0].name : ''
}
const listItems = networks.map((network, index) => {
let className = ''
if (index === selectedNetworkIndex) {
className = 'currentNetwork'
}
return (
<li key={network.name} className={className}>
<button onClick={e => this.changeNetworkRPC(e)}>{network.name}</button>
</li>
)
})
return (
<div className={`NetworkSelect nl-NavigationLinks_Link opacityFull`}>
<div className={`NetworkSelect_Top`}>
<svg className={`nl-IconNetwork`} xmlns="http://www.w3.org/2000/svg" width="18" height="18">
<path
className={`nl-IconNetwork_Path`}
d="M9 18a9 9 0 0 1-9-9 9 9 0 0 1 9-9 9 9 0 0 1 9 9 9 9 0 0 1-9 9zm6.923-8h-1.974c-.116 1.85-.525 3.539-1.167 4.876A6.993 6.993 0 0 0 15.923 10zM9 16c1.51 0 2.747-2.612 2.957-6H6.043c.21 3.388 1.447 6 2.957 6zm-3.782-1.124C4.576 13.539 4.167 11.85 4.051 10H2.077a6.993 6.993 0 0 0 3.141 4.876zM2.077 8h1.974c.116-1.85.525-3.538 1.167-4.876A6.993 6.993 0 0 0 2.077 8zM9 2C7.49 2 6.253 4.612 6.043 8h5.914C11.747 4.612 10.51 2 9 2zm3.782 1.124C13.424 4.462 13.833 6.15 13.949 8h1.974a6.993 6.993 0 0 0-3.141-4.876z"
/>
</svg>
<span className={`nl-NavigationLinks_Text`}>{currentNetworkFullName}</span>
<svg className={`nl-IconNetwork_Arrow`} xmlns="http://www.w3.org/2000/svg" width="8" height="4">
<path d="M0 0h8L4 4 0 0z" />
</svg>
</div>
<ul className={`NetworkSelect_List`}>{listItems}</ul>
</div>
)
}
}

@ -140,7 +140,7 @@ export class RelayEvents extends React.Component {
const home = this.getHomeEvents(homeStore, foreignStore)
const foreign = this.getForeignEvents(foreignStore, homeStore)
const { REACT_APP_UI_HOME_WITHOUT_EVENTS: HOME, REACT_APP_UI_FOREIGN_WITHOUT_EVENTS: FOREIGN } = process.env
const withoutEvents = web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
const withoutEvents = web3Store.isSelectedNetwork(web3Store.homeNet.id) ? yn(HOME) : yn(FOREIGN)
return withoutEvents ? (
<Redirect to="/" />

@ -17,7 +17,7 @@ export class StatisticsPage extends React.Component {
const leftTitle = isNativeToErc ? 'Deposits' : 'Withdrawals'
const rightTitle = isNativeToErc ? 'Withdrawals' : 'Deposits'
const { REACT_APP_UI_HOME_WITHOUT_EVENTS: HOME, REACT_APP_UI_FOREIGN_WITHOUT_EVENTS: FOREIGN } = process.env
const withoutEvents = web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
const withoutEvents = web3Store.isSelectedNetwork(web3Store.homeNet.id) ? yn(HOME) : yn(FOREIGN)
return withoutEvents ? (
<Redirect to="/" />

@ -9,7 +9,7 @@ import { inject, observer } from 'mobx-react'
export class StatusPage extends React.Component {
render() {
const { homeStore, foreignStore, web3Store } = this.props.RootStore
const isHome = web3Store.metamaskNet.id.toString() === web3Store.homeNet.id.toString()
const isHome = web3Store.isSelectedNetwork(web3Store.homeNet.id)
const requiredSignatures = isHome ? homeStore.requiredSignatures : foreignStore.requiredSignatures
const authorities = isHome ? homeStore.validatorsCount : foreignStore.validatorsCount
const symbol = isHome ? homeStore.symbol : foreignStore.symbol
@ -17,7 +17,7 @@ export class StatusPage extends React.Component {
const maxTotalBalance = isHome ? homeStore.maxCurrentDeposit : foreignStore.maxCurrentDeposit
const validatorsList = isHome ? homeStore.validators : foreignStore.validators
const { REACT_APP_UI_HOME_WITHOUT_EVENTS: HOME, REACT_APP_UI_FOREIGN_WITHOUT_EVENTS: FOREIGN } = process.env
const withoutEvents = web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
const withoutEvents = web3Store.isSelectedNetwork(web3Store.homeNet.id) ? yn(HOME) : yn(FOREIGN)
return (
<div className="status-page">

@ -7,7 +7,7 @@ import { WalletIcon } from './menu-icons/WalletIcon'
export class Wallet extends React.Component {
render() {
const { web3Store, homeStore, foreignStore, alertStore } = this.props.RootStore
const isHome = web3Store.metamaskNet.id.toString() === web3Store.homeNet.id.toString()
const isHome = web3Store.isSelectedNetwork(web3Store.homeNet.id)
const address = web3Store.defaultAccount.address
const explorerAddressUrl = isHome
? homeStore.getExplorerAddressUrl(address)

@ -1,7 +1,8 @@
import { action, observable } from 'mobx'
import { action, computed, observable } from 'mobx'
import getWeb3, { getBalance, getWeb3Instance, getNetwork } from './utils/web3'
import { balanceLoaded } from './utils/testUtils'
import { BRIDGE_MODES } from '../../../commons'
import { toHex } from 'web3-utils'
class Web3Store {
@observable
@ -33,6 +34,9 @@ class Web3Store {
@observable
metamaskNet = { id: '', name: '' }
@observable
selectedNet = { id: '', name: '' }
@observable
walletInstalled = true
@ -145,6 +149,22 @@ class Web3Store {
await this.setHomeWeb3Promise
return this.metamaskNet.id === this.homeNet.id
}
@action
setSelectedNetwork(name) {
const newNetwork = name === this.homeNet.name ? this.homeNet : this.foreignNet
this.selectedNet = newNetwork
}
isSelectedNetwork(id) {
const compareNetwork = this.selectedNet.id ? this.selectedNet : this.metamaskNet
return compareNetwork.id.toString() === id.toString()
}
@computed
get reverse() {
return this.isSelectedNetwork(this.foreignNet.id)
}
}
export default Web3Store

@ -60,11 +60,11 @@ const networks = {
4: 'Rinkeby',
30: 'RSK Mainnet',
31: 'RSK Testnet',
42: 'Kovan',
42: 'Kovan Testnet',
61: 'Ethereum Classic',
77: 'Sokol',
77: 'Sokol Testnet',
99: 'POA Network',
100: 'Dai Chain'
100: 'xDai Chain'
}
export const getNetworkName = id => networks[id] || 'Unknown'