Browse Source

Merge pull request #725 from gre/fix-account

Bugfix account.unit to refresh account page when you change it
master
Gaëtan Renaudeau 7 years ago
committed by GitHub
parent
commit
d1e2b54d69
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 125
      src/components/AccountPage/AccountBalanceSummaryHeader.js
  2. 100
      src/components/AccountPage/AccountHeaderActions.js
  3. 160
      src/components/AccountPage/index.js
  4. 1
      src/components/BalanceSummary/index.js
  5. 10
      src/components/CalculateBalance.js

125
src/components/AccountPage/AccountBalanceSummaryHeader.js

@ -0,0 +1,125 @@
// @flow
import React, { PureComponent } from 'react'
import { createStructuredSelector } from 'reselect'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { translate } from 'react-i18next'
import type { Currency, Account } from '@ledgerhq/live-common/lib/types'
import type { T } from 'types/common'
import { saveSettings } from 'actions/settings'
import { accountSelector } from 'reducers/accounts'
import { counterValueCurrencySelector, selectedTimeRangeSelector } from 'reducers/settings'
import type { TimeRange } from 'reducers/settings'
import {
BalanceTotal,
BalanceSinceDiff,
BalanceSincePercent,
} from 'components/BalanceSummary/BalanceInfos'
import Box from 'components/base/Box'
import FormattedVal from 'components/base/FormattedVal'
import PillsDaysCount from 'components/PillsDaysCount'
type OwnProps = {
isAvailable: boolean,
totalBalance: number,
sinceBalance: number,
refBalance: number,
accountId: string, // eslint-disable-line
}
type Props = OwnProps & {
counterValue: Currency,
t: T,
account: Account,
saveSettings: ({ selectedTimeRange: TimeRange }) => *,
selectedTimeRange: TimeRange,
}
const mapStateToProps = createStructuredSelector({
account: accountSelector,
counterValue: counterValueCurrencySelector,
selectedTimeRange: selectedTimeRangeSelector,
})
const mapDispatchToProps = {
saveSettings,
}
class AccountBalanceSummaryHeader extends PureComponent<Props> {
handleChangeSelectedTime = item => {
this.props.saveSettings({ selectedTimeRange: item.key })
}
render() {
const {
account,
t,
counterValue,
selectedTimeRange,
isAvailable,
totalBalance,
sinceBalance,
refBalance,
} = this.props
return (
<Box flow={4} mb={2}>
<Box horizontal>
<BalanceTotal
showCryptoEvenIfNotAvailable
isAvailable={isAvailable}
totalBalance={account.balance}
unit={account.unit}
>
<FormattedVal
animateTicker
disableRounding
alwaysShowSign={false}
color="warmGrey"
unit={counterValue.units[0]}
fontSize={6}
showCode
val={totalBalance}
/>
</BalanceTotal>
<Box>
<PillsDaysCount selected={selectedTimeRange} onChange={this.handleChangeSelectedTime} />
</Box>
</Box>
<Box horizontal justifyContent="center" flow={7}>
<BalanceSincePercent
isAvailable={isAvailable}
t={t}
alignItems="center"
totalBalance={totalBalance}
sinceBalance={sinceBalance}
refBalance={refBalance}
since={selectedTimeRange}
/>
<BalanceSinceDiff
isAvailable={isAvailable}
t={t}
counterValue={counterValue}
alignItems="center"
totalBalance={totalBalance}
sinceBalance={sinceBalance}
refBalance={refBalance}
since={selectedTimeRange}
/>
</Box>
</Box>
)
}
}
export default compose(
connect(
mapStateToProps,
mapDispatchToProps,
),
translate(), // FIXME t() is not even needed directly here. should be underlying component responsability to inject it
)(AccountBalanceSummaryHeader)

100
src/components/AccountPage/AccountHeaderActions.js

