diff --git a/package.json b/package.json index e15c7742..51a2b74b 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "cross-env": "^5.1.4", "d3": "^4.13.0", "debug": "^3.1.0", - "downshift": "^1.31.1", + "downshift": "^1.31.2", "electron-store": "^1.3.0", "electron-updater": "^2.21.1", "fuse.js": "^3.2.0", diff --git a/src/components/AccountPage/index.js b/src/components/AccountPage/index.js index 3e5aa4d3..681b5c80 100644 --- a/src/components/AccountPage/index.js +++ b/src/components/AccountPage/index.js @@ -158,7 +158,6 @@ class AccountPage extends PureComponent { diff --git a/src/components/OperationsList/ConfirmationCheck.js b/src/components/OperationsList/ConfirmationCheck.js index 52874ac7..f2ce085d 100644 --- a/src/components/OperationsList/ConfirmationCheck.js +++ b/src/components/OperationsList/ConfirmationCheck.js @@ -7,27 +7,52 @@ import { rgba } from 'styles/helpers' import type { T } from 'types/common' +import IconArrowDown from 'icons/ArrowDown' +import IconArrowUp from 'icons/ArrowUp' +import IconClock from 'icons/Clock' + import Box from 'components/base/Box' import Tooltip from 'components/base/Tooltip' -import IconCheck from 'icons/Check' -import IconClock from 'icons/Clock' const Container = styled(Box).attrs({ - bg: p => rgba(p.isConfirmed ? p.theme.colors.positiveGreen : p.theme.colors.grey, 0.1), - color: p => (p.isConfirmed ? p.theme.colors.positiveGreen : p.theme.colors.grey), + bg: p => + p.isConfirmed + ? rgba(p.type === 'from' ? p.theme.colors.positiveGreen : p.theme.colors.grey, 0.1) + : 'none', + color: p => (p.type === 'from' ? p.theme.colors.positiveGreen : p.theme.colors.grey), align: 'center', justify: 'center', })` - width: 24px; + border: ${p => + !p.isConfirmed + ? `1px solid ${ + p.type === 'from' ? p.theme.colors.positiveGreen : rgba(p.theme.colors.grey, 0.2) + }` + : 0}; + border-radius: 50%; + position: relative; height: 24px; + width: 24px; +` + +const WrapperClock = styled(Box).attrs({ + bg: 'white', + color: 'grey', +})` border-radius: 50%; + position: absolute; + bottom: -4px; + right: -4px; + padding: 1px; ` const ConfirmationCheck = ({ + type, confirmations, minConfirmations, t, }: { + type: 'to' | 'from', confirmations: number, minConfirmations: number, t: T, @@ -39,8 +64,13 @@ const ConfirmationCheck = ({ isConfirmed ? t('operationsList:confirmed') : t('operationsList:notConfirmed') } > - - {isConfirmed ? : } + + {type === 'from' ? : } + {!isConfirmed && ( + + + + )} ) diff --git a/src/components/OperationsList/index.js b/src/components/OperationsList/index.js index aca9483b..5feaa6ff 100644 --- a/src/components/OperationsList/index.js +++ b/src/components/OperationsList/index.js @@ -3,14 +3,20 @@ import React, { Component } 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 { getDefaultUnitByCoinType } from '@ledgerhq/currencies' + import get from 'lodash/get' import noop from 'lodash/noop' import isEqual from 'lodash/isEqual' -import { getIconByCoinType } from '@ledgerhq/currencies/react' import type { Account, Operation as OperationType, T } from 'types/common' +import { getCounterValue } from 'reducers/settings' + import IconAngleDown from 'icons/AngleDown' import Box, { Card } from 'components/base/Box' @@ -19,19 +25,11 @@ import FormattedVal from 'components/base/FormattedVal' import Text from 'components/base/Text' import ConfirmationCheck from './ConfirmationCheck' -const DATE_COL_SIZE = 80 +const DATE_COL_SIZE = 100 const ACCOUNT_COL_SIZE = 150 const AMOUNT_COL_SIZE = 150 const CONFIRMATION_COL_SIZE = 44 -const Cap = styled(Text).attrs({ - fontSize: 2, - color: 'graphite', - ff: 'Museo Sans|Bold', -})` - text-transform: uppercase; -` - const Day = styled(Text).attrs({ color: 'dark', fontSize: 3, @@ -42,26 +40,15 @@ const Day = styled(Text).attrs({ ` const Hour = styled(Day).attrs({ - color: 'graphite', + color: 'grey', })`` -const HeaderCol = ({ size, children, ...props }: { size?: number, children?: any }) => ( - - {children} - -) - -HeaderCol.defaultProps = { - size: undefined, - children: undefined, -} - const OperationRaw = styled(Box).attrs({ horizontal: true, alignItems: 'center', })` cursor: pointer; - border-bottom: 1px solid ${p => p.theme.colors.fog}; + border-bottom: 1px solid ${p => p.theme.colors.lightGrey}; height: 68px; &:last-child { @@ -91,89 +78,124 @@ const ShowMore = styled(Box).attrs({ p: 4, color: 'wallet', })` - border-top: 1px solid ${p => p.theme.colors.fog}; cursor: pointer; &:hover { text-decoration: underline; } ` +const AddressEllipsis = styled.div` + display: block; + flex-shrink: 1; + min-width: 20px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +` + +const Address = ({ value }: { value: string }) => { + const addrSize = value.length / 2 + + const left = value.slice(0, 10) + const right = value.slice(-addrSize) + const middle = value.slice(10, -addrSize) + + return ( + +
{left}
+ {middle} +
{right}
+
+ ) +} + const Operation = ({ account, - t, + counterValue, + counterValues, + minConfirmations, onAccountClick, + t, tx, withAccount, - minConfirmations, }: { - account: Account | null, - t: T, + account: Account, + counterValue: string, + counterValues: Object | null, + minConfirmations: number, onAccountClick?: Function, + t: T, tx: OperationType, withAccount?: boolean, - minConfirmations: number, }) => { - const acc = account || tx.account + const { unit } = account const time = moment(tx.receivedAt) - const Icon = getIconByCoinType(get(tx, 'account.currency.coinType')) + const Icon = getIconByCoinType(get(account, 'currency.coinType')) + const type = tx.amount > 0 ? 'from' : 'to' + return ( - + + + + - {time.format('DD MMM')} + + {t(`operationsList:${type}`)} + {time.format('HH:mm')} {withAccount && - acc && ( + account && ( onAccountClick && onAccountClick(acc)} + onClick={() => onAccountClick && onAccountClick(account)} > - + {Icon && } - - {acc.name} + + {account.name} )} - - - {tx.amount > 0 ? t('operationsList:from') : t('operationsList:to')} - - - {tx.address} - + +
- - - - - + + + + {counterValues && ( + + )} + ) @@ -184,10 +206,16 @@ Operation.defaultProps = { withAccount: false, } +const mapStateToProps = state => ({ + counterValue: getCounterValue(state), + counterValues: state.counterValues, +}) + type Props = { - account: Account | null, + account: Account, canShowMore: boolean, - minConfirmations: number, + counterValue: string, + counterValues: Object, onAccountClick?: Function, operations: OperationType[], t: T, @@ -195,21 +223,24 @@ type Props = { withAccount?: boolean, } -class OperationsList extends Component { +export class OperationsList extends Component { static defaultProps = { account: null, onAccountClick: noop, withAccount: false, - minConfirmations: 2, canShowMore: false, } shouldComponentUpdate(nextProps: Props) { - if (this.props.canShowMore !== nextProps.canShowMore) { + if (this.props.account !== nextProps.account) { + return true + } + + if (this.props.withAccount !== nextProps.withAccount) { return true } - if (this.props.minConfirmations !== nextProps.minConfirmations) { + if (this.props.canShowMore !== nextProps.canShowMore) { return true } @@ -228,7 +259,8 @@ class OperationsList extends Component { const { account, canShowMore, - minConfirmations, + counterValue, + counterValues, onAccountClick, operations, t, @@ -240,43 +272,40 @@ class OperationsList extends Component { return ( - - - {t('operationsList:date')} - {withAccount && ( - {t('operationsList:account')} - )} - {t('operationsList:address')} - - {t('operationsList:amount')} - - - - - - {operations.map(tx => ( - - ))} - + + + + {operations.map(tx => { + const acc = account || tx.account + const unit = getDefaultUnitByCoinType(acc.coinType) + const cValues = get(counterValues, `${unit.code}-${counterValue}.byDate`, null) + return ( + + ) + })} + + {canShowMore && ( {t('operationsList:showMore')} )} - + ) } } -export default translate()(OperationsList) +export default compose(translate(), connect(mapStateToProps))(OperationsList) diff --git a/src/components/OperationsList/stories.js b/src/components/OperationsList/stories.js index 889b8eec..b8f4bb64 100644 --- a/src/components/OperationsList/stories.js +++ b/src/components/OperationsList/stories.js @@ -1,23 +1,56 @@ // @flow import React from 'react' -import { getDefaultUnitByCoinType } from '@ledgerhq/currencies' +import { getCurrencyByCoinType, getDefaultUnitByCoinType } from '@ledgerhq/currencies' import { storiesOf } from '@storybook/react' import { boolean } from '@storybook/addon-knobs' +import { translate } from 'react-i18next' -import OperationsList from 'components/OperationsList' +import { OperationsList } from 'components/OperationsList' const stories = storiesOf('Components', module) const unit = getDefaultUnitByCoinType(0) +const counterValue = 'USD' +const counterValues = { + 'BTC-USD': { + byDate: { + '2018-01-09': 10000, + }, + }, +} + const operations = [ { address: '5c6ea1716520c7d6e038d36a3223faced3c', hash: '5c6ea1716520c7d6e038d36a3223faced3c4b8f7ffb69d9fb5bd527d562fdb62', amount: 130000000, receivedAt: '2018-01-09T16:03:52Z', + confirmations: 1, + account: { + settings: { + minConfirmations: 10, + }, + currency: getCurrencyByCoinType(0), + name: 'Account 1', + coinType: 0, + unit, + }, + }, + { + address: '5c6ea1716520c7d6e038d36a3223faced3c', + hash: '5c6ea1716520c7d6e038d36a3223faced3c4b8f7ffb69d9fb5bd527d562fdb62', + amount: 130000000, + receivedAt: '2018-01-09T16:03:52Z', + confirmations: 11, account: { + settings: { + minConfirmations: 10, + }, + currency: getCurrencyByCoinType(0), + name: 'Account 1', + coinType: 0, unit, }, }, @@ -26,12 +59,43 @@ const operations = [ hash: '27416a48caab90fab053b507b8b6b9d48fba75421d3bfdbae4b85f64024bc9c4', amount: -65000000, receivedAt: '2018-01-09T16:02:40Z', + confirmations: 11, account: { + settings: { + minConfirmations: 10, + }, + currency: getCurrencyByCoinType(0), + name: 'Account 2', + coinType: 0, + unit, + }, + }, + { + address: '27416a48caab90fab053b507b8b6b9d4', + hash: '27416a48caab90fab053b507b8b6b9d48fba75421d3bfdbae4b85f64024bc9c4', + amount: -65000000, + receivedAt: '2018-01-09T16:02:40Z', + confirmations: 1, + account: { + settings: { + minConfirmations: 10, + }, + currency: getCurrencyByCoinType(0), + name: 'Account 2', + coinType: 0, unit, }, }, ] +const OperationsListComp = translate()(OperationsList) + stories.add('OperationsList', () => ( - + )) diff --git a/src/styles/reset.js b/src/styles/reset.js index 6426099e..ff15b442 100644 --- a/src/styles/reset.js +++ b/src/styles/reset.js @@ -9,6 +9,7 @@ module.exports = `* { min-width: 0; /* it will surely make problem in the future... to be inspected. */ + /* ;_; */ flex-shrink: 0; } diff --git a/src/styles/theme.js b/src/styles/theme.js index 9aeb4c88..8dc6e5c7 100644 --- a/src/styles/theme.js +++ b/src/styles/theme.js @@ -75,7 +75,7 @@ export const colors = { identity: '#41ccb4', lightGraphite: '#fafafa', lightGrey: '#f9f9f9', - positiveGreen: '#96d071', + positiveGreen: '#66be54', smoke: '#666666', wallet: '#4b84ff', white: '#ffffff', diff --git a/static/i18n/en/operationsList.yml b/static/i18n/en/operationsList.yml index 8147e850..c8edd0b6 100644 --- a/static/i18n/en/operationsList.yml +++ b/static/i18n/en/operationsList.yml @@ -2,8 +2,8 @@ date: Date account: Account address: Address amount: Amount -from: From -to: To +from: Receive funds +to: Sent funds showMore: Show more confirmed: Confirmed notConfirmed: Not confirmed diff --git a/yarn.lock b/yarn.lock index 38efd011..1085a6a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3560,9 +3560,9 @@ dotenv@^5.0.0, dotenv@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" -downshift@^1.31.1: - version "1.31.1" - resolved "https://registry.yarnpkg.com/downshift/-/downshift-1.31.1.tgz#86760be5d2ceb9f322746458fc085ea0b923805c" +downshift@^1.31.2: + version "1.31.2" + resolved "https://registry.yarnpkg.com/downshift/-/downshift-1.31.2.tgz#6f638e9720d7540d9dffa0b4c4587cf10811cf8c" duplexer2@~0.1.4: version "0.1.4"