diff --git a/package.json b/package.json index ebbe3e54..dfb8b8ae 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@fortawesome/fontawesome-free-solid": "^5.0.7", "@fortawesome/react-fontawesome": "^0.0.17", "@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-eth": "^4.2.0", "@ledgerhq/hw-transport": "^4.2.0", diff --git a/src/components/AccountPage/AccountHeader.js b/src/components/AccountPage/AccountHeader.js index 6a2bc63a..f90d2191 100644 --- a/src/components/AccountPage/AccountHeader.js +++ b/src/components/AccountPage/AccountHeader.js @@ -17,6 +17,14 @@ const CurName = styled(Text).attrs({ letter-spacing: 1px; ` +const AccountName = styled(Text).attrs({ + color: 'dark', + ff: 'Museo Sans', + fontSize: 7, +})` + line-height: 1; +` + type Props = { account: Account, } @@ -34,9 +42,7 @@ class AccountHeader extends PureComponent { )} {account.currency.name} - - {account.name} - + {account.name} ) diff --git a/src/components/AccountPage/index.js b/src/components/AccountPage/index.js index ce447ce0..633930d0 100644 --- a/src/components/AccountPage/index.js +++ b/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 { T, Account } from 'types/common' -import { formatBTC } from 'helpers/format' - import { getAccountById } from 'reducers/accounts' import { openModal } from 'reducers/modals' -import Box, { Card } from 'components/base/Box' -import Button from 'components/base/Button' 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 AccountHeader from './AccountHeader' +import IconArrowUp from 'icons/ArrowUp' -type Props = { - t: T, - account?: Account, - openModal: Function, -} +import BalanceSummary from 'components/BalanceSummary' +import { + BalanceTotal, + 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) => ({ account: getAccountById(state, props.match.params.id), @@ -39,9 +40,32 @@ const mapDispatchToProps = { openModal, } -class AccountPage extends PureComponent { +type Props = { + t: T, + account?: Account, + openModal: Function, +} + +type State = { + selectedTime: string, + daysCount: number, +} + +class AccountPage extends PureComponent { + state = { + selectedTime: 'week', + daysCount: 7, + } + + handleChangeSelectedTime = item => + this.setState({ + selectedTime: item.key, + daysCount: item.value, + }) + render() { const { account, openModal, t } = this.props + const { selectedTime, daysCount } = this.state // Don't even throw if we jumped in wrong account route if (!account) { @@ -49,19 +73,19 @@ class AccountPage extends PureComponent { } return ( - - + + @@ -75,9 +99,55 @@ class AccountPage extends PureComponent { - - {formatBTC(account.balance)} - + + ( + + + + + + + + + + + + + + + + + )} + /> + + + since one {since} + + ) +} + +export function BalanceSinceDiff(props: Props) { + const { totalBalance, sinceBalance, since, fiat, ...otherProps } = props + return ( + + + since one {since} + + ) +} + +export function BalanceTotal(props: BalanceTotalProps) { + const { fiat, totalBalance, children, unit } = props + return ( + + + {children} + + ) +} + +BalanceTotal.defaultProps = { + fiat: undefined, + children: null, + unit: undefined, +} + function BalanceInfos(props: Props) { const { fiat, totalBalance, since, sinceBalance } = props return ( - - + {'Total balance'} - - - - since one {since} - - - - since one {since} - + + + ) } diff --git a/src/components/BalanceSummary/index.js b/src/components/BalanceSummary/index.js index 71cf4d03..a42bcd3b 100644 --- a/src/components/BalanceSummary/index.js +++ b/src/components/BalanceSummary/index.js @@ -3,7 +3,7 @@ import React, { Fragment } from 'react' import moment from 'moment' -import { formatCurrencyUnit, getFiatUnit } from '@ledgerhq/currencies' +import { formatShort, formatCurrencyUnit, getFiatUnit } from '@ledgerhq/currencies' import type { Accounts } from 'types/common' @@ -13,54 +13,67 @@ import { AreaChart } from 'components/base/Chart' import Box, { Card } from 'components/base/Box' import CalculateBalance from 'components/CalculateBalance' -import BalanceInfos from './BalanceInfos' - type Props = { + chartColor: string, + chartId: string, accounts: Accounts, selectedTime: string, daysCount: number, + renderHeader: null | Function, } -const BalanceSummary = ({ accounts, selectedTime, daysCount }: Props) => ( - - ( - - - - - - - formatCurrencyUnit(getFiatUnit('USD'), d.y * 100, { - showCode: true, - }) - } - renderTickX={t => moment(t).format('MMM. D')} - /> - - - )} - /> - -) +const BalanceSummary = ({ + chartColor, + chartId, + accounts, + selectedTime, + daysCount, + renderHeader, +}: Props) => { + const unit = getFiatUnit('USD') + return ( + + ( + + {renderHeader !== null && ( + + {renderHeader({ + totalBalance, + selectedTime, + sinceBalance, + })} + + )} + + + formatCurrencyUnit(unit, d.y * 100, { + showCode: true, + }) + } + renderTickX={t => moment(t).format('MMM. D')} + renderTickY={t => formatShort(unit, t)} + /> + + + )} + /> + + ) +} export default BalanceSummary diff --git a/src/components/DashboardPage/index.js b/src/components/DashboardPage/index.js index 287440cc..a53c6f41 100644 --- a/src/components/DashboardPage/index.js +++ b/src/components/DashboardPage/index.js @@ -18,9 +18,10 @@ import { getVisibleAccounts } from 'reducers/accounts' import { updateOrderAccounts } from 'actions/accounts' import { saveSettings } from 'actions/settings' +import BalanceInfos from 'components/BalanceSummary/BalanceInfos' import BalanceSummary from 'components/BalanceSummary' import Box from 'components/base/Box' -import Pills from 'components/base/Pills' +import PillsDaysCount from 'components/PillsDaysCount' import Text from 'components/base/Text' import TransactionsList from 'components/TransactionsList' @@ -47,17 +48,12 @@ type State = { accountsChunk: Array>, allTransactions: Array, selectedTime: string, + daysCount: number, } const ACCOUNTS_BY_LINE = 3 const ALL_TRANSACTIONS_LIMIT = 10 -const itemsTimes = [ - { key: 'week', value: 7 }, - { key: 'month', value: 30 }, - { key: 'year', value: 365 }, -] - const getAllTransactions = accounts => { const allTransactions = accounts.reduce((result, account) => { const transactions = get(account, 'transactions', []) @@ -92,18 +88,7 @@ class DashboardPage extends PureComponent { accountsChunk: getAccountsChunk(this.props.accounts), allTransactions: getAllTransactions(this.props.accounts), selectedTime: 'week', - } - - componentWillMount() { - this._itemsTimes = itemsTimes.map(item => ({ - ...item, - value: item.value, - label: this.props.t(`time:${item.key}`), - })) - } - - componentDidMount() { - this._mounted = true + daysCount: 7, } componentWillReceiveProps(nextProps) { @@ -115,37 +100,22 @@ class DashboardPage extends PureComponent { } } - 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 => this.setState({ selectedTime: item.key, + daysCount: item.value, }) - _mounted = false - _itemsTimes = [] - render() { 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 return ( - + {t('dashboard:greetings', { name: 'Khalil' })} @@ -155,17 +125,27 @@ class DashboardPage extends PureComponent { : t('dashboard:noAccounts')} - - + + {totalAccounts > 0 && ( - + ( + + )} + /> diff --git a/src/components/PillsDaysCount.js b/src/components/PillsDaysCount.js new file mode 100644 index 00000000..53fe1fdc --- /dev/null +++ b/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 ( + ({ + ...item, + label: t(`time:${item.key}`), + }))} + activeKey={selectedTime} + onChange={onChange} + /> + ) +} + +export default translate()(PillsDaysCount) diff --git a/src/components/base/Chart/index.js b/src/components/base/Chart/index.js index fe8e99dc..1830990d 100644 --- a/src/components/base/Chart/index.js +++ b/src/components/base/Chart/index.js @@ -242,7 +242,7 @@ export class AreaChart extends PureComponent { return ( ( + render={({ width }) => ( {getLinearGradient({ linearGradient, @@ -259,11 +259,12 @@ export class AreaChart extends PureComponent { containerComponent={AreaChartContainer} > { tickFormat={renderTickY} style={{ grid: { - stroke: colors.lightGrey, + stroke: colors.fog, strokeDasharray: 5, }, axis: { @@ -290,7 +291,6 @@ export class AreaChart extends PureComponent { }} /> { static defaultProps = { full: false, onUpdate: noop, + onScroll: noop, } componentDidMount() { this.handleUpdate(this.props) + + if (this._scrollbar) { + this._scrollbar.addListener(this.handleScroll) + } } componentWillReceiveProps(nextProps: Props) { this.handleUpdate(nextProps) } + componentWillUnmount() { + if (this._scrollbar) { + this._scrollbar.removeListener(this.handleScroll) + } + } + handleUpdate = (props: Props) => { if (this._scrollbar) { props.onUpdate(this._scrollbar) } } + handleScroll = this.props.onScroll + _scrollbar = undefined render() { diff --git a/src/components/layout/Default.js b/src/components/layout/Default.js index 23b5430d..684a7a90 100644 --- a/src/components/layout/Default.js +++ b/src/components/layout/Default.js @@ -48,6 +48,17 @@ class Default extends Component { 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 _scrollContainer = null @@ -67,7 +78,7 @@ class Default extends Component { - (this._scrollContainer = n)}> + (this._scrollContainer = n)} onScroll={this.handleScroll}> diff --git a/src/helpers/btc.js b/src/helpers/btc.js index ddc62008..5e25cc99 100644 --- a/src/helpers/btc.js +++ b/src/helpers/btc.js @@ -154,7 +154,9 @@ export async function getAccount({ try { txs = await ledger.getTransactions(listAddresses, transactionsOpts) 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 diff --git a/yarn.lock b/yarn.lock index 2cd13aa8..3b5f191f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -165,10 +165,12 @@ redux "^3.7.2" redux-thunk "^2.2.0" -"@ledgerhq/currencies@^4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@ledgerhq/currencies/-/currencies-4.2.2.tgz#3fadbdff2b4f7adce9ba255a407bd3999aea3fdc" +"@ledgerhq/currencies@^4.3.0-beta.f8165b69": + version "4.3.0-beta.f8165b69" + resolved "https://registry.yarnpkg.com/@ledgerhq/currencies/-/currencies-4.3.0-beta.f8165b69.tgz#bf85e210a1172ec3cc6821af75d39fdd60627963" dependencies: + lodash "^4.17.5" + numeral "^2.0.6" querystring "^0.2.0" "@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" duplexify@^3.4.2, duplexify@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.3.tgz#8b5818800df92fd0125b27ab896491912858243e" + version "3.5.4" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.4.tgz#4bb46c1796eabebeec4ca9a2e66b808cb7a3d8b4" dependencies: end-of-stream "^1.0.0" inherits "^2.0.1" @@ -7059,6 +7061,10 @@ number-is-nan@^1.0.0: version "1.0.1" 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: version "1.4.3" resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c"