@ -0,0 +1,100 @@
// @flow
import React, { PureComponent, Fragment } from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { translate } from 'react-i18next'
import styled from 'styled-components'
import type { Account } from '@ledgerhq/live-common/lib/types'
import Tooltip from 'components/base/Tooltip'
import { MODAL_SEND, MODAL_RECEIVE, MODAL_SETTINGS_ACCOUNT } from 'config/constants'
import type { T } from 'types/common'
import { rgba } from 'styles/helpers'
import { openModal } from 'reducers/modals'
import IconAccountSettings from 'icons/AccountSettings'
import IconReceive from 'icons/Receive'
import IconSend from 'icons/Send'
import Box, { Tabbable } from 'components/base/Box'
import Button from 'components/base/Button'
const ButtonSettings = styled(Tabbable).attrs({
cursor: 'pointer',
align: 'center',
justify: 'center',
borderRadius: 1,
})`
width: 40px;
height: 40px;
&:hover {
color: ${p => (p.disabled ? '' : p.theme.colors.dark)};
background: ${p => (p.disabled ? '' : rgba(p.theme.colors.fog, 0.2))};
}
&:active {
background: ${p => (p.disabled ? '' : rgba(p.theme.colors.fog, 0.3))};
}
`
const mapStateToProps = null
const mapDispatchToProps = {
openModal,
}
type OwnProps = {
account: Account,
}
type Props = OwnProps & {
t: T,
openModal: Function,
}
class AccountHeaderActions extends PureComponent<Props> {
render() {
const { account, openModal, t } = this.props
return (
<Box horizontal alignItems="center" justifyContent="flex-end" flow={2}>
{account.operations.length > 0 && (
<Fragment>
<Button small primary onClick={() => openModal(MODAL_SEND, { account })}>
<Box horizontal flow={1} alignItems="center">
<IconSend size={12} />
<Box>{t('app:send.title')}</Box>
</Box>
</Button>
<Button small primary onClick={() => openModal(MODAL_RECEIVE, { account })}>
<Box horizontal flow={1} alignItems="center">
<IconReceive size={12} />
<Box>{t('app:receive.title')}</Box>
</Box>
</Button>
</Fragment>
)}
<Tooltip render={() => t('app:account.settings.title')}>
<ButtonSettings onClick={() => openModal(MODAL_SETTINGS_ACCOUNT, { account })}>
<Box justifyContent="center">
<IconAccountSettings size={16} />
</Box>
</ButtonSettings>
</Tooltip>
</Box>
)
}
}
export default compose(
connect(
mapStateToProps,
mapDispatchToProps,
),
translate(),
)(AccountHeaderActions)

160
src/components/AccountPage/index.js

