diff --git a/src/components/NetworkSwitchNotification.jsx b/src/components/NetworkSwitchNotification.jsx new file mode 100644 index 0000000..a162919 --- /dev/null +++ b/src/components/NetworkSwitchNotification.jsx @@ -0,0 +1,29 @@ +import React, { Component } from 'react'; + +class NetworkSwitchNotification extends Component { + render = () => { + return
+
+

You have switched Networks

+
+
+
+ + + + + +
+

+ You are now connected to the
+ {this.props.network} Ethereum Network +

+
+ +
+ } +} + +export default NetworkSwitchNotification; diff --git a/src/components/SetTrade.jsx b/src/components/SetTrade.jsx index 414a2bc..c3ee985 100644 --- a/src/components/SetTrade.jsx +++ b/src/components/SetTrade.jsx @@ -1,20 +1,22 @@ // Libraries import React from "react"; -import {inject, observer} from "mobx-react"; +import { inject, observer } from "mobx-react"; import ReactTooltip from "react-tooltip"; // UI Components -import {SwapArrows, IdentityIcon, Circle, Attention} from "../components-ui/Icons"; +import { SwapArrows, IdentityIcon, Circle, Attention } from "../components-ui/Icons"; import Spinner from "../components-ui/Spinner"; import TokenAmount from "../components-ui/TokenAmount"; import TokensSelector from "../components-ui/TokensSelector"; // Utils -import {toWei} from "../utils/helpers"; +import { toWei } from "../utils/helpers"; // Settings import * as settings from "../settings"; import NetworkIndicator from "./NetworkIndicator"; +import NetworkSwitchNotification from "./NetworkSwitchNotification"; +import { autorun } from "mobx"; @inject("network") @inject("system") @@ -103,7 +105,7 @@ class SetTrade extends React.Component { const amountToBuy = this.amountBuy.value; const whole = amountToBuy.split(".")[0]; const decimals = amountToBuy.split(".")[1]; - if (whole.length <=15 && (!decimals || (decimals && decimals.length <= 18))) { // 18 should be replaced with any token's decimals according to some sort of configuration + if (whole.length <= 15 && (!decimals || (decimals && decimals.length <= 18))) { // 18 should be replaced with any token's decimals according to some sort of configuration this.props.system.calculatePayAmount(this.state.from, this.state.to, amountToBuy); } } @@ -126,180 +128,195 @@ class SetTrade extends React.Component { render() { return ( - this.state.showTokenSelector - ? - this.setState({showTokenSelector: false})} /> - : -
-
+ + { + this.props.network.hasSwitched && + } + { + this.state.showTokenSelector + ? + this.setState({showTokenSelector: false})}/> + : +
+
- + -

Enter Order Details

- +

Enter Order Details

