From 8a2ad1878de83426bbfc4f2cbb784c65ee1b5644 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Fri, 26 Oct 2018 23:47:41 +0200 Subject: [PATCH 1/4] move Web3 logic out of component --- src/components/Web3Donation/index.jsx | 84 ++++++++++----------------- src/components/Web3Donation/utils.js | 47 ++++++++++++++- 2 files changed, 76 insertions(+), 55 deletions(-) diff --git a/src/components/Web3Donation/index.jsx b/src/components/Web3Donation/index.jsx index d8148c93..3277f31d 100644 --- a/src/components/Web3Donation/index.jsx +++ b/src/components/Web3Donation/index.jsx @@ -1,10 +1,9 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' -import Web3 from 'web3' import InputGroup from './InputGroup' import Alerts from './Alerts' import styles from './index.module.scss' -import { getNetworkName, Logger } from './utils' +import { getWeb3, getAccounts, getNetwork } from './utils' const ONE_SECOND = 1000 const ONE_MINUTE = ONE_SECOND * 60 @@ -12,7 +11,7 @@ const ONE_MINUTE = ONE_SECOND * 60 export default class Web3Donation extends PureComponent { state = { web3Connected: false, - networkId: null, + netId: null, networkName: null, accounts: [], selectedAccount: null, @@ -41,31 +40,13 @@ export default class Web3Donation extends PureComponent { } async initWeb3() { - // Modern dapp browsers... - if (window.ethereum) { - this.web3 = new Web3(window.ethereum) + try { + this.web3 = await getWeb3() - try { - // Request account access - await window.ethereum.enable() - this.setState({ web3Connected: true }) - - this.initAllTheTings() - } catch (error) { - // User denied account access... - Logger.error(error) - this.setState({ error }) - } - } - // Legacy dapp browsers... - else if (window.web3) { - this.web3 = new Web3(window.web3.currentProvider) - this.setState({ web3Connected: true }) - - this.initAllTheTings() - } - // Non-dapp browsers... - else { + this.setState({ web3Connected: this.web3 ? true : false }) + this.web3 && this.initAllTheTings() + } catch (error) { + this.setState({ error }) this.setState({ web3Connected: false }) } } @@ -95,41 +76,36 @@ export default class Web3Donation extends PureComponent { } } - fetchNetwork = () => { + fetchNetwork = async () => { const { web3 } = this - web3 && - web3.eth && - web3.eth.net.getId((err, netId) => { - if (err) this.setState({ error: err }) + try { + const { netId, networkName } = await getNetwork(web3) - if (netId !== this.state.networkId) { - this.setState({ - error: null, - networkId: netId - }) - - getNetworkName(netId).then(networkName => { - this.setState({ networkName }) - }) - } + this.setState({ + error: null, + netId, + networkName }) + } catch (error) { + this.setState({ error }) + } } - fetchAccounts = () => { + fetchAccounts = async () => { const { web3 } = this - web3 && - web3.eth && - web3.eth.getAccounts((err, accounts) => { - if (err) this.setState({ error: err }) + try { + const accounts = await getAccounts(web3) - this.setState({ - error: null, - accounts, - selectedAccount: accounts[0].toLowerCase() - }) + this.setState({ + error: null, + accounts, + selectedAccount: accounts[0] ? accounts[0].toLowerCase() : null }) + } catch (error) { + this.setState({ error }) + } } sendTransaction() { @@ -168,7 +144,7 @@ export default class Web3Donation extends PureComponent { render() { const { - networkId, + netId, accounts, selectedAccount, web3Connected, @@ -181,7 +157,7 @@ export default class Web3Donation extends PureComponent { message } = this.state - const hasCorrectNetwork = networkId === 1 + const hasCorrectNetwork = netId === 1 const hasAccount = accounts.length !== 0 return ( diff --git a/src/components/Web3Donation/utils.js b/src/components/Web3Donation/utils.js index 70430dec..8d430f42 100644 --- a/src/components/Web3Donation/utils.js +++ b/src/components/Web3Donation/utils.js @@ -1,4 +1,49 @@ -export const getNetworkName = async netId => { +import Web3 from 'web3' + +export const getWeb3 = async () => { + let web3 + + // Modern dapp browsers... + if (window.ethereum) { + web3 = new Web3(window.ethereum) + + try { + // Request account access + await window.ethereum.enable() + + return web3 + } catch (error) { + // User denied account access... + Logger.error(error) + return error + } + } + // Legacy dapp browsers... + else if (window.web3) { + web3 = new Web3(window.web3.currentProvider) + + return web3 + } + // Non-dapp browsers... + else { + return + } +} + +export const getAccounts = async web3 => { + const ethAccounts = await web3.eth.getAccounts() + + return ethAccounts +} + +export const getNetwork = async web3 => { + const netId = await web3.eth.net.getId() + const networkName = getNetworkName(netId) + + return { netId, networkName } +} + +export const getNetworkName = netId => { let networkName switch (netId) { From ef78d92f74a3cf1ea1598519725bc051b2c931e2 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Sat, 27 Oct 2018 14:23:06 +0200 Subject: [PATCH 2/4] prototype nicer web3 loading experience --- package.json | 2 +- src/components/Post/PostMeta.module.scss | 2 +- .../Web3Donation/Alerts.module.scss | 4 ++ src/components/Web3Donation/InputGroup.jsx | 12 +++- .../Web3Donation/InputGroup.module.scss | 16 +++++ src/components/Web3Donation/index.jsx | 68 +++++++++++-------- src/components/Web3Donation/index.module.scss | 10 ++- 7 files changed, 79 insertions(+), 35 deletions(-) diff --git a/package.json b/package.json index 6e9d5e31..5a7f9d60 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "@babel/node": "^7.0.0", "@babel/preset-env": "^7.1.0", "babel-eslint": "^10.0.1", - "eslint": "^5.7.0", + "eslint": "^5.8.0", "eslint-config-prettier": "^3.1.0", "eslint-loader": "^2.1.1", "eslint-plugin-graphql": "^2.1.1", diff --git a/src/components/Post/PostMeta.module.scss b/src/components/Post/PostMeta.module.scss index 6c768906..1a600aae 100644 --- a/src/components/Post/PostMeta.module.scss +++ b/src/components/Post/PostMeta.module.scss @@ -4,7 +4,7 @@ ///////////////////////////////////// .entryMeta { - font-size: $font-size-base; + font-size: $font-size-small; margin-top: $spacer * 2; color: $brand-grey-light; } diff --git a/src/components/Web3Donation/Alerts.module.scss b/src/components/Web3Donation/Alerts.module.scss index f5b301e9..857df040 100644 --- a/src/components/Web3Donation/Alerts.module.scss +++ b/src/components/Web3Donation/Alerts.module.scss @@ -5,6 +5,10 @@ margin-top: $spacer / 2; font-size: $font-size-small; color: darken($alert-error, 60%); + + &:empty { + display: none; + } } .success { diff --git a/src/components/Web3Donation/InputGroup.jsx b/src/components/Web3Donation/InputGroup.jsx index ff86c05f..a2c8e38e 100644 --- a/src/components/Web3Donation/InputGroup.jsx +++ b/src/components/Web3Donation/InputGroup.jsx @@ -12,7 +12,9 @@ export default class InputGroup extends PureComponent { amount: PropTypes.string.isRequired, onAmountChange: PropTypes.func.isRequired, handleButton: PropTypes.func.isRequired, - selectedAccount: PropTypes.string + selectedAccount: PropTypes.string, + inTransaction: PropTypes.bool, + message: PropTypes.string } render() { @@ -22,10 +24,14 @@ export default class InputGroup extends PureComponent { amount, onAmountChange, handleButton, - selectedAccount + selectedAccount, + inTransaction, + message } = this.props - return ( + return inTransaction ? ( +
{message}
+ ) : (
{ try { this.web3 = await getWeb3() this.setState({ web3Connected: this.web3 ? true : false }) - this.web3 && this.initAllTheTings() + this.web3 ? this.initAllTheTings() : this.setState({ loading: false }) } catch (error) { this.setState({ error }) this.setState({ web3Connected: false }) } } - initAllTheTings() { - this.fetchAccounts() - this.fetchNetwork() + async initAllTheTings() { + await this.fetchAccounts() + await this.fetchNetwork() + + this.setState({ loading: false }) + this.initAccountsPoll() this.initNetworkPoll() } @@ -85,7 +90,8 @@ export default class Web3Donation extends PureComponent { this.setState({ error: null, netId, - networkName + networkName, + isCorrectNetwork: netId === 1 }) } catch (error) { this.setState({ error }) @@ -123,7 +129,7 @@ export default class Web3Donation extends PureComponent { message: 'Waiting for network confirmation, hang on...' }) }) - .on('error', error => this.setState({ error, loading: false })) + .on('error', error => this.setState({ error, inTransaction: false })) .then(() => { this.setState({ message: 'Confirmed. You are awesome, thanks!' }) }) @@ -131,7 +137,7 @@ export default class Web3Donation extends PureComponent { handleButton = () => { this.setState({ - loading: true, + inTransaction: true, message: 'Waiting for your confirmation...' }) @@ -144,10 +150,11 @@ export default class Web3Donation extends PureComponent { render() { const { - netId, + isCorrectNetwork, accounts, selectedAccount, web3Connected, + inTransaction, loading, amount, networkName, @@ -157,7 +164,6 @@ export default class Web3Donation extends PureComponent { message } = this.state - const hasCorrectNetwork = netId === 1 const hasAccount = accounts.length !== 0 return ( @@ -167,32 +173,36 @@ export default class Web3Donation extends PureComponent {

Send Ether with MetaMask, Brave, or Mist.

- {web3Connected && ( -
- {loading ? ( - message - ) : ( +
+ {loading ? ( +
Checking...
+ ) : ( + web3Connected && ( - )} -
- )} + ) + )} +
- + {!loading && ( + + )}
) } diff --git a/src/components/Web3Donation/index.module.scss b/src/components/Web3Donation/index.module.scss index 194c5c59..f20ea05a 100644 --- a/src/components/Web3Donation/index.module.scss +++ b/src/components/Web3Donation/index.module.scss @@ -18,8 +18,16 @@ } .web3Row { - min-height: 58px; + min-height: 77px; display: flex; align-items: center; justify-content: center; + + &:empty { + display: none; + } +} + +.message { + font-size: $font-size-small; } From 86948a5340731c61a8c23c3f15e2baf0f31aa652 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Sun, 28 Oct 2018 11:16:57 +0100 Subject: [PATCH 3/4] tweaks --- src/components/Web3Donation/Alerts.jsx | 6 +-- src/components/Web3Donation/InputGroup.jsx | 22 +++----- .../Web3Donation/InputGroup.module.scss | 4 +- src/components/Web3Donation/index.jsx | 24 ++++++--- src/components/Web3Donation/index.module.scss | 28 ++++++++++ src/components/Web3Donation/utils.js | 4 +- src/components/atoms/Coinhive.jsx | 5 +- src/components/atoms/Modal.module.scss | 2 +- src/components/atoms/Qr.jsx | 23 ++++++-- src/components/atoms/Qr.module.scss | 54 +++++++++++++++++++ .../molecules/ModalThanks.module.scss | 44 --------------- 11 files changed, 133 insertions(+), 83 deletions(-) create mode 100644 src/components/atoms/Qr.module.scss diff --git a/src/components/Web3Donation/Alerts.jsx b/src/components/Web3Donation/Alerts.jsx index da216a57..3151150a 100644 --- a/src/components/Web3Donation/Alerts.jsx +++ b/src/components/Web3Donation/Alerts.jsx @@ -1,4 +1,4 @@ -import React, { Fragment, PureComponent } from 'react' +import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import styles from './Alerts.module.scss' @@ -42,7 +42,7 @@ export default class Alerts extends PureComponent { {!web3Connected ? ( ) : ( - + <> {!hasAccount && ( )} @@ -58,7 +58,7 @@ export default class Alerts extends PureComponent { message={this.alertMessages(null, transactionHash).transaction} /> )} - + )}
) diff --git a/src/components/Web3Donation/InputGroup.jsx b/src/components/Web3Donation/InputGroup.jsx index a2c8e38e..f5476a0a 100644 --- a/src/components/Web3Donation/InputGroup.jsx +++ b/src/components/Web3Donation/InputGroup.jsx @@ -7,36 +7,30 @@ import styles from './InputGroup.module.scss' export default class InputGroup extends PureComponent { static propTypes = { - hasCorrectNetwork: PropTypes.bool.isRequired, + isCorrectNetwork: PropTypes.bool.isRequired, hasAccount: PropTypes.bool.isRequired, amount: PropTypes.string.isRequired, onAmountChange: PropTypes.func.isRequired, handleButton: PropTypes.func.isRequired, - selectedAccount: PropTypes.string, - inTransaction: PropTypes.bool, - message: PropTypes.string + selectedAccount: PropTypes.string } render() { const { - hasCorrectNetwork, + isCorrectNetwork, hasAccount, amount, onAmountChange, handleButton, - selectedAccount, - inTransaction, - message + selectedAccount } = this.props - return inTransaction ? ( -
{message}
- ) : ( + return (
Make it rain - {hasCorrectNetwork && + {isCorrectNetwork && hasAccount && (
diff --git a/src/components/Web3Donation/InputGroup.module.scss b/src/components/Web3Donation/InputGroup.module.scss index 0dc15dca..06e07cf1 100644 --- a/src/components/Web3Donation/InputGroup.module.scss +++ b/src/components/Web3Donation/InputGroup.module.scss @@ -5,7 +5,7 @@ max-width: 18rem; margin: auto; position: relative; - animation: fadeIn .5s ease-out backwards; + animation: fadeIn .8s ease-out backwards; @media (min-width: $screen-sm) { display: flex; @@ -84,7 +84,7 @@ } .message { - font-size: $font-size-small; + composes: message from './index.module.scss'; } @keyframes fadeIn { diff --git a/src/components/Web3Donation/index.jsx b/src/components/Web3Donation/index.jsx index ce7c3cb1..96c4057f 100644 --- a/src/components/Web3Donation/index.jsx +++ b/src/components/Web3Donation/index.jsx @@ -22,7 +22,8 @@ export default class Web3Donation extends PureComponent { receipt: null, inTransaction: false, error: null, - message: 'Hang on...' + message: 'Hang on', + success: false } static propTypes = { @@ -126,19 +127,22 @@ export default class Web3Donation extends PureComponent { .once('transactionHash', transactionHash => { this.setState({ transactionHash, - message: 'Waiting for network confirmation, hang on...' + message: 'Waiting for network confirmation, hang on' }) }) .on('error', error => this.setState({ error, inTransaction: false })) .then(() => { - this.setState({ message: 'Confirmed. You are awesome, thanks!' }) + this.setState({ + message: 'Confirmed. You are awesome, thanks!', + success: true + }) }) } handleButton = () => { this.setState({ inTransaction: true, - message: 'Waiting for your confirmation...' + message: 'Waiting for your confirmation' }) this.sendTransaction() @@ -161,7 +165,8 @@ export default class Web3Donation extends PureComponent { error, transactionHash, confirmationNumber, - message + message, + success } = this.state const hasAccount = accounts.length !== 0 @@ -175,17 +180,20 @@ export default class Web3Donation extends PureComponent {
{loading ? ( -
Checking...
+
Checking
+ ) : inTransaction ? ( +
+ {message} +
) : ( web3Connected && ( ) diff --git a/src/components/Web3Donation/index.module.scss b/src/components/Web3Donation/index.module.scss index f20ea05a..93743afb 100644 --- a/src/components/Web3Donation/index.module.scss +++ b/src/components/Web3Donation/index.module.scss @@ -30,4 +30,32 @@ .message { font-size: $font-size-small; + position: relative; + + &::after { + overflow: hidden; + display: inline-block; + vertical-align: bottom; + animation: ellipsis steps(4, end) 1s infinite; + content: '\2026'; // ascii code for the ellipsis character + width: 0; + position: absolute; + left: 100%; + bottom: 0; + } +} + +.success { + composes: message; + color: green; + + &::after { + display: none; + } +} + +@keyframes ellipsis { + to { + width: .75rem; + } } diff --git a/src/components/Web3Donation/utils.js b/src/components/Web3Donation/utils.js index 8d430f42..0752d4ff 100644 --- a/src/components/Web3Donation/utils.js +++ b/src/components/Web3Donation/utils.js @@ -74,9 +74,7 @@ export const getFiat = async amount => { try { const response = await fetch(url) - if (!response.ok) { - throw Error(response.statusText) - } + if (!response.ok) Logger.error(response.statusText) const data = await response.json() const { price_usd, price_eur } = data[0] const dollar = (amount * price_usd).toFixed(2) diff --git a/src/components/atoms/Coinhive.jsx b/src/components/atoms/Coinhive.jsx index 1fd7af8f..1f98b6a9 100644 --- a/src/components/atoms/Coinhive.jsx +++ b/src/components/atoms/Coinhive.jsx @@ -33,9 +33,8 @@ export default class CoinHiveClient extends PureComponent { return new Promise(resolve => { loadScript(config.script, error => { - if (error) { - return - } + if (error) return + resolve( window.CoinHive.Anonymous(config.siteKey, { throttle: config.throttle, diff --git a/src/components/atoms/Modal.module.scss b/src/components/atoms/Modal.module.scss index 28ae690b..38535960 100644 --- a/src/components/atoms/Modal.module.scss +++ b/src/components/atoms/Modal.module.scss @@ -8,7 +8,7 @@ left: 0; right: 0; bottom: 0; - z-index: 10; + z-index: 9; background: rgba($body-background-color, .9); // backdrop-filter: blur(5px); animation: fadein .3s; diff --git a/src/components/atoms/Qr.jsx b/src/components/atoms/Qr.jsx index 6f3b0202..d65e9f3c 100644 --- a/src/components/atoms/Qr.jsx +++ b/src/components/atoms/Qr.jsx @@ -1,11 +1,17 @@ -import React, { Fragment } from 'react' +import React from 'react' import PropTypes from 'prop-types' import { QRCode } from 'react-qr-svg' import Clipboard from 'react-clipboard.js' import { ReactComponent as IconClipboard } from '../../images/clipboard.svg' +import styles from './Qr.module.scss' + +const onCopySuccess = e => { + e.trigger.classList.add(styles.copied) +} + const Qr = ({ address, title }) => ( - + <> {title &&

{title}

} ( level="Q" style={{ width: 120 }} value={address} + className={styles.qr} /> -
+
+    
       {address}
-      
+       onCopySuccess(e)}
+        className={styles.button}
+      >
         
       
     
- + ) Qr.propTypes = { diff --git a/src/components/atoms/Qr.module.scss b/src/components/atoms/Qr.module.scss new file mode 100644 index 00000000..880b4977 --- /dev/null +++ b/src/components/atoms/Qr.module.scss @@ -0,0 +1,54 @@ +@import 'variables'; + +.qr { + margin-bottom: $spacer / 2; +} + +.code { + margin: 0; + position: relative; + padding: 0; + padding-right: 2rem; + + code { + padding: $spacer / 2; + font-size: .65rem; + text-align: center; + } +} + +.button { + margin: 0; + position: absolute; + right: 0; + top: 0; + bottom: 0; + border: 0; + box-shadow: none; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + background: rgba($brand-grey, .3); + padding: $spacer / 3; + + svg { + width: 1rem; + height: 1rem; + fill: $brand-grey-light; + transition: .15s ease-out; + } + + &:hover { + svg { + fill: $brand-grey-dimmed; + } + } +} + +.copied { + background: green; + + // stylelint-disable-next-line no-descending-specificity + svg { + fill: $brand-grey-dimmed; + } +} diff --git a/src/components/molecules/ModalThanks.module.scss b/src/components/molecules/ModalThanks.module.scss index 0c10f1e1..6b59682c 100644 --- a/src/components/molecules/ModalThanks.module.scss +++ b/src/components/molecules/ModalThanks.module.scss @@ -39,48 +39,4 @@ width: 48%; margin-top: 0; } - - > svg { - margin-bottom: $spacer / 2; - } - - pre { - margin: 0; - position: relative; - padding: 0; - padding-right: 2rem; - - code { - padding: $spacer / 2; - font-size: .65rem; - text-align: center; - } - } - - button { - margin: 0; - position: absolute; - right: 0; - top: 0; - bottom: 0; - border: 0; - box-shadow: none; - border-top-left-radius: 0; - border-bottom-left-radius: 0; - background: rgba($brand-grey, .3); - padding: $spacer / 3; - - svg { - width: 1rem; - height: 1rem; - fill: $brand-grey; - transition: .15s ease-out; - } - - &:hover { - svg { - fill: $brand-grey-dimmed; - } - } - } } From 87f6f426c213d3d620b4c5330bdcfe05e999cf54 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Tue, 30 Oct 2018 18:08:07 +0100 Subject: [PATCH 4/4] tweaks --- package.json | 2 +- src/components/Web3Donation/Alerts.jsx | 95 ++++++------ .../Web3Donation/Alerts.module.scss | 32 +++- src/components/Web3Donation/InputGroup.jsx | 26 +--- src/components/Web3Donation/index.jsx | 138 +++++++----------- src/components/molecules/ModalThanks.jsx | 2 +- 6 files changed, 135 insertions(+), 160 deletions(-) diff --git a/package.json b/package.json index 5a7f9d60..60f9013d 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "prettier": "^1.14.3", "prettier-eslint-cli": "^4.7.1", "prettier-stylelint": "^0.4.2", - "stylelint": "^9.6.0", + "stylelint": "^9.7.0", "stylelint-config-css-modules": "^1.3.0", "stylelint-config-standard": "^18.2.0", "stylelint-scss": "^3.3.2" diff --git a/src/components/Web3Donation/Alerts.jsx b/src/components/Web3Donation/Alerts.jsx index 3151150a..3ff8b278 100644 --- a/src/components/Web3Donation/Alerts.jsx +++ b/src/components/Web3Donation/Alerts.jsx @@ -2,65 +2,58 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import styles from './Alerts.module.scss' -const Message = ({ message, ...props }) => ( -
-) +export const alertMessages = (networkName, transactionHash) => ({ + noAccount: + 'Web3 detected, but no account. Are you logged into your MetaMask account?', + noCorrectNetwork: `Please connect to Main network. You are on ${networkName} right now.`, + noWeb3: + 'No Web3 detected. Install MetaMask, Brave, or Mist.', + transaction: `See your transaction on etherscan.io.`, + waitingForUser: 'Waiting for your confirmation', + waitingConfirmation: 'Waiting for network confirmation, hang on', + success: 'Confirmed. You are awesome, thanks!' +}) export default class Alerts extends PureComponent { static propTypes = { - hasCorrectNetwork: PropTypes.bool.isRequired, - hasAccount: PropTypes.bool.isRequired, - networkName: PropTypes.string, - error: PropTypes.object, - transactionHash: PropTypes.string, - confirmationNumber: PropTypes.number, - receipt: PropTypes.object, - web3Connected: PropTypes.bool.isRequired + message: PropTypes.object, + transactionHash: PropTypes.string } - alertMessages = (networkName, transactionHash) => ({ - noAccount: - 'Web3 detected, but no account. Are you logged into your MetaMask account?', - noCorrectNetwork: `Please connect to Main network. You are on ${networkName} right now.`, - noWeb3: - 'No Web3 detected. Install MetaMask, Brave, or Mist.', - transaction: `See your transaction on etherscan.io.` - }) + constructMessage = () => { + const { transactionHash, message } = this.props + + let messageOutput + + if (transactionHash) { + messageOutput = + message.text + + '
' + + alertMessages(null, transactionHash).transaction + } else { + messageOutput = message.text + } + + return messageOutput + } + + classes() { + const { status } = this.props.message + + if (status === 'success') { + return styles.success + } else if (status === 'error') { + return styles.error + } + return styles.alert + } render() { - const { - hasCorrectNetwork, - hasAccount, - networkName, - error, - transactionHash, - web3Connected - } = this.props - return ( -
- {!web3Connected ? ( - - ) : ( - <> - {!hasAccount && ( - - )} - {!hasCorrectNetwork && ( - - )} - {error && } - - {transactionHash && ( - - )} - - )} -
+
) } } diff --git a/src/components/Web3Donation/Alerts.module.scss b/src/components/Web3Donation/Alerts.module.scss index 857df040..1b3aa060 100644 --- a/src/components/Web3Donation/Alerts.module.scss +++ b/src/components/Web3Donation/Alerts.module.scss @@ -2,16 +2,44 @@ @import 'mixins'; .alert { - margin-top: $spacer / 2; font-size: $font-size-small; - color: darken($alert-error, 60%); + display: inline-block; &:empty { display: none; } + + &::after { + overflow: hidden; + display: inline-block; + vertical-align: bottom; + animation: ellipsis steps(4, end) 1s infinite; + content: '\2026'; // ascii code for the ellipsis character + width: 0; + position: absolute; + } +} + +.error { + composes: alert; + color: darken($alert-error, 60%); + + &::after { + display: none; + } } .success { composes: alert; color: darken($alert-success, 60%); + + &::after { + display: none; + } +} + +@keyframes ellipsis { + to { + width: .75rem; + } } diff --git a/src/components/Web3Donation/InputGroup.jsx b/src/components/Web3Donation/InputGroup.jsx index f5476a0a..1bc3ea20 100644 --- a/src/components/Web3Donation/InputGroup.jsx +++ b/src/components/Web3Donation/InputGroup.jsx @@ -7,21 +7,17 @@ import styles from './InputGroup.module.scss' export default class InputGroup extends PureComponent { static propTypes = { - isCorrectNetwork: PropTypes.bool.isRequired, - hasAccount: PropTypes.bool.isRequired, amount: PropTypes.string.isRequired, onAmountChange: PropTypes.func.isRequired, - handleButton: PropTypes.func.isRequired, + sendTransaction: PropTypes.func.isRequired, selectedAccount: PropTypes.string } render() { const { - isCorrectNetwork, - hasAccount, amount, onAmountChange, - handleButton, + sendTransaction, selectedAccount } = this.props @@ -30,7 +26,6 @@ export default class InputGroup extends PureComponent {
ETH
- - {isCorrectNetwork && - hasAccount && ( -
- - {selectedAccount && } -
- )} +
+ + {selectedAccount && } +
) } diff --git a/src/components/Web3Donation/index.jsx b/src/components/Web3Donation/index.jsx index 96c4057f..0b56c962 100644 --- a/src/components/Web3Donation/index.jsx +++ b/src/components/Web3Donation/index.jsx @@ -1,29 +1,25 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import InputGroup from './InputGroup' -import Alerts from './Alerts' +import Alerts, { alertMessages } from './Alerts' import styles from './index.module.scss' import { getWeb3, getAccounts, getNetwork } from './utils' const ONE_SECOND = 1000 const ONE_MINUTE = ONE_SECOND * 60 +const correctNetwork = 1 export default class Web3Donation extends PureComponent { state = { - web3Connected: false, netId: null, networkName: null, - isCorrectNetwork: false, - loading: true, accounts: [], selectedAccount: null, amount: '0.01', transactionHash: null, receipt: null, - inTransaction: false, - error: null, - message: 'Hang on', - success: false + message: null, + inTransaction: false } static propTypes = { @@ -43,22 +39,24 @@ export default class Web3Donation extends PureComponent { } initWeb3 = async () => { + this.setState({ message: { text: 'Checking' } }) + try { this.web3 = await getWeb3() - this.setState({ web3Connected: this.web3 ? true : false }) - this.web3 ? this.initAllTheTings() : this.setState({ loading: false }) + this.web3 + ? this.initAllTheTings() + : this.setState({ + message: { status: 'error', text: alertMessages().noWeb3 } + }) } catch (error) { - this.setState({ error }) - this.setState({ web3Connected: false }) + this.setState({ message: { status: 'error', text: error } }) } } async initAllTheTings() { - await this.fetchAccounts() - await this.fetchNetwork() - - this.setState({ loading: false }) + this.fetchAccounts() + this.fetchNetwork() this.initAccountsPoll() this.initNetworkPoll() @@ -67,7 +65,6 @@ export default class Web3Donation extends PureComponent { resetAllTheThings() { clearInterval(this.interval) clearInterval(this.networkInterval) - this.setState({ web3Connected: false }) } initAccountsPoll() { @@ -84,40 +81,44 @@ export default class Web3Donation extends PureComponent { fetchNetwork = async () => { const { web3 } = this + const { netId, networkName } = await getNetwork(web3) - try { - const { netId, networkName } = await getNetwork(web3) - + if (netId === correctNetwork) { + this.setState({ netId, networkName }) + } else { this.setState({ - error: null, - netId, - networkName, - isCorrectNetwork: netId === 1 + message: { + status: 'error', + text: alertMessages(networkName).noCorrectNetwork + } }) - } catch (error) { - this.setState({ error }) } } fetchAccounts = async () => { const { web3 } = this + const accounts = await getAccounts(web3) - try { - const accounts = await getAccounts(web3) - + if (accounts[0]) { this.setState({ - error: null, accounts, - selectedAccount: accounts[0] ? accounts[0].toLowerCase() : null + selectedAccount: accounts[0].toLowerCase() + }) + } else { + this.setState({ + message: { status: 'error', text: alertMessages().noAccount } }) - } catch (error) { - this.setState({ error }) } } - sendTransaction() { + sendTransaction = () => { const { web3 } = this + this.setState({ + inTransaction: true, + message: { text: alertMessages().waitingForUser } + }) + web3.eth .sendTransaction({ from: this.state.selectedAccount, @@ -127,50 +128,32 @@ export default class Web3Donation extends PureComponent { .once('transactionHash', transactionHash => { this.setState({ transactionHash, - message: 'Waiting for network confirmation, hang on' + message: { text: alertMessages().waitingConfirmation } }) }) - .on('error', error => this.setState({ error, inTransaction: false })) + .on('error', error => + this.setState({ message: { status: 'error', text: error } }) + ) .then(() => { this.setState({ - message: 'Confirmed. You are awesome, thanks!', - success: true + message: { status: 'success', text: alertMessages().success } }) }) } - handleButton = () => { - this.setState({ - inTransaction: true, - message: 'Waiting for your confirmation' - }) - - this.sendTransaction() - } - onAmountChange = ({ target }) => { this.setState({ amount: target.value }) } render() { const { - isCorrectNetwork, - accounts, selectedAccount, - web3Connected, - inTransaction, - loading, amount, - networkName, - error, transactionHash, - confirmationNumber, message, - success + inTransaction } = this.state - const hasAccount = accounts.length !== 0 - return (
@@ -179,38 +162,21 @@ export default class Web3Donation extends PureComponent {
- {loading ? ( -
Checking
- ) : inTransaction ? ( -
- {message} -
+ {selectedAccount && + this.state.netId === correctNetwork && + !inTransaction ? ( + ) : ( - web3Connected && ( - + message && ( + ) )}
- - {!loading && ( - - )}
) } diff --git a/src/components/molecules/ModalThanks.jsx b/src/components/molecules/ModalThanks.jsx index 118156be..de16af84 100644 --- a/src/components/molecules/ModalThanks.jsx +++ b/src/components/molecules/ModalThanks.jsx @@ -37,7 +37,7 @@ class ModalThanks extends PureComponent {
-

Other wallets

+

Any other wallets

Send Bitcoin or Ether from any wallet.