@ -5,19 +5,8 @@ import { compose } from 'redux'
import { connect } from 'react-redux'
import { translate } from 'react-i18next'
import { Redirect } from 'react-router'
import styled from 'styled-components'
import type { Currency, Account } from '@ledgerhq/live-common/lib/types'
import SyncOneAccountOnMount from 'components/SyncOneAccountOnMount'
import Tooltip from 'components/base/Tooltip'
import TrackPage from 'analytics/TrackPage'
import { MODAL_SEND, MODAL_RECEIVE, MODAL_SETTINGS_ACCOUNT } from 'config/constants'
import type { T } from 'types/common'
import { rgba } from 'styles/helpers'
import { saveSettings } from 'actions/settings'
import { accountSelector } from 'reducers/accounts'
import {
counterValueCurrencySelector,
@ -26,47 +15,19 @@ import {
timeRangeDaysByKey,
} from 'reducers/settings'
import type { TimeRange } from 'reducers/settings'
import { openModal } from 'reducers/modals'
import IconAccountSettings from 'icons/AccountSettings'
import IconReceive from 'icons/Receive'
import IconSend from 'icons/Send'
import TrackPage from 'analytics/TrackPage'
import SyncOneAccountOnMount from 'components/SyncOneAccountOnMount'
import BalanceSummary from 'components/BalanceSummary'
import {
BalanceTotal,
BalanceSinceDiff,
BalanceSincePercent,
} from 'components/BalanceSummary/BalanceInfos'
import Box, { Tabbable } from 'components/base/Box'
import Button from 'components/base/Button'
import FormattedVal from 'components/base/FormattedVal'
import PillsDaysCount from 'components/PillsDaysCount'
import Box from 'components/base/Box'
import OperationsList from 'components/OperationsList'
import StickyBackToTop from 'components/StickyBackToTop'
import AccountHeader from './AccountHeader'
import AccountHeaderActions from './AccountHeaderActions'
import AccountBalanceSummaryHeader from './AccountBalanceSummaryHeader'
import EmptyStateAccount from './EmptyStateAccount'
const ButtonSettings = styled(Tabbable).attrs({
cursor: 'pointer',
align: 'center',
justify: 'center',
borderRadius: 1,
})`
width: 40px;
height: 40px;
&:hover {
color: ${p => (p.disabled ? '' : p.theme.colors.dark)};
background: ${p => (p.disabled ? '' : rgba(p.theme.colors.fog, 0.2))};
}
&:active {
background: ${p => (p.disabled ? '' : rgba(p.theme.colors.fog, 0.3))};
}
`
const mapStateToProps = (state, props) => ({
account: accountSelector(state, { accountId: props.match.params.id }),
counterValue: counterValueCurrencySelector(state),
@ -74,74 +35,54 @@ const mapStateToProps = (state, props) => ({
selectedTimeRange: selectedTimeRangeSelector(state),
})
const mapDispatchToProps = {
openModal,
saveSettings,
}
const mapDispatchToProps = null
type Props = {
counterValue: Currency,
t: T,
account?: Account,
openModal: Function,
saveSettings: ({ selectedTimeRange: TimeRange }) => *,
selectedTimeRange: TimeRange,
}
class AccountPage extends PureComponent<Props> {
handleChangeSelectedTime = item => {
this.props.saveSettings({ selectedTimeRange: item.key })
renderBalanceSummaryHeader = ({ isAvailable, totalBalance, sinceBalance, refBalance }) => {
const { account } = this.props
if (!account) return null
return (
<AccountBalanceSummaryHeader
accountId={account.id}
isAvailable={isAvailable}
totalBalance={totalBalance}
sinceBalance={sinceBalance}
refBalance={refBalance}
/>
)
}
_cacheBalance = null
render() {
const { account, openModal, t, counterValue, selectedTimeRange } = this.props
const { account, t, counterValue, selectedTimeRange } = this.props
const daysCount = timeRangeDaysByKey[selectedTimeRange]
// Don't even throw if we jumped in wrong account route
if (!account) {
return <Redirect to="/" />
}
return (
// Force re-render account page, for avoid animation
// `key` forces re-render account page when going an another account (skip animations)
<Box key={account.id}>
<TrackPage
category="Account"
currency={account.currency.id}
operationsLength={account.operations.length}
/>
<SyncOneAccountOnMount priority={10} accountId={account.id} />
<Box horizontal mb={5} flow={4}>
<AccountHeader account={account} />
<Box horizontal alignItems="center" justifyContent="flex-end" flow={2}>
{account.operations.length > 0 && (
<Fragment>
<Button small primary onClick={() => openModal(MODAL_SEND, { account })}>
<Box horizontal flow={1} alignItems="center">
<IconSend size={12} />
<Box>{t('app:send.title')}</Box>
</Box>
</Button>
<Button small primary onClick={() => openModal(MODAL_RECEIVE, { account })}>
<Box horizontal flow={1} alignItems="center">
<IconReceive size={12} />
<Box>{t('app:receive.title')}</Box>
</Box>
</Button>
</Fragment>
)}
<Tooltip render={() => t('app:account.settings.title')}>
<ButtonSettings onClick={() => openModal(MODAL_SETTINGS_ACCOUNT, { account })}>
<Box justifyContent="center">
<IconAccountSettings size={16} />
</Box>
</ButtonSettings>
</Tooltip>
</Box>
<AccountHeaderActions account={account} />
</Box>
{account.operations.length > 0 ? (
<Fragment>
<Box mb={7}>
@ -152,59 +93,12 @@ class AccountPage extends PureComponent<Props> {
counterValue={counterValue}
daysCount={daysCount}
selectedTimeRange={selectedTimeRange}
renderHeader={({ isAvailable, totalBalance, sinceBalance, refBalance }) => (
<Box flow={4} mb={2}>
<Box horizontal>
<BalanceTotal
showCryptoEvenIfNotAvailable
isAvailable={isAvailable}
totalBalance={account.balance}
unit={account.unit}
>
<FormattedVal
animateTicker
disableRounding
alwaysShowSign={false}
color="warmGrey"
unit={counterValue.units[0]}
fontSize={6}
showCode
val={totalBalance}
/>
</BalanceTotal>
<Box>
<PillsDaysCount
selected={selectedTimeRange}
onChange={this.handleChangeSelectedTime}
/>
</Box>
</Box>
<Box horizontal justifyContent="center" flow={7}>
<BalanceSincePercent
isAvailable={isAvailable}
t={t}
alignItems="center"
totalBalance={totalBalance}
sinceBalance={sinceBalance}
refBalance={refBalance}
since={selectedTimeRange}
/>
<BalanceSinceDiff
isAvailable={isAvailable}
t={t}
counterValue={counterValue}
alignItems="center"
totalBalance={totalBalance}
sinceBalance={sinceBalance}
refBalance={refBalance}
since={selectedTimeRange}
/>
</Box>
</Box>
)}
renderHeader={this.renderBalanceSummaryHeader}
/>
</Box>
<OperationsList account={account} title={t('app:account.lastOperations')} />
<StickyBackToTop />
</Fragment>
) : (

1
src/components/BalanceSummary/index.js

@ -35,6 +35,7 @@ const BalanceSummary = ({
selectedTimeRange,
}: Props) => {
const account = accounts.length === 1 ? accounts[0] : undefined
// FIXME This nesting 😱
return (
<Card p={0} py={5}>
<CalculateBalance accounts={accounts} daysCount={daysCount}>

10
src/components/CalculateBalance.js

@ -32,6 +32,7 @@ type Props = OwnProps & {
balanceStart: number,
balanceEnd: number,
isAvailable: boolean,
hash: string,
}
const mapStateToProps = (state: State, props: OwnProps) => {
@ -71,19 +72,20 @@ const mapStateToProps = (state: State, props: OwnProps) => {
({ ...item, originalValue: originalValues[i] || 0 }),
)
const balanceEnd = balanceHistory[balanceHistory.length - 1].value
return {
isAvailable,
balanceHistory,
balanceStart: balanceHistory[0].value,
balanceEnd: balanceHistory[balanceHistory.length - 1].value,
balanceEnd,
hash: `${balanceHistory.length}_${balanceEnd}`,
}
}
const hash = ({ balanceHistory, balanceEnd }) => `${balanceHistory.length}_${balanceEnd}`
class CalculateBalance extends Component<Props> {
shouldComponentUpdate(nextProps) {
return hash(nextProps) !== hash(this.props)
return nextProps.hash !== this.props.hash
}
render() {
const { children } = this.props

Loading…
Cancel
Save