+ -
-
-
- { - this.props.system.trade.errorOrders && !this.props.system.trade.errorInputSell && - +
+
+
+ { + this.props.system.trade.errorOrders && !this.props.system.trade.errorInputSell && + No orders available to {this.props.system.trade.errorOrders.type}  - {this.props.system.trade.errorOrders.amount} {this.props.system.trade.errorOrders.token} + {this.props.system.trade.errorOrders.amount} {this.props.system.trade.errorOrders.token} - } - { - this.props.system.trade.errorInputSell && - ( - this.props.system.trade.errorInputSell === "funds" - ? - You don't have enough {this.props.tokens[this.props.system.trade.from].name} in your Wallet - : - this.props.system.trade.errorInputSell === "gasCost" - ? - You won't have enough ETH to pay for the gas! - : - + } + { + this.props.system.trade.errorInputSell && + ( + this.props.system.trade.errorInputSell === "funds" + ? + You don't have enough {this.props.tokens[this.props.system.trade.from].name} in your Wallet + : + this.props.system.trade.errorInputSell === "gasCost" + ? + You won't have enough ETH to pay for the gas! + : + {this.props.tokens[this.props.system.trade.from].symbol}  - Minimum Value: {this.props.system.trade.errorInputSell.replace("minValue:", "")} + Minimum Value: {this.props.system.trade.errorInputSell.replace("minValue:", "")} - ) - } - { - !this.props.system.trade.errorOrders && !this.props.system.trade.errorInputSell && this.props.system.trade.errorInputBuy && - + ) + } + { + !this.props.system.trade.errorOrders && !this.props.system.trade.errorInputSell && this.props.system.trade.errorInputBuy && + {this.props.tokens[this.props.system.trade.to].symbol}  - Minimum Value: {this.props.system.trade.errorInputBuy.replace("minValue:", "")} + Minimum Value: {this.props.system.trade.errorInputBuy.replace("minValue:", "")} - } - { - !this.props.system.trade.errorOrders && !this.props.system.trade.errorInputSell && !this.props.system.trade.errorInputBuy && - + } + { + !this.props.system.trade.errorOrders && !this.props.system.trade.errorInputSell && !this.props.system.trade.errorInputBuy && + Price - +

The estimated price of your order is calculated based on the current depth of the OasisDEX order book and the size of your order.

- -  ~  + +  ~  - + Slippage Limit - +

The maximum allowed difference between the estimated price of the order and the actual price. The two may differ if the order book changes before your trade executes.

- {settings.chain[this.props.network.network].threshold[[this.state.from, this.state.to].sort((a, b) => a > b).join("")]}% + {settings.chain[this.props.network.network].threshold[[this.state.from, this.state.to].sort((a, b) => a > b).join("")]}%
- + Gas cost - { - this.props.system.trade.txCost.gt(0) - ? - ~ - : - - } + { + this.props.system.trade.txCost.gt(0) + ? + ~ + : + + } - + Price Impact - +

The difference between the best current price on the OasisDEX order book and the estimated price of your order.

- 5 ? "#E53935" : ""}} - className="value">{this.priceImpact()}% + 5 ? "#E53935" : ""}} + className="value">{this.priceImpact()}%
-
- } -
-
-
-
-
-
this.pickToken("from")}> - {this.props.tokens[this.state.from].icon} - { - !this.props.system.balances[this.props.tokens[this.state.from].symbol.toLowerCase()] - ? - - : - + }
-
- this.amountPay = input} - value={this.props.system.trade.amountPayInput || ""} - onChange={this.calculateBuyAmount} placeholder="deposit amount" /> -
-
+
+ +
+
this.pickToken("from")}> + {this.props.tokens[this.state.from].icon} + { + !this.props.system.balances[this.props.tokens[this.state.from].symbol.toLowerCase()] + ? + + : + + } +
+
+ this.amountPay = input} + value={this.props.system.trade.amountPayInput || ""} + onChange={this.calculateBuyAmount} placeholder="deposit amount"/> +
+
+
- + +
+
+
this.pickToken("to")}> + {this.props.tokens[this.state.to].icon} + { + !this.props.system.balances[this.props.tokens[this.state.to].symbol.toLowerCase()] + ? + + : + + } +
+
+ this.amountBuy = input} + value={this.props.system.trade.amountBuyInput || ""} + onChange={this.calculatePayAmount} placeholder="receive amount"/> +
+
+
-
-
this.pickToken("to")}> - {this.props.tokens[this.state.to].icon} - { - !this.props.system.balances[this.props.tokens[this.state.to].symbol.toLowerCase()] - ? - - : - - } -
-
- this.amountBuy = input} - value={this.props.system.trade.amountBuyInput || ""} - onChange={this.calculatePayAmount} placeholder="receive amount" /> -
-
- -
- { - this.hasDetails() && !this.props.system.trade.errorInputSell && !this.props.system.trade.errorInputBuy && !this.props.system.trade.errorOrders && -
-
+ { + this.hasDetails() && !this.props.system.trade.errorInputSell && !this.props.system.trade.errorInputBuy && !this.props.system.trade.errorOrders && +
+ -
- } - -
+
+ + } + +
+ } + ) } } diff --git a/src/index.css b/src/index.css index c236e9b..200da0d 100644 --- a/src/index.css +++ b/src/index.css @@ -4,6 +4,7 @@ @import 'styles/NoAccount.css'; @import 'styles/Responsive.css'; @import 'styles/NetworkIndicator.css'; +@import 'styles/NetworkSwitchNotification.css'; body { margin: 0; diff --git a/src/stores/Network.jsx b/src/stores/Network.jsx index da3022f..8ddc942 100644 --- a/src/stores/Network.jsx +++ b/src/stores/Network.jsx @@ -1,5 +1,5 @@ // Libraries -import {observable} from "mobx"; +import {observable, action} from "mobx"; // Utils import * as blockchain from "../utils/blockchain"; @@ -13,6 +13,7 @@ export default class NetworkStore { @observable isConnected = false; @observable latestBlock = null; @observable network = ""; + @observable hasSwitched = false; @observable outOfSync = true; @observable isHw = false; @observable hw = {active: false, showSelector: false, option: null, derivationPath: null, addresses: [], loading: false, error: null}; @@ -22,9 +23,15 @@ export default class NetworkStore { this.rootStore = rootStore; } - setNetwork = async () => { + @action setNetwork = async () => { try { const result = await blockchain.checkNetwork(this.isConnected, this.network); + + //This is useful to catch when the user changed the network. + if(this.network && this.result.data.network !== this.network) { + this.hasSwitched = true; + } + Object.keys(result.data).forEach(key => { this[key] = result.data[key]; }); if (!this.stopIntervals && result.status) { this.setAccount(); @@ -37,6 +44,10 @@ export default class NetworkStore { } } + @action ackNetworkSwitch =() => { + this.hasSwitched = false; + }; + stopNetwork = () => { this.stopIntervals = true; blockchain.stopProvider(); @@ -73,6 +84,7 @@ export default class NetworkStore { }, () => {}); } + // Web3 web client setWeb3WebClient = async () => { try { diff --git a/src/styles/App.css b/src/styles/App.css index ed8db26..b31f447 100644 --- a/src/styles/App.css +++ b/src/styles/App.css @@ -168,6 +168,11 @@ margin-top: auto; } +.frame.network-switch-notification { + position: absolute; + z-index: 2; +} + .frame > .info-box.more-info { justify-content: space-evenly; order: 4; diff --git a/src/styles/NetworkSwitchNotification.css b/src/styles/NetworkSwitchNotification.css new file mode 100644 index 0000000..0337548 --- /dev/null +++ b/src/styles/NetworkSwitchNotification.css @@ -0,0 +1,36 @@ +/* + This is to make the button always at the bottom of the frame. + The logic for doing this is duplicated and implemented in various places. + Most likely should be extracted as common class i.e. `button.bottom` +*/ +.network-switch-notification button { + margin-top: auto; +} + +.network-switch-notification .content { + display: flex; + align-items: center; + justify-content: space-evenly; + flex-direction: column; + + border: 1px solid #F7F7F8; + border-radius: 4px; + + height: 284px; + + margin-top: 24px; +} + +.network-switch-notification p { + opacity: 0.9; + font-family: "Montserrat", sans-serif; + font-weight: 500; + font-size: 14px; + color: #5B5B5C; + letter-spacing: 1px; + text-align: center; +} + +.network-switch-notification strong { + font-weight: 600; +} \ No newline at end of file