Browse Source

Merge pull request #187 from loeck/master

Add chart in AccountPage
master
Meriadec Pillet 7 years ago
committed by GitHub
parent
commit
17f0e6fe5d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      package.json
  2. 11
      src/actions/counterValues.js
  3. 12
      src/components/AccountPage/AccountHeader.js
  4. 118
      src/components/AccountPage/index.js
  5. 113
      src/components/BalanceSummary/BalanceInfos.js
  6. 43
      src/components/BalanceSummary/index.js
  7. 2
      src/components/DashboardPage/AccountCard.js
  8. 69
      src/components/DashboardPage/index.js
  9. 36
      src/components/PillsDaysCount.js
  10. 10
      src/components/base/Chart/index.js
  11. 12
      src/components/base/GrowScroll/index.js
  12. 13
      src/components/layout/Default.js
  13. 46
      src/components/modals/AddAccount/index.js
  14. 4
      src/helpers/btc.js
  15. 2
      src/renderer/init.js
  16. 1
      static/i18n/en/dashboard.yml
  17. 2
      static/i18n/en/time.yml
  18. 16
      yarn.lock

2
package.json

@ -49,7 +49,7 @@
"@fortawesome/fontawesome-free-solid": "^5.0.7", "@fortawesome/fontawesome-free-solid": "^5.0.7",
"@fortawesome/react-fontawesome": "^0.0.17", "@fortawesome/react-fontawesome": "^0.0.17",
"@ledgerhq/common": "^4.2.0", "@ledgerhq/common": "^4.2.0",
"@ledgerhq/currencies": "^4.2.2", "@ledgerhq/currencies": "^4.3.0-beta.f8165b69",
"@ledgerhq/hw-app-btc": "^4.2.2", "@ledgerhq/hw-app-btc": "^4.2.2",
"@ledgerhq/hw-app-eth": "^4.2.0", "@ledgerhq/hw-app-eth": "^4.2.0",
"@ledgerhq/hw-transport": "^4.2.0", "@ledgerhq/hw-transport": "^4.2.0",

11
src/actions/counterValues.js

@ -20,7 +20,7 @@ export const updateCounterValues: UpdateCounterValues = payload => ({
payload, payload,
}) })
type FetchCounterValues = (?number) => (Dispatch<*>, Function) => void type FetchCounterValues = (?number) => (Dispatch<*>, Function) => Promise<any>
export const fetchCounterValues: FetchCounterValues = coinType => (dispatch, getState) => { export const fetchCounterValues: FetchCounterValues = coinType => (dispatch, getState) => {
const { accounts, counterValues } = getState() const { accounts, counterValues } = getState()
@ -39,7 +39,7 @@ export const fetchCounterValues: FetchCounterValues = coinType => (dispatch, get
const todayCounterValues = get(counterValues, `${code}-USD.${today}`, null) const todayCounterValues = get(counterValues, `${code}-USD.${today}`, null)
if (todayCounterValues !== null) { if (todayCounterValues !== null) {
return {} return null
} }
return axios return axios
@ -56,11 +56,16 @@ export const fetchCounterValues: FetchCounterValues = coinType => (dispatch, get
})) }))
} }
Promise.all(coinTypes.map(fetchCounterValuesByCoinType)).then(result => { return Promise.all(coinTypes.map(fetchCounterValuesByCoinType)).then(result => {
const newCounterValues = result.reduce((r, v) => { const newCounterValues = result.reduce((r, v) => {
if (v !== null) {
r[v.symbol] = v.values r[v.symbol] = v.values
}
return r return r
}, {}) }, {})
if (Object.keys(newCounterValues).length !== 0) {
dispatch(updateCounterValues(newCounterValues)) dispatch(updateCounterValues(newCounterValues))
}
}) })
} }

12
src/components/AccountPage/AccountHeader.js

@ -17,6 +17,14 @@ const CurName = styled(Text).attrs({
letter-spacing: 1px; letter-spacing: 1px;
` `
const AccountName = styled(Text).attrs({
color: 'dark',
ff: 'Museo Sans',
fontSize: 7,
})`
line-height: 1;
`
type Props = { type Props = {
account: Account, account: Account,
} }
@ -34,9 +42,7 @@ class AccountHeader extends PureComponent<Props> {
)} )}
<Box> <Box>
<CurName>{account.currency.name}</CurName> <CurName>{account.currency.name}</CurName>
<Text ff="Museo Sans|Regular" fontSize={7} color="dark"> <AccountName>{account.name}</AccountName>
{account.name}
</Text>
</Box> </Box>
</Box> </Box>
) )

118
src/components/AccountPage/index.js

