Browse Source
this also start splitting a bit the AccountPage component as CalculateBalance will memoize things, we want inner part to be potentially re-render if they depend on other things, we do this by connecting them to redux. redux idea is to connect leafs instead of connecting the whole tree when possible, so this fit this paradigm to me.master
Gaëtan Renaudeau
7 years ago
5 changed files with 259 additions and 137 deletions
@ -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) |
@ -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) |
Loading…
Reference in new issue