From 187a8dd37dae1c6f9723e564b4b71fabac2bcc96 Mon Sep 17 00:00:00 2001 From: Vadim Date: Fri, 12 Jun 2020 17:24:50 +0300 Subject: [PATCH] JS and CSS refactorings, fixes, and improvements --- apps/block_scout_web/assets/css/_mixins.scss | 5 +- .../assets/css/components/_form.scss | 8 ++ .../assets/css/theme/_dai_variables.scss | 9 ++ .../assets/css/theme/_dark-theme.scss | 12 ++ .../block_scout_web/assets/js/pages/stakes.js | 1 + .../assets/js/pages/stakes/claim_reward.js | 51 ++------ .../assets/js/pages/stakes/make_stake.js | 15 ++- .../assets/js/pages/stakes/remove_pool.js | 19 ++- .../assets/js/pages/stakes/utils.js | 110 +++++++++++------- 9 files changed, 135 insertions(+), 95 deletions(-) diff --git a/apps/block_scout_web/assets/css/_mixins.scss b/apps/block_scout_web/assets/css/_mixins.scss index 14b633bddf..8d759a695b 100644 --- a/apps/block_scout_web/assets/css/_mixins.scss +++ b/apps/block_scout_web/assets/css/_mixins.scss @@ -172,8 +172,9 @@ &[disabled] { &, &:hover { - background-color: $bg-color; - border-color: $text-color; + background-color: $bg-color!important; + border-color: $primary!important; + color: $primary!important; cursor: default; opacity: 0.5; } diff --git a/apps/block_scout_web/assets/css/components/_form.scss b/apps/block_scout_web/assets/css/components/_form.scss index 1458e8bc56..0109e8c514 100644 --- a/apps/block_scout_web/assets/css/components/_form.scss +++ b/apps/block_scout_web/assets/css/components/_form.scss @@ -92,6 +92,14 @@ $form-control-border-color-active: $primary !default; color: white; background: #FF7884; border-radius: 0 0 2px 2px; + + .link-helptip { + border-bottom-width: 1px; + border-bottom-style: dotted; + color: inherit; + cursor: help; + text-decoration: none; + } } } diff --git a/apps/block_scout_web/assets/css/theme/_dai_variables.scss b/apps/block_scout_web/assets/css/theme/_dai_variables.scss index ec33adba4a..373323eaca 100644 --- a/apps/block_scout_web/assets/css/theme/_dai_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_dai_variables.scss @@ -105,6 +105,15 @@ $dark-tertiary: #5a77ff; background-color: transparent!important; border-color: $dark-tertiary!important; color: $dark-tertiary!important; + + &[disabled] { + &, + &:hover { + background-color: transparent!important; + border-color: $dark-tertiary!important; + color: $dark-tertiary!important; + } + } } .dark-theme-applied .btn-line:hover { diff --git a/apps/block_scout_web/assets/css/theme/_dark-theme.scss b/apps/block_scout_web/assets/css/theme/_dark-theme.scss index 0af35f7090..774c87611c 100644 --- a/apps/block_scout_web/assets/css/theme/_dark-theme.scss +++ b/apps/block_scout_web/assets/css/theme/_dark-theme.scss @@ -296,6 +296,14 @@ $dark-stakes-banned-background: #3e314c; color: $labels-dark; } + .stakes-table-body { + .refresh-informer { + a { + color: inherit; + } + } + } + .stakes-td { border-bottom-color: darken($labels-dark, 30); } @@ -554,6 +562,10 @@ $dark-stakes-banned-background: #3e314c; color: #fff; transition: border-color 0.15s ease-in-out; + &[readonly] { + background-color: $dark-light!important; + } + &::placeholder { color: $labels-dark; } diff --git a/apps/block_scout_web/assets/js/pages/stakes.js b/apps/block_scout_web/assets/js/pages/stakes.js index 6069ce6595..e43d001238 100644 --- a/apps/block_scout_web/assets/js/pages/stakes.js +++ b/apps/block_scout_web/assets/js/pages/stakes.js @@ -29,6 +29,7 @@ export const initialState = { network: null, refreshBlockNumber: 0, // last page refresh block number refreshInterval: null, + refreshPageFunc: refreshPageWrapper, stakingAllowed: false, stakingTokenDefined: false, stakingContract: null, diff --git a/apps/block_scout_web/assets/js/pages/stakes/claim_reward.js b/apps/block_scout_web/assets/js/pages/stakes/claim_reward.js index 860b169d59..234e3427e7 100644 --- a/apps/block_scout_web/assets/js/pages/stakes/claim_reward.js +++ b/apps/block_scout_web/assets/js/pages/stakes/claim_reward.js @@ -9,7 +9,7 @@ import { unlockModal } from '../../lib/modals' import { displayInputError, hideInputError } from '../../lib/validation' -import { isSupportedNetwork } from './utils' +import { isSupportedNetwork, makeContractCall } from './utils' let status = 'modalClosed' @@ -230,53 +230,20 @@ function onPoolsFound ($modal, $modalBody, channel, store) { const gasLimit = parseInt($('#tx-gas-limit', $modalBody).text().replace(/~/g, '').trim(), 10) const state = store.getState() const stakingContract = state.stakingContract - const from = state.account - const web3 = state.web3 if (isNaN(gasLimit)) { claimFinished('Invalid gas limit. Please, contact support.') } else if (!stakingContract) { claimFinished('Staking contract is undefined. Please, contact support.') - } else if (!from) { - claimFinished('Your MetaMask account is undefined. Please, contact support.') - } else if (!web3) { - claimFinished('Web3 is undefined. Please, contact support.') } else if (!poolStakingAddress) { claimFinished('Pool staking address is undefined. Please, contact support.') } else { - stakingContract.methods.claimReward(epochs, poolStakingAddress).send({ - from, - gasPrice: web3.utils.toWei('1', 'gwei'), - gas: Math.ceil(gasLimit * 1.2) // +20% reserve to ensure enough gas - }, async function (error, txHash) { - if (error) { - claimFinished(error.message) - } else { - try { - let tx - let currentBlockNumber - const maxWaitBlocks = 6 - const startBlockNumber = (await web3.eth.getBlockNumber()) - 0 - const finishBlockNumber = startBlockNumber + maxWaitBlocks - do { - await sleep(5) // seconds - tx = await web3.eth.getTransactionReceipt(txHash) - currentBlockNumber = await web3.eth.getBlockNumber() - } while (tx === null && currentBlockNumber <= finishBlockNumber) - if (tx) { - if (tx.status === true || tx.status === '0x1') { - claimFinished() - } else { - claimFinished('Transaction reverted') - } - } else { - claimFinished(`Your transaction was not mined in ${maxWaitBlocks} blocks. Please, try again with the increased gas price or fixed nonce (use Reset Account feature of MetaMask).`) - } - } catch (e) { - claimFinished(e.message) - } - } - }) + makeContractCall( + stakingContract.methods.claimReward(epochs, poolStakingAddress), + store, + gasLimit, + claimFinished + ) } } function claimFinished (error) { @@ -303,10 +270,6 @@ function lockUI (lock, $modal, $button, $poolsDropdown, $epochChoiceRadio, $spec $specifiedEpochsText.prop('disabled', lock) } -function sleep (seconds) { - return new Promise(resolve => setTimeout(resolve, seconds * 1000)) -} - function showButton (type, $modalBody, calculations) { const $recalculateButton = $('button.recalculate', $modalBody) const $submitButton = $('button.submit', $modalBody) diff --git a/apps/block_scout_web/assets/js/pages/stakes/make_stake.js b/apps/block_scout_web/assets/js/pages/stakes/make_stake.js index 313aba20ce..c8da9aff3c 100644 --- a/apps/block_scout_web/assets/js/pages/stakes/make_stake.js +++ b/apps/block_scout_web/assets/js/pages/stakes/make_stake.js @@ -2,19 +2,22 @@ import $ from 'jquery' import { BigNumber } from 'bignumber.js' import { openErrorModal, openModal, openWarningModal, lockModal } from '../../lib/modals' import { setupValidation } from '../../lib/validation' -import { makeContractCall, setupChart, isSupportedNetwork } from './utils' +import { makeContractCall, setupChart, isSupportedNetwork, isStakingAllowed } from './utils' export function openMakeStakeModal (event, store) { - if (!store.getState().account) { + const state = store.getState() + + if (!state.account) { openWarningModal('Unauthorized', 'You haven\'t approved the reading of account list from your MetaMask or MetaMask is not installed.') return } if (!isSupportedNetwork(store)) return + if (!isStakingAllowed(state)) return const address = $(event.target).closest('[data-address]').data('address') || store.getState().account - store.getState().channel + state.channel .push('render_make_stake', { address }) .receive('ok', msg => { const $modal = $(msg.html) @@ -47,8 +50,6 @@ export function openMakeStakeModal (event, store) { } async function makeStake ($modal, address, store, msg) { - lockModal($modal) - const state = store.getState() const stakingContract = state.stakingContract const validatorSetContract = state.validatorSetContract @@ -56,6 +57,10 @@ async function makeStake ($modal, address, store, msg) { const stake = new BigNumber($modal.find('[delegator-stake]').val().replace(',', '.').trim()).shiftedBy(decimals).integerValue() + if (!isSupportedNetwork(store)) return + if (!isStakingAllowed(state)) return + lockModal($modal) + let miningAddress = msg.mining_address if (!miningAddress || miningAddress === '0x0000000000000000000000000000000000000000') { miningAddress = await validatorSetContract.methods.miningByStakingAddress(address).call() diff --git a/apps/block_scout_web/assets/js/pages/stakes/remove_pool.js b/apps/block_scout_web/assets/js/pages/stakes/remove_pool.js index 9b47658b58..1f7905632b 100644 --- a/apps/block_scout_web/assets/js/pages/stakes/remove_pool.js +++ b/apps/block_scout_web/assets/js/pages/stakes/remove_pool.js @@ -1,4 +1,4 @@ -import { openQuestionModal } from '../../lib/modals' +import { openErrorModal, openQuestionModal } from '../../lib/modals' import { makeContractCall, isSupportedNetwork } from './utils' export function openRemovePoolModal (store) { @@ -7,6 +7,19 @@ export function openRemovePoolModal (store) { } async function removePool (store) { - const contract = store.getState().stakingContract - makeContractCall(contract.methods.removeMyPool(), store) + const state = store.getState() + const call = state.stakingContract.methods.removeMyPool() + let gasLimit + + try { + gasLimit = await call.estimateGas({ + from: state.account, + gasPrice: 1000000000 + }) + } catch (err) { + openErrorModal('Error', 'Currently you cannot remove your pool. Please try again during the next epoch.') + return + } + + makeContractCall(call, store, gasLimit) } diff --git a/apps/block_scout_web/assets/js/pages/stakes/utils.js b/apps/block_scout_web/assets/js/pages/stakes/utils.js index 79ff43a203..315f6ebae0 100644 --- a/apps/block_scout_web/assets/js/pages/stakes/utils.js +++ b/apps/block_scout_web/assets/js/pages/stakes/utils.js @@ -1,55 +1,79 @@ import $ from 'jquery' import Chart from 'chart.js' -import { refreshPage } from '../../lib/async_listing_load' import { openErrorModal, openSuccessModal, openWarningModal } from '../../lib/modals' -export async function makeContractCall (call, store) { - let gas, timeout - let resultShown = false - const account = store.getState().account +export async function makeContractCall (call, store, gasLimit, callbackFunc) { + const state = store.getState() + const from = state.account + const web3 = state.web3 - try { - gas = await call.estimateGas({ - from: account, - gasPrice: 1000000000 - }) - } catch (err) { - openErrorModal('Error', 'Your transaction cannot be mined at the moment. Please, try again in a few blocks.') - return + if (!callbackFunc) { + callbackFunc = function (errorMessage) { + if (!errorMessage) { + state.refreshPageFunc(store) + openSuccessModal('Success', 'Transaction is confirmed.') + } else { + openErrorModal('Error', errorMessage) + } + } } - try { - await call.send({ - from: account, - gas: Math.ceil(gas * 1.2), - gasPrice: 1000000000 - }).once('transactionHash', (hash) => { - timeout = setTimeout(() => { - if (!resultShown) { - openErrorModal('Error', 'Your transaction cannot be mined at the moment. Please, try again with the increased gas price or fixed nonce (use Reset Account feature of MetaMask).') - resultShown = true - } - }, 30000) - }) + if (!from) { + return callbackFunc('Your MetaMask account is undefined. Please, contact support.') + } else if (!web3) { + return callbackFunc('Web3 is undefined. Please, contact support.') + } - clearTimeout(timeout) - refreshPage(store) + const gasPrice = web3.utils.toWei('1', 'gwei') - if (!resultShown) { - openSuccessModal('Success', 'Transaction is confirmed.') - resultShown = true - } - } catch (err) { - clearTimeout(timeout) - let errorMessage = 'Your MetaMask transaction was not processed, please try again in a few minutes.' - if (err.message) { - const detailsMessage = err.message.replace(/["]/g, '"') - console.log(detailsMessage) - const detailsHTML = ` Details` - errorMessage = errorMessage + detailsHTML + if (!gasLimit) { + try { + gasLimit = await call.estimateGas({ from, gasPrice }) + } catch (e) { + return callbackFunc('Your transaction cannot be mined at the moment. Please, try again in a few blocks.') } - openErrorModal('Error', errorMessage) } + + call.send({ + from, + gasPrice, + gas: Math.ceil(gasLimit * 1.2) // +20% reserve to ensure enough gas + }, async function (error, txHash) { + if (error) { + let errorMessage = 'Your transaction wasn\'t processed, please try again in a few blocks.' + if (error.message) { + const detailsMessage = error.message.replace(/["]/g, '"') + console.log(detailsMessage) + const detailsHTML = ` Details` + errorMessage = errorMessage + detailsHTML + } + callbackFunc(errorMessage) + } else { + try { + let tx + let currentBlockNumber + const maxWaitBlocks = 6 + const startBlockNumber = (await web3.eth.getBlockNumber()) - 0 + const finishBlockNumber = startBlockNumber + maxWaitBlocks + do { + await sleep(5) // seconds + tx = await web3.eth.getTransactionReceipt(txHash) + currentBlockNumber = await web3.eth.getBlockNumber() + } while (tx === null && currentBlockNumber <= finishBlockNumber) + if (tx) { + if (tx.status === true || tx.status === '0x1') { + callbackFunc() // success + } else { + callbackFunc('Transaction reverted') + } + } else { + callbackFunc(`Your transaction wasn't processed in ${maxWaitBlocks} blocks. Please, try again with the increased gas price or fixed nonce (use Reset Account feature of MetaMask).`) + } + } catch (e) { + callbackFunc(e.message) + } + } + }) } export function setupChart ($canvas, self, total) { @@ -107,3 +131,7 @@ export function isSupportedNetwork (store) { openWarningModal('Unauthorized', 'Please, connect to the xDai Chain.
Instructions') return false } + +function sleep (seconds) { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)) +}