@ -11,25 +11,26 @@ import { MODAL_SEND, MODAL_RECEIVE, MODAL_SETTINGS_ACCOUNT } from 'constants'
import type { MapStateToProps } from 'react-redux' import type { MapStateToProps } from 'react-redux'
import type { T, Account } from 'types/common' import type { T, Account } from 'types/common'
import { formatBTC } from 'helpers/format'
import { getAccountById } from 'reducers/accounts' import { getAccountById } from 'reducers/accounts'
import { openModal } from 'reducers/modals' import { openModal } from 'reducers/modals'
import Box, { Card } from 'components/base/Box'
import Button from 'components/base/Button'
import IconControls from 'icons/Controls' import IconControls from 'icons/Controls'
import Text from 'components/base/Text'
import TransactionsList from 'components/TransactionsList'
import IconArrowUp from 'icons/ArrowUp'
import IconArrowDown from 'icons/ArrowDown' import IconArrowDown from 'icons/ArrowDown'
import AccountHeader from './AccountHeader' import IconArrowUp from 'icons/ArrowUp'
type Props = { import BalanceSummary from 'components/BalanceSummary'
t: T, import {
account?: Account, BalanceTotal,
openModal: Function, BalanceSinceDiff,
} BalanceSincePercent,
} from 'components/BalanceSummary/BalanceInfos'
import Box from 'components/base/Box'
import Button from 'components/base/Button'
import FormattedVal from 'components/base/FormattedVal'
import PillsDaysCount from 'components/PillsDaysCount'
import TransactionsList from 'components/TransactionsList'
import AccountHeader from './AccountHeader'
const mapStateToProps: MapStateToProps<*, *, *> = (state, props) => ({ const mapStateToProps: MapStateToProps<*, *, *> = (state, props) => ({
account: getAccountById(state, props.match.params.id), account: getAccountById(state, props.match.params.id),
@ -39,9 +40,32 @@ const mapDispatchToProps = {
openModal, openModal,
} }
class AccountPage extends PureComponent<Props> { type Props = {
t: T,
account?: Account,
openModal: Function,
}
type State = {
selectedTime: string,
daysCount: number,
}
class AccountPage extends PureComponent<Props, State> {
state = {
selectedTime: 'week',
daysCount: 7,
}
handleChangeSelectedTime = item =>
this.setState({
selectedTime: item.key,
daysCount: item.value,
})
render() { render() {
const { account, openModal, t } = this.props const { account, openModal, t } = this.props
const { selectedTime, daysCount } = this.state
// Don't even throw if we jumped in wrong account route // Don't even throw if we jumped in wrong account route
if (!account) { if (!account) {
@ -49,19 +73,19 @@ class AccountPage extends PureComponent<Props> {
} }
return ( return (
<Box flow={7}> <Box>
<Box horizontal> <Box horizontal mb={5}>
<AccountHeader account={account} /> <AccountHeader account={account} />
<Box horizontal alignItems="center" justifyContent="flex-end" grow flow={2}> <Box horizontal alignItems="center" justifyContent="flex-end" grow flow={2}>
<Button primary onClick={() => openModal(MODAL_SEND, { account })}> <Button primary onClick={() => openModal(MODAL_SEND, { account })}>
<Box horizontal flow={2} alignItems="center"> <Box horizontal flow={1} alignItems="center">
<IconArrowUp height={16} width={16} /> <IconArrowUp width={12} />
<Box>{t('send:title')}</Box> <Box>{t('send:title')}</Box>
</Box> </Box>
</Button> </Button>
<Button primary onClick={() => openModal(MODAL_RECEIVE, { account })}> <Button primary onClick={() => openModal(MODAL_RECEIVE, { account })}>
<Box horizontal flow={2} alignItems="center"> <Box horizontal flow={1} alignItems="center">
<IconArrowDown height={16} width={16} /> <IconArrowDown width={12} />
<Box>{t('receive:title')}</Box> <Box>{t('receive:title')}</Box>
</Box> </Box>
</Button> </Button>
@ -75,9 +99,57 @@ class AccountPage extends PureComponent<Props> {
</Button> </Button>
</Box> </Box>
</Box> </Box>
<Card style={{ height: 435 }} alignItems="center" justifyContent="center"> <Box mb={7}>
<Text fontSize={5}>{formatBTC(account.balance)}</Text> <BalanceSummary
</Card> chartColor={account.currency.color}
chartId={`account-chart-${account.id}`}
accounts={[account]}
selectedTime={selectedTime}
daysCount={daysCount}
renderHeader={({ totalBalance, sinceBalance }) => (
<Box flow={4} mb={2}>
<Box horizontal>
<BalanceTotal totalBalance={account.balance} unit={account.unit}>
<Box mt={1}>
<FormattedVal
alwaysShowSign={false}
color="warmGrey"
fiat="USD"
fontSize={6}
showCode
style={{ lineHeight: 1 }}
val={totalBalance}
/>
</Box>
</BalanceTotal>
<Box>
<PillsDaysCount
selectedTime={selectedTime}
onChange={this.handleChangeSelectedTime}
/>
</Box>
</Box>
<Box horizontal justifyContent="center" flow={7}>
<BalanceSincePercent
t={t}
alignItems="center"
totalBalance={totalBalance}
sinceBalance={sinceBalance}
since={selectedTime}
/>
<BalanceSinceDiff
t={t}
fiat="USD"
alignItems="center"
totalBalance={totalBalance}
sinceBalance={sinceBalance}
since={selectedTime}
/>
</Box>
</Box>
)}
/>
</Box>
<TransactionsList <TransactionsList
title={t('account:lastOperations')} title={t('account:lastOperations')}
transactions={account.transactions} transactions={account.transactions}

113
src/components/BalanceSummary/BalanceInfos.js

@ -3,58 +3,117 @@
import React from 'react' import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import type { Unit } from '@ledgerhq/currencies'
import type { T } from 'types/common'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Text from 'components/base/Text' import Text from 'components/base/Text'
import FormattedVal from 'components/base/FormattedVal' import FormattedVal from 'components/base/FormattedVal'
type Props = { const Sub = styled(Text).attrs({
fiat: string, ff: 'Open Sans',
color: 'warnGrey',
fontSize: 4,
})`
text-transform: lowercase;
`
type BalanceSinceProps = {
since: string, since: string,
totalBalance: number, totalBalance: number,
sinceBalance: number, sinceBalance: number,
t: T,
} }
const Sub = styled(Text).attrs({ type BalanceTotalProps = {
ff: 'Open Sans', children?: any,
color: 'warnGrey', fiat?: string,
fontSize: 4, totalBalance: number,
})`` unit?: Unit,
}
function BalanceInfos(props: Props) { type Props = {
const { fiat, totalBalance, since, sinceBalance } = props fiat: string,
} & BalanceSinceProps
export function BalanceSincePercent(props: BalanceSinceProps) {
const { t, totalBalance, sinceBalance, since, ...otherProps } = props
return ( return (
<Box horizontal alignItems="flex-end" flow={7}> <Box {...otherProps}>
<Box grow>
<FormattedVal
fiat={fiat}
val={totalBalance}
alwaysShowSign={false}
showCode
fontSize={8}
color="dark"
style={{ lineHeight: 1 }}
/>
<Sub>{'Total balance'}</Sub>
</Box>
<Box alignItems="flex-end">
<FormattedVal <FormattedVal
isPercent isPercent
val={Math.floor((totalBalance - sinceBalance) / sinceBalance * 100)} val={Math.floor((totalBalance - sinceBalance) / sinceBalance * 100)}
alwaysShowSign alwaysShowSign
fontSize={7} fontSize={7}
/> />
<Sub>since one {since}</Sub> <Sub>{t('time:since', { since: t(`time:${since}`) })}</Sub>
</Box> </Box>
<Box alignItems="flex-end"> )
}
export function BalanceSinceDiff(props: Props) {
const { t, totalBalance, sinceBalance, since, fiat, ...otherProps } = props
return (
<Box {...otherProps}>
<FormattedVal <FormattedVal
fiat="USD" fiat={fiat}
alwaysShowSign alwaysShowSign
showCode showCode
val={totalBalance - sinceBalance} val={totalBalance - sinceBalance}
fontSize={7} fontSize={7}
/> />
<Sub>since one {since}</Sub> <Sub>{t('time:since', { since: t(`time:${since}`) })}</Sub>
</Box> </Box>
)
}
export function BalanceTotal(props: BalanceTotalProps) {
const { fiat, totalBalance, children, unit } = props
return (
<Box grow>
<FormattedVal
alwaysShowSign={false}
color="dark"
fiat={fiat}
fontSize={8}
showCode
style={{ lineHeight: 1 }}
unit={unit}
val={totalBalance}
/>
{children}
</Box>
)
}
BalanceTotal.defaultProps = {
fiat: undefined,
children: null,
unit: undefined,
}
function BalanceInfos(props: Props) {
const { t, fiat, totalBalance, since, sinceBalance } = props
return (
<Box horizontal alignItems="flex-end" flow={7}>
<BalanceTotal fiat={fiat} totalBalance={totalBalance}>
<Sub>{t('dashboard:totalBalance')}</Sub>
</BalanceTotal>
<BalanceSincePercent
alignItems="flex-end"
totalBalance={totalBalance}
sinceBalance={sinceBalance}
since={since}
t={t}
/>
<BalanceSinceDiff
fiat="USD"
alignItems="flex-end"
totalBalance={totalBalance}
sinceBalance={sinceBalance}
since={since}
t={t}
/>
</Box> </Box>
) )
} }

43
src/components/BalanceSummary/index.js

@ -3,7 +3,7 @@
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
import moment from 'moment' import moment from 'moment'
import { formatCurrencyUnit, getFiatUnit } from '@ledgerhq/currencies' import { formatShort, formatCurrencyUnit, getFiatUnit } from '@ledgerhq/currencies'
import type { Accounts } from 'types/common' import type { Accounts } from 'types/common'
@ -13,35 +13,46 @@ import { AreaChart } from 'components/base/Chart'
import Box, { Card } from 'components/base/Box' import Box, { Card } from 'components/base/Box'
import CalculateBalance from 'components/CalculateBalance' import CalculateBalance from 'components/CalculateBalance'
import BalanceInfos from './BalanceInfos'
type Props = { type Props = {
chartColor: string,
chartId: string,
accounts: Accounts, accounts: Accounts,
selectedTime: string, selectedTime: string,
daysCount: number, daysCount: number,
renderHeader: null | Function,
} }
const BalanceSummary = ({ accounts, selectedTime, daysCount }: Props) => ( const BalanceSummary = ({
<Card flow={3} p={0} py={6}> chartColor,
chartId,
accounts,
selectedTime,
daysCount,
renderHeader,
}: Props) => {
const unit = getFiatUnit('USD')
return (
<Card p={0} py={6}>
<CalculateBalance <CalculateBalance
accounts={accounts} accounts={accounts}
daysCount={daysCount} daysCount={daysCount}
render={({ allBalances, totalBalance, sinceBalance }) => ( render={({ allBalances, totalBalance, sinceBalance }) => (
<Fragment> <Fragment>
{renderHeader !== null && (
<Box px={6}> <Box px={6}>
<BalanceInfos {renderHeader({
fiat="USD" totalBalance,
totalBalance={totalBalance} selectedTime,
since={selectedTime} sinceBalance,
sinceBalance={sinceBalance} })}
/>
</Box> </Box>
)}
<Box ff="Open Sans" fontSize={4} color="graphite"> <Box ff="Open Sans" fontSize={4} color="graphite">
<AreaChart <AreaChart
color="#5286f7" color={chartColor}
data={allBalances} data={allBalances}
height={250} height={250}
id="dashboard-chart" id={chartId}
padding={{ padding={{
top: space[6], top: space[6],
bottom: space[6], bottom: space[6],
@ -50,17 +61,19 @@ const BalanceSummary = ({ accounts, selectedTime, daysCount }: Props) => (
}} }}
strokeWidth={2} strokeWidth={2}
renderLabels={d => renderLabels={d =>
formatCurrencyUnit(getFiatUnit('USD'), d.y * 100, { formatCurrencyUnit(unit, d.y * 100, {
showCode: true, showCode: true,
}) })
} }
renderTickX={t => moment(t).format('MMM. D')} renderTickX={t => moment(t).format('MMM. D')}
renderTickY={t => formatShort(unit, t)}
/> />
</Box> </Box>
</Fragment> </Fragment>
)} )}
/> />
</Card> </Card>
) )
}
export default BalanceSummary export default BalanceSummary

2
src/components/DashboardPage/AccountCard.js

@ -86,7 +86,7 @@ const AccountCard = ({
color={account.currency.color} color={account.currency.color}
height={52} height={52}
id={`account-chart-${account.id}`} id={`account-chart-${account.id}`}
linearGradient={[[5, 0.2], [75, 0]]} linearGradient={[[5, 0.2], [100, 0]]}
simple simple
strokeWidth={1.5} strokeWidth={1.5}
/> />

69
src/components/DashboardPage/index.js

@ -18,9 +18,10 @@ import { getVisibleAccounts } from 'reducers/accounts'
import { updateOrderAccounts } from 'actions/accounts' import { updateOrderAccounts } from 'actions/accounts'
import { saveSettings } from 'actions/settings' import { saveSettings } from 'actions/settings'
import BalanceInfos from 'components/BalanceSummary/BalanceInfos'
import BalanceSummary from 'components/BalanceSummary' import BalanceSummary from 'components/BalanceSummary'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Pills from 'components/base/Pills' import PillsDaysCount from 'components/PillsDaysCount'
import Text from 'components/base/Text' import Text from 'components/base/Text'
import TransactionsList from 'components/TransactionsList' import TransactionsList from 'components/TransactionsList'
@ -47,17 +48,12 @@ type State = {
accountsChunk: Array<Array<Account | null>>, accountsChunk: Array<Array<Account | null>>,
allTransactions: Array<Object>, allTransactions: Array<Object>,
selectedTime: string, selectedTime: string,
daysCount: number,
} }
const ACCOUNTS_BY_LINE = 3 const ACCOUNTS_BY_LINE = 3
const ALL_TRANSACTIONS_LIMIT = 10 const ALL_TRANSACTIONS_LIMIT = 10
const itemsTimes = [
{ key: 'week', value: 7 },
{ key: 'month', value: 30 },
{ key: 'year', value: 365 },
]
const getAllTransactions = accounts => { const getAllTransactions = accounts => {
const allTransactions = accounts.reduce((result, account) => { const allTransactions = accounts.reduce((result, account) => {
const transactions = get(account, 'transactions', []) const transactions = get(account, 'transactions', [])
@ -92,18 +88,7 @@ class DashboardPage extends PureComponent<Props, State> {
accountsChunk: getAccountsChunk(this.props.accounts), accountsChunk: getAccountsChunk(this.props.accounts),
allTransactions: getAllTransactions(this.props.accounts), allTransactions: getAllTransactions(this.props.accounts),
selectedTime: 'week', selectedTime: 'week',
} daysCount: 7,
componentWillMount() {
this._itemsTimes = itemsTimes.map(item => ({
...item,
value: item.value,
label: this.props.t(`time:${item.key}`),
}))
}
componentDidMount() {
this._mounted = true
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
@ -115,37 +100,22 @@ class DashboardPage extends PureComponent<Props, State> {
} }
} }
componentWillUnmount() {
this._mounted = false
}
getDaysCount() {
const { selectedTime } = this.state
const selectedTimeItems = this._itemsTimes.find(i => i.key === selectedTime)
return selectedTimeItems && selectedTimeItems.value ? selectedTimeItems.value : 7
}
handleChangeSelectedTime = item => handleChangeSelectedTime = item =>
this.setState({ this.setState({
selectedTime: item.key, selectedTime: item.key,
daysCount: item.value,
}) })
_mounted = false
_itemsTimes = []
render() { render() {
const { push, accounts, t } = this.props const { push, accounts, t } = this.props
const { accountsChunk, allTransactions, selectedTime } = this.state const { accountsChunk, allTransactions, selectedTime, daysCount } = this.state
const daysCount = this.getDaysCount()
const totalAccounts = accounts.length const totalAccounts = accounts.length
return ( return (
<Box flow={7}> <Box flow={7}>
<Box horizontal alignItems="flex-end"> <Box horizontal alignItems="flex-end">
<Box> <Box grow>
<Text color="dark" ff="Museo Sans" fontSize={7}> <Text color="dark" ff="Museo Sans" fontSize={7}>
{t('dashboard:greetings', { name: 'Khalil' })} {t('dashboard:greetings', { name: 'Khalil' })}
</Text> </Text>
@ -155,17 +125,28 @@ class DashboardPage extends PureComponent<Props, State> {
: t('dashboard:noAccounts')} : t('dashboard:noAccounts')}
</Text> </Text>
</Box> </Box>
<Box ml="auto"> <Box>
<Pills <PillsDaysCount selectedTime={selectedTime} onChange={this.handleChangeSelectedTime} />
items={this._itemsTimes}
activeKey={selectedTime}
onChange={this.handleChangeSelectedTime}
/>
</Box> </Box>
</Box> </Box>
{totalAccounts > 0 && ( {totalAccounts > 0 && (
<Fragment> <Fragment>
<BalanceSummary accounts={accounts} selectedTime={selectedTime} daysCount={daysCount} /> <BalanceSummary
chartId="dashboard-chart"
chartColor="#5286f7"
accounts={accounts}
selectedTime={selectedTime}
daysCount={daysCount}
renderHeader={({ totalBalance, selectedTime, sinceBalance }) => (
<BalanceInfos
t={t}
fiat="USD"
totalBalance={totalBalance}
since={selectedTime}
sinceBalance={sinceBalance}
/>
)}
/>
<Box flow={4}> <Box flow={4}>
<Box horizontal alignItems="flex-end"> <Box horizontal alignItems="flex-end">
<Text color="dark" ff="Museo Sans" fontSize={6}> <Text color="dark" ff="Museo Sans" fontSize={6}>

36
src/components/PillsDaysCount.js

@ -0,0 +1,36 @@
// @flow
import React from 'react'
import { translate } from 'react-i18next'
import type { T } from 'types/common'
import Pills from 'components/base/Pills'
type Props = {
selectedTime: string,
onChange: Function,
t: T,
}
const itemsTimes = [
{ key: 'week', value: 7 },
{ key: 'month', value: 30 },
{ key: 'year', value: 365 },
]
function PillsDaysCount(props: Props) {
const { selectedTime, onChange, t } = props
return (
<Pills
items={itemsTimes.map(item => ({
...item,
label: t(`time:${item.key}`),
}))}
activeKey={selectedTime}
onChange={onChange}
/>
)
}
export default translate()(PillsDaysCount)

10
src/components/base/Chart/index.js

@ -206,7 +206,7 @@ export class AreaChart extends PureComponent<Chart> {
static defaultProps = { static defaultProps = {
height: 100, height: 100,
id: 'chart', id: 'chart',
linearGradient: [[5, 0.2], [50, 0]], linearGradient: [[5, 0.2], [100, 0]],
strokeWidth: 2, strokeWidth: 2,
renderLabels: (d: Object) => d.y, renderLabels: (d: Object) => d.y,
renderTickX: (t: any) => t, renderTickX: (t: any) => t,
@ -242,7 +242,7 @@ export class AreaChart extends PureComponent<Chart> {
return ( return (
<WrapperChart <WrapperChart
height={height} height={height}
render={({ width, isAnimationActive }) => ( render={({ width }) => (
<Fragment> <Fragment>
{getLinearGradient({ {getLinearGradient({
linearGradient, linearGradient,
@ -259,11 +259,12 @@ export class AreaChart extends PureComponent<Chart> {
containerComponent={AreaChartContainer} containerComponent={AreaChartContainer}
> >
<VictoryAxis <VictoryAxis
animate={false}
tickCount={6} tickCount={6}
tickFormat={renderTickX} tickFormat={renderTickX}
style={{ style={{
axis: { axis: {
stroke: colors.lightGrey, stroke: colors.fog,
}, },
tickLabels: { tickLabels: {
...tickLabelsStyle, ...tickLabelsStyle,
@ -277,7 +278,7 @@ export class AreaChart extends PureComponent<Chart> {
tickFormat={renderTickY} tickFormat={renderTickY}
style={{ style={{
grid: { grid: {
stroke: colors.lightGrey, stroke: colors.fog,
strokeDasharray: 5, strokeDasharray: 5,
}, },
axis: { axis: {
@ -290,7 +291,6 @@ export class AreaChart extends PureComponent<Chart> {
}} }}
/> />
<VictoryArea <VictoryArea
animate={isAnimationActive ? { duration: ANIMATION_DURATION } : null}
data={data} data={data}
x="name" x="name"
y="value" y="value"

12
src/components/base/GrowScroll/index.js

@ -14,22 +14,34 @@ type Props = {
full: boolean, full: boolean,
maxHeight?: number, maxHeight?: number,
onUpdate: Function, onUpdate: Function,
onScroll: Function,
} }
class GrowScroll extends PureComponent<Props> { class GrowScroll extends PureComponent<Props> {
static defaultProps = { static defaultProps = {
full: false, full: false,
onUpdate: noop, onUpdate: noop,
onScroll: noop,
} }
componentDidMount() { componentDidMount() {
this.handleUpdate(this.props) this.handleUpdate(this.props)
if (this._scrollbar) {
this._scrollbar.addListener(this.props.onScroll)
}
} }
componentWillReceiveProps(nextProps: Props) { componentWillReceiveProps(nextProps: Props) {
this.handleUpdate(nextProps) this.handleUpdate(nextProps)
} }
componentWillUnmount() {
if (this._scrollbar) {
this._scrollbar.removeListener(this.props.onScroll)
}
}
handleUpdate = (props: Props) => { handleUpdate = (props: Props) => {
if (this._scrollbar) { if (this._scrollbar) {
props.onUpdate(this._scrollbar) props.onUpdate(this._scrollbar)

13
src/components/layout/Default.js

@ -48,6 +48,17 @@ class Default extends Component<Props> {
clearTimeout(this._timeout) clearTimeout(this._timeout)
} }
handleScroll = () => {
document.querySelectorAll('.tippy-popper').forEach((p: any) => {
const instance = p._tippy
if (instance.state.visible) {
instance.popperInstance.disableEventListeners()
instance.hide(0)
}
})
}
_timeout = undefined _timeout = undefined
_scrollContainer = null _scrollContainer = null
@ -67,7 +78,7 @@ class Default extends Component<Props> {
<Box shrink grow bg="lightGrey" color="grey" relative> <Box shrink grow bg="lightGrey" color="grey" relative>
<TopBar /> <TopBar />
<UpdateNotifier /> <UpdateNotifier />
<Container innerRef={n => (this._scrollContainer = n)}> <Container innerRef={n => (this._scrollContainer = n)} onScroll={this.handleScroll}>
<Route path="/" exact component={DashboardPage} /> <Route path="/" exact component={DashboardPage} />
<Route path="/settings" component={SettingsPage} /> <Route path="/settings" component={SettingsPage} />
<Route path="/account/:id" component={AccountPage} /> <Route path="/account/:id" component={AccountPage} />

46
src/components/modals/AddAccount/index.js

@ -21,6 +21,7 @@ import { getCurrentDevice } from 'reducers/devices'
import { sendEvent } from 'renderer/events' import { sendEvent } from 'renderer/events'
import { addAccount, updateAccount } from 'actions/accounts' import { addAccount, updateAccount } from 'actions/accounts'
import { fetchCounterValues } from 'actions/counterValues'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Button from 'components/base/Button' import Button from 'components/base/Button'
@ -55,9 +56,13 @@ const Steps = {
/> />
</Box> </Box>
<Box horizontal justifyContent="flex-end"> <Box horizontal justifyContent="flex-end">
{props.fetchingCounterValues ? (
'Fetching counterValues...'
) : (
<Button primary type="submit"> <Button primary type="submit">
{props.t('addAccount:title')} {props.t('addAccount:title')}
</Button> </Button>
)}
</Box> </Box>
</Box> </Box>
</form> </form>
@ -113,41 +118,47 @@ const Steps = {
type Step = 'chooseCurrency' | 'connectDevice' | 'inProgress' | 'listAccounts' type Step = 'chooseCurrency' | 'connectDevice' | 'inProgress' | 'listAccounts'
type Props = { type Props = {
t: T,
accounts: Accounts, accounts: Accounts,
archivedAccounts: Accounts,
addAccount: Function, addAccount: Function,
updateAccount: Function, archivedAccounts: Accounts,
canCreateAccount: boolean, canCreateAccount: boolean,
closeModal: Function, closeModal: Function,
counterValues: Object,
currentDevice: Device | null, currentDevice: Device | null,
fetchCounterValues: Function,
t: T,
updateAccount: Function,
} }
type State = { type State = {
step: Step,
currency: Currency | null,
accounts: Accounts, accounts: Accounts,
currency: Currency | null,
fetchingCounterValues: boolean,
progress: null | Object, progress: null | Object,
step: Step,
} }
const mapStateToProps: MapStateToProps<*, *, *> = state => ({ const mapStateToProps: MapStateToProps<*, *, *> = state => ({
accounts: getAccounts(state), accounts: getAccounts(state),
archivedAccounts: getArchivedAccounts(state), archivedAccounts: getArchivedAccounts(state),
canCreateAccount: canCreateAccount(state), canCreateAccount: canCreateAccount(state),
counterValues: state.counterValues,
currentDevice: getCurrentDevice(state), currentDevice: getCurrentDevice(state),
}) })
const mapDispatchToProps = { const mapDispatchToProps = {
addAccount, addAccount,
updateAccount,
closeModal, closeModal,
fetchCounterValues,
updateAccount,
} }
const defaultState = { const defaultState = {
step: 'chooseCurrency',
progress: null,
fetchingCounterValues: false,
currency: null, currency: null,
accounts: [], accounts: [],
progress: null,
step: 'chooseCurrency',
} }
class AddAccountModal extends PureComponent<Props, State> { class AddAccountModal extends PureComponent<Props, State> {
@ -200,16 +211,17 @@ class AddAccountModal extends PureComponent<Props, State> {
getStepProps() { getStepProps() {
const { currentDevice, archivedAccounts, canCreateAccount, updateAccount, t } = this.props const { currentDevice, archivedAccounts, canCreateAccount, updateAccount, t } = this.props
const { currency, step, progress, accounts } = this.state const { currency, step, progress, accounts, fetchingCounterValues } = this.state
const props = (predicate, props) => (predicate ? props : {}) const props = (predicate, props) => (predicate ? props : {})
return { return {
...props(step === 'chooseCurrency', { ...props(step === 'chooseCurrency', {
t,
currency, currency,
fetchingCounterValues,
onChangeCurrency: this.handleChangeCurrency, onChangeCurrency: this.handleChangeCurrency,
onSubmit: this.handleSubmit, onSubmit: this.handleSubmit,
t,
}), }),
...props(step === 'connectDevice', { ...props(step === 'connectDevice', {
t, t,
@ -271,13 +283,25 @@ class AddAccountModal extends PureComponent<Props, State> {
handleChangeCurrency = (currency: Currency) => this.setState({ currency }) handleChangeCurrency = (currency: Currency) => this.setState({ currency })
handleSubmit = (e: SyntheticEvent<HTMLFormElement>) => { handleSubmit = async (e: SyntheticEvent<HTMLFormElement>) => {
e.preventDefault() e.preventDefault()
const { fetchCounterValues } = this.props
const { currency } = this.state
if (currency !== null) {
this.setState({
fetchingCounterValues: true,
})
await fetchCounterValues(currency.coinType)
this.setState({ this.setState({
fetchingCounterValues: false,
step: 'connectDevice', step: 'connectDevice',
}) })
} }
}
handleClose = () => { handleClose = () => {
sendEvent('msg', 'kill.process', { sendEvent('msg', 'kill.process', {

4
src/helpers/btc.js

@ -154,7 +154,9 @@ export async function getAccount({
try { try {
txs = await ledger.getTransactions(listAddresses, transactionsOpts) txs = await ledger.getTransactions(listAddresses, transactionsOpts)
txs = txs.filter(t => !allTxsHash.includes(t.hash)).reverse() txs = txs.filter(t => !allTxsHash.includes(t.hash)).reverse()
} catch (e) {} // eslint-disable-line no-empty } catch (e) {
console.log('getTransactions', e) // eslint-disable-line no-console
}
const hasTransactions = txs.length > 0 const hasTransactions = txs.length > 0

2
src/renderer/init.js

@ -29,8 +29,8 @@ const history = createHistory()
const store = createStore(history) const store = createStore(history)
const rootNode = document.getElementById('app') const rootNode = document.getElementById('app')
store.dispatch(initCounterValues())
store.dispatch(fetchSettings()) store.dispatch(fetchSettings())
store.dispatch(initCounterValues())
const state = store.getState() || {} const state = store.getState() || {}
const language = getLanguage(state) const language = getLanguage(state)

1
static/i18n/en/dashboard.yml

@ -4,3 +4,4 @@ summary: here is the summary of your account
summary_plural: 'here is the summary of your {{count}} accounts' summary_plural: 'here is the summary of your {{count}} accounts'
noAccounts: no accounts noAccounts: no accounts
recentActivity: Recent activity recentActivity: Recent activity
totalBalance: Total balance

2
static/i18n/en/time.yml

@ -2,3 +2,5 @@ day: Day
week: Week week: Week
month: Month month: Month
year: Year year: Year
since: since one {{since}}

16
yarn.lock

@ -165,10 +165,12 @@
redux "^3.7.2" redux "^3.7.2"
redux-thunk "^2.2.0" redux-thunk "^2.2.0"
"@ledgerhq/currencies@^4.2.2": "@ledgerhq/currencies@^4.3.0-beta.f8165b69":
version "4.2.2" version "4.3.0-beta.f8165b69"
resolved "https://registry.yarnpkg.com/@ledgerhq/currencies/-/currencies-4.2.2.tgz#3fadbdff2b4f7adce9ba255a407bd3999aea3fdc" resolved "https://registry.yarnpkg.com/@ledgerhq/currencies/-/currencies-4.3.0-beta.f8165b69.tgz#bf85e210a1172ec3cc6821af75d39fdd60627963"
dependencies: dependencies:
lodash "^4.17.5"
numeral "^2.0.6"
querystring "^0.2.0" querystring "^0.2.0"
"@ledgerhq/hw-app-btc@^4.2.2": "@ledgerhq/hw-app-btc@^4.2.2":
@ -3422,8 +3424,8 @@ duplexer3@^0.1.4:
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
duplexify@^3.4.2, duplexify@^3.5.3: duplexify@^3.4.2, duplexify@^3.5.3:
version "3.5.3" version "3.5.4"
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.3.tgz#8b5818800df92fd0125b27ab896491912858243e" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.4.tgz#4bb46c1796eabebeec4ca9a2e66b808cb7a3d8b4"
dependencies: dependencies:
end-of-stream "^1.0.0" end-of-stream "^1.0.0"
inherits "^2.0.1" inherits "^2.0.1"
@ -7059,6 +7061,10 @@ number-is-nan@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
numeral@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506"
nwmatcher@^1.4.3: nwmatcher@^1.4.3:
version "1.4.3" version "1.4.3"
resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c" resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c"

Loading…
Cancel
Save