mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +01:00
Add visual indicator when displaying a cached balance (#5854)
This commit is contained in:
parent
df3169d1c7
commit
02bdbbbc3e
@ -139,6 +139,9 @@
|
||||
"balance": {
|
||||
"message": "Balance"
|
||||
},
|
||||
"balanceOutdated": {
|
||||
"message": "Balance may be outdated"
|
||||
},
|
||||
"balances": {
|
||||
"message": "Token balance(s)"
|
||||
},
|
||||
|
@ -23,6 +23,7 @@
|
||||
"name": "Send Account 4"
|
||||
}
|
||||
},
|
||||
"cachedBalances": {},
|
||||
"unapprovedTxs": {},
|
||||
"currentCurrency": "USD",
|
||||
"conversionRate": 1200.88200327,
|
||||
|
@ -23,6 +23,7 @@
|
||||
"name": "Send Account 4"
|
||||
}
|
||||
},
|
||||
"cachedBalances": {},
|
||||
"unapprovedTxs": {},
|
||||
"currentCurrency": "USD",
|
||||
"conversionRate": 19855,
|
||||
|
@ -23,6 +23,7 @@
|
||||
"name": "Send Account 4"
|
||||
}
|
||||
},
|
||||
"cachedBalances": {},
|
||||
"assetImages": {},
|
||||
"unapprovedTxs": {},
|
||||
"currentCurrency": "USD",
|
||||
|
@ -23,6 +23,7 @@
|
||||
"name": "Send Account 4"
|
||||
}
|
||||
},
|
||||
"cachedBalances": {},
|
||||
"unapprovedTxs": {},
|
||||
"currentCurrency": "USD",
|
||||
"conversionRate": 1200.88200327,
|
||||
|
@ -23,6 +23,7 @@
|
||||
"name": "Send Account 4"
|
||||
}
|
||||
},
|
||||
"cachedBalances": {},
|
||||
"currentCurrency": "USD",
|
||||
"conversionRate": 1200.88200327,
|
||||
"conversionDate": 1489013762,
|
||||
|
@ -11,6 +11,7 @@
|
||||
"name": "Test Account 2"
|
||||
}
|
||||
},
|
||||
"cachedBalances": {},
|
||||
"unapprovedTxs": {
|
||||
"8393540981007587": {
|
||||
"id": 8393540981007587,
|
||||
|
@ -19,6 +19,7 @@ describe('Selectors', function () {
|
||||
'address': '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
|
||||
},
|
||||
},
|
||||
cachedBalances: {},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
@ -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,7 +29,7 @@ export default class CurrencyDisplay extends PureComponent {
|
||||
<div
|
||||
className={classnames('currency-display-component', className)}
|
||||
style={style}
|
||||
title={title}
|
||||
title={!hideTitle && title || null}
|
||||
>
|
||||
{ prefixComponent }
|
||||
<span className="currency-display-component__text">{ text }</span>
|
||||
|
@ -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">
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -121,6 +121,7 @@ describe('AccountListItem Component', function () {
|
||||
{
|
||||
type: 'PRIMARY',
|
||||
value: 'mockBalance',
|
||||
hideTitle: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
@ -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',
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -22,6 +22,7 @@ module.exports = {
|
||||
'name': 'Send Account 4',
|
||||
},
|
||||
},
|
||||
'cachedBalances': {},
|
||||
'currentBlockGasLimit': '0x4c1878',
|
||||
'currentCurrency': 'USD',
|
||||
'conversionRate': 1200.88200327,
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
) : (
|
||||
<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="transaction-view-balance__primary-balance"
|
||||
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="transaction-view-balance__secondary-balance"
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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]),
|
||||
|
@ -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;
|
||||
|
@ -59,6 +59,7 @@ $oslo-gray: #8C8E94;
|
||||
$polar: #fafcfe;
|
||||
$blizzard-blue: #bfdef3;
|
||||
$mischka: #dddee9;
|
||||
$web-orange: #f2a202;
|
||||
|
||||
/*
|
||||
Z-Indicies
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user