diff --git a/src/__mocks__/render.js b/src/__mocks__/render.js
index 7b945e49..76871dd6 100644
--- a/src/__mocks__/render.js
+++ b/src/__mocks__/render.js
@@ -2,8 +2,10 @@ import React from 'react'
import { Provider } from 'react-redux'
import renderer from 'react-test-renderer'
import { ThemeProvider } from 'styled-components'
+import { I18nextProvider } from 'react-i18next'
import createStore from 'renderer/createStore'
+import i18n from 'renderer/i18n/electron'
import theme from 'styles/theme'
@@ -11,9 +13,11 @@ export default function render(component, state) {
const store = createStore({ state })
return renderer
.create(
-
- {component}
- ,
+
+
+ {component}
+
+ ,
)
.toJSON()
}
diff --git a/src/components/AccountPage/index.js b/src/components/AccountPage/index.js
index 1a750a1d..8615d921 100644
--- a/src/components/AccountPage/index.js
+++ b/src/components/AccountPage/index.js
@@ -168,11 +168,7 @@ class AccountPage extends PureComponent {
)}
/>
-
+
)
}
diff --git a/src/components/DashboardPage/index.js b/src/components/DashboardPage/index.js
index 2e664db5..d1388651 100644
--- a/src/components/DashboardPage/index.js
+++ b/src/components/DashboardPage/index.js
@@ -5,11 +5,9 @@ import { compose } from 'redux'
import { translate } from 'react-i18next'
import { connect } from 'react-redux'
import { push } from 'react-router-redux'
-import type { Account, Operation } from '@ledgerhq/wallet-common/lib/types'
+import type { Account } from '@ledgerhq/wallet-common/lib/types'
import chunk from 'lodash/chunk'
-import get from 'lodash/get'
-import sortBy from 'lodash/sortBy'
import type { T } from 'types/common'
@@ -49,33 +47,11 @@ type Props = {
type State = {
accountsChunk: Array>,
- allOperations: Operation[],
selectedTime: string,
daysCount: number,
}
const ACCOUNTS_BY_LINE = 3
-const ALL_OPERATIONS_LIMIT = 10
-
-const getAllOperations = accounts => {
- const allOperations = accounts.reduce((result, account) => {
- const operations = get(account, 'operations', [])
-
- result = [
- ...result,
- ...operations.map(t => ({
- ...t,
- account,
- })),
- ]
-
- return result
- }, [])
-
- return sortBy(allOperations, t => t.date)
- .reverse()
- .slice(0, ALL_OPERATIONS_LIMIT)
-}
const getAccountsChunk = accounts => {
// create shallow copy of accounts, to be mutated
@@ -89,7 +65,6 @@ const getAccountsChunk = accounts => {
class DashboardPage extends PureComponent {
state = {
accountsChunk: getAccountsChunk(this.props.accounts),
- allOperations: getAllOperations(this.props.accounts),
selectedTime: 'week',
daysCount: 7,
}
@@ -98,7 +73,6 @@ class DashboardPage extends PureComponent {
if (nextProps.accounts !== this.props.accounts) {
this.setState({
accountsChunk: getAccountsChunk(nextProps.accounts),
- allOperations: getAllOperations(nextProps.accounts),
})
}
}
@@ -111,7 +85,7 @@ class DashboardPage extends PureComponent {
render() {
const { push, accounts, t, counterValue } = this.props
- const { accountsChunk, allOperations, selectedTime, daysCount } = this.state
+ const { accountsChunk, selectedTime, daysCount } = this.state
const totalAccounts = accounts.length
@@ -193,7 +167,7 @@ class DashboardPage extends PureComponent {
push(`/account/${account.id}`)}
- operations={allOperations}
+ accounts={accounts}
title={t('dashboard:recentActivity')}
withAccount
/>
diff --git a/src/components/OperationsList/index.js b/src/components/OperationsList/index.js
index 3d8103d1..65561511 100644
--- a/src/components/OperationsList/index.js
+++ b/src/components/OperationsList/index.js
@@ -1,16 +1,20 @@
// @flow
-import React, { Component } from 'react'
+import React, { PureComponent } from 'react'
import styled from 'styled-components'
import moment from 'moment'
import { connect } from 'react-redux'
import { compose } from 'redux'
import { translate } from 'react-i18next'
import { getIconByCoinType } from '@ledgerhq/currencies/react'
+import {
+ groupAccountOperationsByDay,
+ groupAccountsOperationsByDay,
+} from '@ledgerhq/wallet-common/lib/helpers/account'
import type { Account, Operation as OperationType } from '@ledgerhq/wallet-common/lib/types'
import noop from 'lodash/noop'
-import isEqual from 'lodash/isEqual'
+import keyBy from 'lodash/keyBy'
import type { T } from 'types/common'
@@ -22,9 +26,9 @@ import IconAngleDown from 'icons/AngleDown'
import Box, { Card } from 'components/base/Box'
import CounterValue from 'components/CounterValue'
-import Defer from 'components/base/Defer'
import FormattedVal from 'components/base/FormattedVal'
import Text from 'components/base/Text'
+import Defer from 'components/base/Defer'
import ConfirmationCheck from './ConfirmationCheck'
@@ -33,6 +37,14 @@ const ACCOUNT_COL_SIZE = 150
const AMOUNT_COL_SIZE = 150
const CONFIRMATION_COL_SIZE = 44
+const calendarOpts = {
+ sameDay: 'LL – [Today]',
+ nextDay: 'LL – [Tomorrow]',
+ lastDay: 'LL – [Yesterday]',
+ lastWeek: 'LL',
+ sameElse: 'LL',
+}
+
const Day = styled(Text).attrs({
color: 'dark',
fontSize: 3,
@@ -69,6 +81,7 @@ const Cell = styled(Box).attrs({
alignItems: 'center',
})`
width: ${p => (p.size ? `${p.size}px` : '')};
+ overflow: ${p => (p.noOverflow ? 'hidden' : '')};
`
const ShowMore = styled(Box).attrs({
@@ -155,6 +168,7 @@ const Operation = ({
{withAccount &&
account && (
{
+export class OperationsList extends PureComponent {
static defaultProps = {
- account: null,
onAccountClick: noop,
withAccount: false,
canShowMore: false,
+ nbToShow: 20,
}
- shouldComponentUpdate(nextProps: Props) {
- if (this.props.account !== nextProps.account) {
- return true
- }
-
- if (this.props.withAccount !== nextProps.withAccount) {
- return true
- }
-
- if (this.props.canShowMore !== nextProps.canShowMore) {
- return true
- }
-
- if (this._hashCache === null) {
- return true
- }
-
- return !isEqual(this._hashCache, this.getHashCache(nextProps.operations))
- }
-
- getHashCache = (operations: OperationType[]) => operations.map(t => t.id)
-
handleClickOperation = (data: Object) => this.props.openModal(MODAL_OPERATION_DETAILS, data)
- _hashCache = null
-
render() {
- const { account, canShowMore, onAccountClick, operations, t, title, withAccount } = this.props
+ const {
+ account,
+ title,
+ accounts,
+ canShowMore,
+ onAccountClick,
+ t,
+ withAccount,
+ nbToShow,
+ } = this.props
+
+ if (!account && !accounts) {
+ console.warn('Preventing render OperationsList because not received account or accounts') // eslint-disable-line no-console
+ return null
+ }
+ const groupedOperations = accounts
+ ? groupAccountsOperationsByDay(accounts, nbToShow)
+ : groupAccountOperationsByDay(account, nbToShow)
- this._hashCache = this.getHashCache(operations)
+ const accountsMap = accounts ? keyBy(accounts, 'id') : { [account.id]: account }
return (
-
-
-
- {operations.map(op => {
- // $FlowFixMe
- const acc = account || op.account
- return (
-
- )
- })}
-
-
+
+ {title && (
+
+ {title}
+
+ )}
+ {groupedOperations.map(group => {
+ const d = moment(group.day)
+ return (
+
+
+ {d.calendar(null, calendarOpts)}
+
+
+ {group.data.map(op => {
+ const account = accountsMap[op.accountId]
+ if (!account) {
+ return null
+ }
+ return (
+
+ )
+ })}
+
+
+ )
+ })}
{canShowMore && (
{t('operationsList:showMore')}
diff --git a/src/components/OperationsList/stories.js b/src/components/OperationsList/stories.js
index ebe1f11b..b144eac1 100644
--- a/src/components/OperationsList/stories.js
+++ b/src/components/OperationsList/stories.js
@@ -1,78 +1,24 @@
// @flow
import React from 'react'
-import { getCurrencyByCoinType, getDefaultUnitByCoinType } from '@ledgerhq/currencies'
+import { genAccount } from '@ledgerhq/wallet-common/lib/mock/account'
import { storiesOf } from '@storybook/react'
import { boolean } from '@storybook/addon-knobs'
-import { accounts } from 'components/SelectAccount/stories'
-
import OperationsList from 'components/OperationsList'
+import Box from 'components/base/Box'
const stories = storiesOf('Components', module)
-const unit = getDefaultUnitByCoinType(0)
-
-const account = ({ name }) => ({
- ...accounts[0],
- minConfirmations: 10,
- currency: getCurrencyByCoinType(0),
- name,
- coinType: 0,
- unit,
-})
-
-const operations = [
- {
- address: '5c6ea1716520c7d6e038d36a3223faced3c',
- hash: '5c6ea1716520c7d6e038d36a3223faced3c4b8f7ffb69d9fb5bd527d562fdb62',
- id: '5c6ea1716520c7d6e038d36a3223faced3c4b8f7ffb69d9fb5bd527d562fdb62',
- amount: 1.3e8,
- date: new Date('2018-01-09T16:03:52Z'),
- confirmations: 1,
- account: account({
- name: 'Account 1',
- }),
- },
- {
- address: '5c6ea1716520c7d6e038d36a3223faced3c',
- hash: '26bdf265d725db5bf9d96bff7f8b4c3decaf3223a63d830e6d7c0256171ae6c5',
- id: '26bdf265d725db5bf9d96bff7f8b4c3decaf3223a63d830e6d7c0256171ae6c5',
- amount: 1.6e8,
- date: new Date('2018-01-09T16:03:52Z'),
- confirmations: 11,
- account: account({
- name: 'Account 1',
- }),
- },
- {
- address: '27416a48caab90fab053b507b8b6b9d4',
- hash: '27416a48caab90fab053b507b8b6b9d48fba75421d3bfdbae4b85f64024bc9c4',
- id: '27416a48caab90fab053b507b8b6b9d48fba75421d3bfdbae4b85f64024bc9c4',
- amount: -6.5e8,
- date: new Date('2018-01-09T16:02:40Z'),
- confirmations: 11,
- account: account({
- name: 'Account 2',
- }),
- },
- {
- address: '27416a48caab90fab053b507b8b6b9d4',
- hash: '4c9cb42046f58b4eabdfb3d12457abf84d9b6b8b705b350baf09baac84a61472',
- id: '4c9cb42046f58b4eabdfb3d12457abf84d9b6b8b705b350baf09baac84a61472',
- amount: -4.2e8,
- date: new Date('2018-01-09T16:02:40Z'),
- confirmations: 1,
- account: account({
- name: 'Account 2',
- }),
- },
-]
+const account1 = genAccount('account1')
+const account2 = genAccount('account2')
stories.add('OperationsList', () => (
-
+
+
+
))
diff --git a/src/components/SettingsPage/index.js b/src/components/SettingsPage/index.js
index 826455a7..725549f2 100644
--- a/src/components/SettingsPage/index.js
+++ b/src/components/SettingsPage/index.js
@@ -4,6 +4,7 @@ import React, { PureComponent } from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { translate } from 'react-i18next'
+import moment from 'moment'
import type { Settings, T } from 'types/common'
import type { SaveSettings } from 'actions/settings'
@@ -56,6 +57,7 @@ class SettingsPage extends PureComponent {
if (newSettings.language !== settings.language) {
i18n.changeLanguage(newSettings.language)
+ moment.locale(newSettings.language)
}
if (newSettings.counterValue !== settings.counterValue) {
diff --git a/src/helpers/staticPath.js b/src/helpers/staticPath.js
index 1351ec63..102fe5a7 100644
--- a/src/helpers/staticPath.js
+++ b/src/helpers/staticPath.js
@@ -7,4 +7,4 @@ export default (__DEV__ && !STORYBOOK_ENV && NODE_ENV !== 'test'
? __static
: isRunningInAsar
? __dirname.replace(/app\.asar$/, 'static')
- : !STORYBOOK_ENV ? `${__dirname}/../static` : 'static')
+ : !STORYBOOK_ENV ? `${__dirname}/../../static` : 'static')
diff --git a/src/renderer/i18n/instanciate.js b/src/renderer/i18n/instanciate.js
index d8a6eec8..a4ff9e7b 100644
--- a/src/renderer/i18n/instanciate.js
+++ b/src/renderer/i18n/instanciate.js
@@ -4,7 +4,7 @@ const commonConfig = {
fallbackLng: 'en',
debug: false,
react: {
- wait: true,
+ wait: process.env.NODE_ENV !== 'test',
},
}
diff --git a/src/renderer/init.js b/src/renderer/init.js
index f7dae0a8..63a5acb4 100644
--- a/src/renderer/init.js
+++ b/src/renderer/init.js
@@ -5,6 +5,7 @@ import { remote } from 'electron'
import { render } from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import createHistory from 'history/createHashHistory'
+import moment from 'moment'
import createStore from 'renderer/createStore'
import events from 'renderer/events'
@@ -37,6 +38,8 @@ const state = store.getState() || {}
const language = getLanguage(state)
const locked = isLocked(state)
+moment.locale(language)
+
function r(Comp) {
if (rootNode) {
render({Comp}, rootNode)
|