diff options
22 files changed, 161 insertions, 31 deletions
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 7810c6eb4..33e72cd83 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -139,6 +139,9 @@ "balance": { "message": "Balance" }, + "balanceOutdated": { + "message": "Balance may be outdated" + }, "balances": { "message": "Token balance(s)" }, diff --git a/development/states/confirm-sig-requests.json b/development/states/confirm-sig-requests.json index 613112ec9..aa3e8dfdf 100644 --- a/development/states/confirm-sig-requests.json +++ b/development/states/confirm-sig-requests.json @@ -23,6 +23,7 @@ "name": "Send Account 4" } }, + "cachedBalances": {}, "unapprovedTxs": {}, "currentCurrency": "USD", "conversionRate": 1200.88200327, diff --git a/development/states/currency-localization.json b/development/states/currency-localization.json index a4ca19eb6..7dd1a135d 100644 --- a/development/states/currency-localization.json +++ b/development/states/currency-localization.json @@ -23,6 +23,7 @@ "name": "Send Account 4" } }, + "cachedBalances": {}, "unapprovedTxs": {}, "currentCurrency": "USD", "conversionRate": 19855, diff --git a/development/states/send-edit.json b/development/states/send-edit.json index 0157dece4..f617910f1 100644 --- a/development/states/send-edit.json +++ b/development/states/send-edit.json @@ -23,6 +23,7 @@ "name": "Send Account 4" } }, + "cachedBalances": {}, "assetImages": {}, "unapprovedTxs": {}, "currentCurrency": "USD", diff --git a/development/states/send-new-ui.json b/development/states/send-new-ui.json index 88bffbd48..bb4d80c5c 100644 --- a/development/states/send-new-ui.json +++ b/development/states/send-new-ui.json @@ -23,6 +23,7 @@ "name": "Send Account 4" } }, + "cachedBalances": {}, "unapprovedTxs": {}, "currentCurrency": "USD", "conversionRate": 1200.88200327, diff --git a/development/states/tx-list-items.json b/development/states/tx-list-items.json index 24daf3254..7939e3d94 100644 --- a/development/states/tx-list-items.json +++ b/development/states/tx-list-items.json @@ -23,6 +23,7 @@ "name": "Send Account 4" } }, + "cachedBalances": {}, "currentCurrency": "USD", "conversionRate": 1200.88200327, "conversionDate": 1489013762, diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 8deff5531..671697182 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -11,6 +11,7 @@ "name": "Test Account 2" } }, + "cachedBalances": {}, "unapprovedTxs": { "8393540981007587": { "id": 8393540981007587, diff --git a/test/unit/ui/app/selectors.spec.js b/test/unit/ui/app/selectors.spec.js index e2b198abf..070de0bcd 100644 --- a/test/unit/ui/app/selectors.spec.js +++ b/test/unit/ui/app/selectors.spec.js @@ -19,6 +19,7 @@ describe('Selectors', function () { 'address': '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', }, }, + cachedBalances: {}, }, } }) diff --git a/ui/app/components/currency-display/currency-display.component.js b/ui/app/components/currency-display/currency-display.component.js index 2d7413b57..6a743cc4e 100644 --- a/ui/app/components/currency-display/currency-display.component.js +++ b/ui/app/components/currency-display/currency-display.component.js @@ -17,10 +17,11 @@ export default class CurrencyDisplay extends PureComponent { value: PropTypes.string, numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), hideLabel: PropTypes.bool, + hideTitle: PropTypes.bool, } render () { - const { className, displayValue, prefix, prefixComponent, style, suffix } = this.props + const { className, displayValue, prefix, prefixComponent, style, suffix, hideTitle } = this.props const text = `${prefix || ''}${displayValue}` const title = `${text} ${suffix}` @@ -28,9 +29,9 @@ export default class CurrencyDisplay extends PureComponent { <div className={classnames('currency-display-component', className)} style={style} - title={title} + title={!hideTitle && title || null} > - { prefixComponent} + { prefixComponent } <span className="currency-display-component__text">{ text }</span> { suffix && ( diff --git a/ui/app/components/send/account-list-item/account-list-item.component.js b/ui/app/components/send/account-list-item/account-list-item.component.js index a61467bb3..665383e58 100644 --- a/ui/app/components/send/account-list-item/account-list-item.component.js +++ b/ui/app/components/send/account-list-item/account-list-item.component.js @@ -1,9 +1,11 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import classnames from 'classnames' import { checksumAddress } from '../../../util' import Identicon from '../../identicon' import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display' import { PRIMARY, SECONDARY } from '../../../constants/common' +import Tooltip from '../../tooltip-v2' export default class AccountListItem extends Component { @@ -16,6 +18,7 @@ export default class AccountListItem extends Component { displayBalance: PropTypes.bool, handleClick: PropTypes.func, icon: PropTypes.node, + balanceIsCached: PropTypes.bool, }; static contextTypes = { @@ -30,6 +33,7 @@ export default class AccountListItem extends Component { displayBalance = true, handleClick, icon = null, + balanceIsCached, } = this.props const { name, address, balance } = account || {} @@ -58,16 +62,34 @@ export default class AccountListItem extends Component { { displayBalance && ( - <div className="account-list-item__account-balances"> - <UserPreferencedCurrencyDisplay - type={PRIMARY} - value={balance} - /> - <UserPreferencedCurrencyDisplay - type={SECONDARY} - value={balance} - /> - </div> + <Tooltip + position="left" + title={this.context.t('balanceOutdated')} + disabled={!balanceIsCached} + style={{ + left: '-20px !important', + }} + > + <div className={classnames('account-list-item__account-balances', { + 'account-list-item__cached-balances': balanceIsCached, + })}> + <div className="account-list-item__primary-cached-container"> + <UserPreferencedCurrencyDisplay + type={PRIMARY} + value={balance} + hideTitle={true} + /> + { + balanceIsCached ? <span className="account-list-item__cached-star">*</span> : null + } + </div> + <UserPreferencedCurrencyDisplay + type={SECONDARY} + value={balance} + hideTitle={true} + /> + </div> + </Tooltip> ) } diff --git a/ui/app/components/send/account-list-item/account-list-item.container.js b/ui/app/components/send/account-list-item/account-list-item.container.js index f8e73d923..03a60be67 100644 --- a/ui/app/components/send/account-list-item/account-list-item.container.js +++ b/ui/app/components/send/account-list-item/account-list-item.container.js @@ -4,6 +4,9 @@ import { getCurrentCurrency, getNativeCurrency, } from '../send.selectors.js' +import { + isBalanceCached, +} from '../../../selectors' import AccountListItem from './account-list-item.component' export default connect(mapStateToProps)(AccountListItem) @@ -13,5 +16,6 @@ function mapStateToProps (state) { conversionRate: getConversionRate(state), currentCurrency: getCurrentCurrency(state), nativeCurrency: getNativeCurrency(state), + balanceIsCached: isBalanceCached(state), } } diff --git a/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js b/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js index 6ffc0b1c6..f2ddb73c0 100644 --- a/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js +++ b/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js @@ -121,6 +121,7 @@ describe('AccountListItem Component', function () { { type: 'PRIMARY', value: 'mockBalance', + hideTitle: true, } ) }) diff --git a/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js b/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js index 7c2f5fcb2..8c22bc8f8 100644 --- a/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js +++ b/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js @@ -15,6 +15,9 @@ proxyquire('../account-list-item.container.js', { getCurrentCurrency: (s) => `mockCurrentCurrency:${s}`, getNativeCurrency: (s) => `mockNativeCurrency:${s}`, }, + '../../../selectors.js': { + isBalanceCached: (s) => `mockBalanceIsCached:${s}`, + }, }) describe('account-list-item container', () => { @@ -26,6 +29,7 @@ describe('account-list-item container', () => { conversionRate: 'mockConversionRate:mockState', currentCurrency: 'mockCurrentCurrency:mockState', nativeCurrency: 'mockNativeCurrency:mockState', + balanceIsCached: 'mockBalanceIsCached:mockState', }) }) diff --git a/ui/app/components/send/tests/send-selectors-test-data.js b/ui/app/components/send/tests/send-selectors-test-data.js index 30a2666cf..66c0da229 100644 --- a/ui/app/components/send/tests/send-selectors-test-data.js +++ b/ui/app/components/send/tests/send-selectors-test-data.js @@ -22,6 +22,7 @@ module.exports = { 'name': 'Send Account 4', }, }, + 'cachedBalances': {}, 'currentBlockGasLimit': '0x4c1878', 'currentCurrency': 'USD', 'conversionRate': 1200.88200327, diff --git a/ui/app/components/tooltip-v2.js b/ui/app/components/tooltip-v2.js index 054782203..b54026794 100644 --- a/ui/app/components/tooltip-v2.js +++ b/ui/app/components/tooltip-v2.js @@ -20,6 +20,7 @@ export default class Tooltip extends PureComponent { arrow: PropTypes.bool, children: PropTypes.node, containerClassName: PropTypes.string, + disabled: PropTypes.bool, onHidden: PropTypes.func, position: PropTypes.oneOf([ 'top', @@ -33,10 +34,11 @@ export default class Tooltip extends PureComponent { title: PropTypes.string, trigger: PropTypes.any, wrapperClassName: PropTypes.string, + style: PropTypes.object, } render () { - const {arrow, children, containerClassName, position, size, title, trigger, onHidden, wrapperClassName } = this.props + const {arrow, children, containerClassName, disabled, position, size, title, trigger, onHidden, wrapperClassName, style } = this.props if (!title) { return ( @@ -50,6 +52,7 @@ export default class Tooltip extends PureComponent { <div className={wrapperClassName}> <ReactTippy className={containerClassName} + disabled={disabled} title={title} position={position} trigger={trigger} @@ -57,6 +60,7 @@ export default class Tooltip extends PureComponent { size={size} arrow={arrow} onHidden={onHidden} + style={style} > {children} </ReactTippy> diff --git a/ui/app/components/transaction-view-balance/index.scss b/ui/app/components/transaction-view-balance/index.scss index f3fd580d7..bdcd536b0 100644 --- a/ui/app/components/transaction-view-balance/index.scss +++ b/ui/app/components/transaction-view-balance/index.scss @@ -17,6 +17,7 @@ display: flex; flex-direction: column; min-width: 0; + position: relative; @media screen and (max-width: $break-small) { align-items: center; @@ -26,6 +27,10 @@ } } + &__primary-container { + display: flex; + } + &__primary-balance { font-size: 1.5rem; @@ -36,6 +41,19 @@ } } + &__cached-star { + margin-left: 4px; + } + + &__cached-balance, &__cached-star { + color: $web-orange; + } + + &__cached-secondary-balance { + color: rgba(220, 153, 18, 0.6901960784313725); + font-size: 1.15rem; + } + &__secondary-balance { font-size: 1.15rem; color: #a0a0a0; diff --git a/ui/app/components/transaction-view-balance/transaction-view-balance.component.js b/ui/app/components/transaction-view-balance/transaction-view-balance.component.js index a24b97478..bd6b4bdb6 100644 --- a/ui/app/components/transaction-view-balance/transaction-view-balance.component.js +++ b/ui/app/components/transaction-view-balance/transaction-view-balance.component.js @@ -1,11 +1,13 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' +import classnames from 'classnames' import Button from '../button' import Identicon from '../identicon' import TokenBalance from '../token-balance' import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display' import { SEND_ROUTE } from '../../routes' import { PRIMARY, SECONDARY } from '../../constants/common' +import Tooltip from '../tooltip-v2' export default class TransactionViewBalance extends PureComponent { static contextTypes = { @@ -19,10 +21,11 @@ export default class TransactionViewBalance extends PureComponent { network: PropTypes.string, balance: PropTypes.string, assetImage: PropTypes.string, + balanceIsCached: PropTypes.bool, } renderBalance () { - const { selectedToken, balance } = this.props + const { selectedToken, balance, balanceIsCached } = this.props return selectedToken ? ( @@ -34,20 +37,34 @@ export default class TransactionViewBalance extends PureComponent { /> </div> ) : ( - <div className="transaction-view-balance__balance"> - <UserPreferencedCurrencyDisplay - className="transaction-view-balance__primary-balance" - value={balance} - type={PRIMARY} - ethNumberOfDecimals={4} - /> - <UserPreferencedCurrencyDisplay - className="transaction-view-balance__secondary-balance" - value={balance} - type={SECONDARY} - ethNumberOfDecimals={4} - /> - </div> + <Tooltip position="top" title={this.context.t('balanceOutdated')} disabled={!balanceIsCached}> + <div className="transaction-view-balance__balance"> + <div className="transaction-view-balance__primary-container"> + <UserPreferencedCurrencyDisplay + className={classnames('transaction-view-balance__primary-balance', { + 'transaction-view-balance__cached-balance': balanceIsCached, + })} + value={balance} + type={PRIMARY} + ethNumberOfDecimals={4} + hideTitle={true} + /> + { + balanceIsCached ? <span className="transaction-view-balance__cached-star">*</span> : null + } + </div> + <UserPreferencedCurrencyDisplay + className={classnames({ + 'transaction-view-balance__cached-secondary-balance': balanceIsCached, + 'transaction-view-balance__secondary-balance': !balanceIsCached, + })} + value={balance} + type={SECONDARY} + ethNumberOfDecimals={4} + hideTitle={true} + /> + </div> + </Tooltip> ) } diff --git a/ui/app/components/transaction-view-balance/transaction-view-balance.container.js b/ui/app/components/transaction-view-balance/transaction-view-balance.container.js index f9f05b0ae..354db5ae1 100644 --- a/ui/app/components/transaction-view-balance/transaction-view-balance.container.js +++ b/ui/app/components/transaction-view-balance/transaction-view-balance.container.js @@ -8,6 +8,7 @@ import { getNativeCurrency, getSelectedTokenAssetImage, getMetaMaskAccounts, + isBalanceCached, } from '../../selectors' import { showModal } from '../../actions' @@ -24,6 +25,7 @@ const mapStateToProps = state => { balance, nativeCurrency: getNativeCurrency(state), assetImage: getSelectedTokenAssetImage(state), + balanceIsCached: isBalanceCached(state), } } diff --git a/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js index f2a834ea7..d9f29327d 100644 --- a/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js +++ b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js @@ -10,6 +10,7 @@ export default class UserPreferencedCurrencyDisplay extends PureComponent { value: PropTypes.string, numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), hideLabel: PropTypes.bool, + hideTitle: PropTypes.bool, style: PropTypes.object, showEthLogo: PropTypes.bool, ethLogoHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), diff --git a/ui/app/css/itcss/components/account-dropdown.scss b/ui/app/css/itcss/components/account-dropdown.scss index b29afdc8c..716404cc3 100644 --- a/ui/app/css/itcss/components/account-dropdown.scss +++ b/ui/app/css/itcss/components/account-dropdown.scss @@ -24,6 +24,10 @@ position: relative; } + &__tooltip-wrapper { + left: -10px; + } + &__account-balances { height: auto; border: none; @@ -34,6 +38,24 @@ position: relative; } + &__primary-cached-container { + display: flex; + } + + &__cached-star { + margin-left: 4px; + } + + &__cached-balances { + div:first-of-type { + color: $web-orange; + } + + div:last-of-type { + color: rgba(220, 153, 18, 0.6901960784313725) + } + } + &__account-name { font-size: 16px; margin-left: 8px; @@ -52,6 +74,13 @@ font-size: 12px; } + &__balance-flag { + position: absolute; + top: 3px; + left: -8px; + color: $curious-blue; + } + &__account-primary-balance { color: $scorpion; border: none; diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss index 42a8655df..89bd8b96a 100644 --- a/ui/app/css/itcss/settings/variables.scss +++ b/ui/app/css/itcss/settings/variables.scss @@ -59,6 +59,7 @@ $oslo-gray: #8C8E94; $polar: #fafcfe; $blizzard-blue: #bfdef3; $mischka: #dddee9; +$web-orange: #f2a202; /* Z-Indicies diff --git a/ui/app/selectors.js b/ui/app/selectors.js index f1ef41f28..c60b27ab4 100644 --- a/ui/app/selectors.js +++ b/ui/app/selectors.js @@ -37,6 +37,7 @@ const selectors = { getMetaMaskAccounts, getCurrentEthBalance, getNetworkIdentifier, + isBalanceCached, } module.exports = selectors @@ -62,7 +63,7 @@ function getSelectedIdentity (state) { function getMetaMaskAccounts (state) { const currentAccounts = state.metamask.accounts - const cachedBalances = state.metamask.cachedBalances + const cachedBalances = state.metamask.cachedBalances[state.metamask.network] const selectedAccounts = {} Object.keys(currentAccounts).forEach(accountID => { @@ -70,7 +71,7 @@ function getMetaMaskAccounts (state) { if (account && account.balance === null || account.balance === undefined) { selectedAccounts[accountID] = { ...account, - balance: cachedBalances[accountID], + balance: cachedBalances && cachedBalances[accountID], } } else { selectedAccounts[accountID] = account @@ -79,6 +80,20 @@ function getMetaMaskAccounts (state) { return selectedAccounts } +function isBalanceCached (state) { + const selectedAccountBalance = state.metamask.accounts[getSelectedAddress(state)].balance + const cachedBalance = getSelectedAccountCachedBalance(state) + + return Boolean(!selectedAccountBalance && cachedBalance) +} + +function getSelectedAccountCachedBalance (state) { + const cachedBalances = state.metamask.cachedBalances[state.metamask.network] + const selectedAddress = getSelectedAddress(state) + + return cachedBalances && cachedBalances[selectedAddress] +} + function getSelectedAccount (state) { const accounts = getMetaMaskAccounts(state) const selectedAddress = getSelectedAddress(state) |