diff --git a/.circleci/config.yml b/.circleci/config.yml index 76ffd7d2..c5149361 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,7 +20,7 @@ jobs: command: yarn flow-typed - run: name: Temporary remove broken flow definitions - command: rm flow-typed/npm/{react-i18next_v7.x.x.js,react-redux_v5.x.x.js,redux_v3.x.x.js} + command: rm flow-typed/npm/{react-i18next_v7.x.x.js,react-redux_v5.x.x.js,redux_v3.x.x.js,styled-components_v3.x.x.js} - run: name: Lint command: yarn lint diff --git a/package.json b/package.json index 6f711fb6..04da20dd 100644 --- a/package.json +++ b/package.json @@ -57,11 +57,11 @@ "bs58check": "^2.1.1", "color": "^3.0.0", "cross-env": "^5.1.4", - "d3": "^5.0.0", + "d3": "^5.1.0", "debug": "^3.1.0", "downshift": "^1.31.7", "electron-store": "^1.3.0", - "electron-updater": "^2.21.4", + "electron-updater": "^2.21.8", "fuse.js": "^3.2.0", "history": "^4.7.2", "i18next": "^11.2.2", @@ -74,8 +74,8 @@ "qs": "^6.5.1", "raven": "^2.5.0", "raven-js": "^3.24.1", - "react": "^16.3.1", - "react-dom": "^16.3.1", + "react": "^16.3.2", + "react-dom": "^16.3.2", "react-flip-ticker": "^0.3.0", "react-i18next": "^7.6.0", "react-mortal": "^3.2.0", @@ -92,7 +92,7 @@ "smooth-scrollbar": "^8.2.7", "source-map": "0.7.2", "source-map-support": "^0.5.4", - "styled-components": "^3.2.5", + "styled-components": "^3.2.6", "styled-system": "^2.2.1", "tippy.js": "^2.5.2", "ws": "^5.1.1", @@ -105,24 +105,24 @@ "@babel/preset-flow": "7.0.0-beta.42", "@babel/preset-react": "7.0.0-beta.42", "@babel/preset-stage-0": "7.0.0-beta.42", - "@storybook/addon-actions": "^3.4.1", - "@storybook/addon-knobs": "^3.4.1", - "@storybook/addon-links": "^3.4.1", - "@storybook/addon-options": "^3.4.1", - "@storybook/addons": "^3.4.1", - "@storybook/react": "^3.4.1", + "@storybook/addon-actions": "^3.4.2", + "@storybook/addon-knobs": "^3.4.2", + "@storybook/addon-links": "^3.4.2", + "@storybook/addon-options": "^3.4.2", + "@storybook/addons": "^3.4.2", + "@storybook/react": "^3.4.2", "babel-core": "7.0.0-bridge.0", "babel-eslint": "^8.2.3", "babel-jest": "^22.4.3", "babel-loader": "^8.0.0-beta.2", "babel-plugin-module-resolver": "^3.1.1", "babel-plugin-styled-components": "^1.5.0", - "chalk": "^2.3.1", + "chalk": "^2.4.0", "chance": "^1.0.13", "concurrently": "^3.5.1", "dotenv": "^5.0.1", "electron": "1.8.4", - "electron-builder": "^20.8.1", + "electron-builder": "^20.9.0", "electron-devtools-installer": "^2.2.3", "electron-rebuild": "^1.7.3", "electron-webpack": "^2.0.1", @@ -142,10 +142,10 @@ "js-yaml": "^3.10.0", "lint-staged": "^7.0.4", "node-loader": "^0.6.0", - "prettier": "^1.12.0", + "prettier": "^1.12.1", "react-hot-loader": "^4.0.1", - "react-test-renderer": "^16.3.1", - "webpack": "^4.5.0", + "react-test-renderer": "^16.3.2", + "webpack": "^4.6.0", "webpack-bundle-analyzer": "^2.11.1", "webpack-cli": "^2.0.14", "yaml-loader": "^0.5.0" diff --git a/src/components/CounterValue/__tests__/__snapshots__/CounterValue.test.js.snap b/src/components/CounterValue/__tests__/__snapshots__/CounterValue.test.js.snap index 668aee53..709cd6ae 100644 --- a/src/components/CounterValue/__tests__/__snapshots__/CounterValue.test.js.snap +++ b/src/components/CounterValue/__tests__/__snapshots__/CounterValue.test.js.snap @@ -2,7 +2,7 @@ exports[`components CounterValue basic 1`] = `
+ USD 10.00 @@ -11,7 +11,7 @@ exports[`components CounterValue basic 1`] = ` exports[`components CounterValue specifying ticker different from default 1`] = `
+ USD 5.00 @@ -20,7 +20,7 @@ exports[`components CounterValue specifying ticker different from default 1`] = exports[`components CounterValue using countervalue different from default 1`] = `
+ EUR 0.42 @@ -29,7 +29,7 @@ exports[`components CounterValue using countervalue different from default 1`] = exports[`components CounterValue with time travel whith date in countervalues 1`] = `
+ USD 20.00 @@ -38,7 +38,7 @@ exports[`components CounterValue with time travel whith date in countervalues 1` exports[`components CounterValue with time travel whith date not in countervalues 1`] = `
+ USD 0.00 @@ -47,7 +47,7 @@ exports[`components CounterValue with time travel whith date not in countervalue exports[`components CounterValue without countervalues populated 1`] = `
+ USD 0.00 diff --git a/src/components/CurrentAddress/index.js b/src/components/CurrentAddress/index.js index 977029d5..1b95a372 100644 --- a/src/components/CurrentAddress/index.js +++ b/src/components/CurrentAddress/index.js @@ -1,7 +1,7 @@ // @flow import React, { PureComponent } from 'react' -import { translate } from 'react-i18next' +import { Trans, translate } from 'react-i18next' import styled from 'styled-components' import noop from 'lodash/noop' @@ -25,20 +25,12 @@ import IconShield from 'icons/Shield' const Container = styled(Box).attrs({ borderRadius: 1, alignItems: 'center', - bg: p => (p.withQRCode ? 'lightGrey' : 'transparent'), - py: 5, + bg: p => + p.withQRCode ? (p.notValid ? rgba(p.theme.colors.alertRed, 0.02) : 'lightGrey') : 'transparent', + py: 4, px: 7, -})`` - -const WrapperAddress = styled(Box).attrs({ - alignItems: 'center', - borderRadius: 1, - py: p => (p.notValid ? 4 : 0), - px: 4, })` - background: ${p => (p.notValid ? rgba(p.theme.colors.alertRed, 0.05) : 'transparent')}; - border: ${p => (p.notValid ? `1px dashed ${rgba(p.theme.colors.alertRed, 0.26)}` : 'none')}; - width: 100%; + border: ${p => (p.notValid ? `1px dashed ${rgba(p.theme.colors.alertRed, 0.5)}` : 'none')}; ` const Address = styled(Box).attrs({ @@ -63,11 +55,17 @@ const Label = styled(Box).attrs({ fontSize: 4, flow: 1, horizontal: true, -})`` +})` + strong { + color: ${p => p.theme.colors.dark}; + font-weight: 600; + border-bottom: 1px dashed ${p => p.theme.colors.dark}; + } +` const Footer = styled(Box).attrs({ horizontal: true, - mt: 5, + mt: 4, })` text-transform: uppercase; width: 100%; @@ -77,9 +75,20 @@ const FooterButtonWrapper = styled(Box).attrs({ color: 'grey', alignItems: 'center', justifyContent: 'center', - grow: true, + borderRadius: 1, })` cursor: pointer; + height: 55px; + width: 55px; + + &:hover { + background-color: rgba(100, 144, 241, 0.1); + color: ${p => p.theme.colors.dark}; + + svg { + color: ${p => p.theme.colors.wallet}; + } + } ` const FooterButton = ({ @@ -91,15 +100,18 @@ const FooterButton = ({ label: string, onClick: Function, }) => ( - - {icon} - - {label} - - + + + {icon} + + {label} + + + ) type Props = { + accountName?: string, address: string, addressVerified?: boolean, amount?: string, @@ -130,6 +142,7 @@ class CurrentAddress extends PureComponent { render() { const { + accountName, address, addressVerified, amount, @@ -149,20 +162,27 @@ class CurrentAddress extends PureComponent { return ( - - {withQRCode && ( - - - - )} - -
- {address} -
-
+ {withQRCode && ( + + + + )} + +
+ {address} +
{withBadge && ( @@ -186,7 +206,7 @@ class CurrentAddress extends PureComponent { )} /> ( } diff --git a/src/components/CurrentAddress/stories.js b/src/components/CurrentAddress/stories.js index 188b4c00..bc665a32 100644 --- a/src/components/CurrentAddress/stories.js +++ b/src/components/CurrentAddress/stories.js @@ -2,7 +2,7 @@ import React from 'react' import { storiesOf } from '@storybook/react' -import { boolean } from '@storybook/addon-knobs' +import { boolean, text } from '@storybook/addon-knobs' import CurrentAddress from 'components/CurrentAddress' @@ -12,6 +12,7 @@ const stories = storiesOf('Components', module) stories.add('CurrentAddress', () => ( ({ + username: state.settings.username, accounts: getVisibleAccounts(state), counterValue: getCounterValueCode(state), }) @@ -48,6 +49,7 @@ type Props = { accounts: Account[], push: Function, counterValue: string, + username: string, } type State = { @@ -109,7 +111,7 @@ class DashboardPage extends PureComponent { _cacheBalance = null render() { - const { push, accounts, t, counterValue } = this.props + const { push, accounts, t, counterValue, username } = this.props const { accountsChunk, selectedTime, daysCount } = this.state const totalAccounts = accounts.length @@ -119,7 +121,7 @@ class DashboardPage extends PureComponent { - {t('dashboard:greetings', { name: 'Khalil' })} + {t('dashboard:greetings', { name: username })} {totalAccounts > 0 diff --git a/src/components/IsUnlocked.js b/src/components/IsUnlocked.js index e184aaea..113f55e7 100644 --- a/src/components/IsUnlocked.js +++ b/src/components/IsUnlocked.js @@ -1,10 +1,10 @@ // @flow +import bcrypt from 'bcryptjs' import React, { Component } from 'react' import { connect } from 'react-redux' import { compose } from 'redux' import { translate } from 'react-i18next' -import bcrypt from 'bcryptjs' import type { Account } from '@ledgerhq/wallet-common/lib/types' import type { Settings, T } from 'types/common' @@ -25,7 +25,7 @@ import { isLocked, unlock } from 'reducers/application' import { getCounterValueCode } from 'reducers/settings' import Box from 'components/base/Box' -import Input from 'components/base/Input' +import InputPassword from 'components/base/InputPassword' type InputValue = { password: string, @@ -141,7 +141,7 @@ class IsUnlocked extends Component {
- (this._input = n)} placeholder={t('common:password')} diff --git a/src/components/OperationsList/index.js b/src/components/OperationsList/index.js index e09c8f73..1684666a 100644 --- a/src/components/OperationsList/index.js +++ b/src/components/OperationsList/index.js @@ -16,6 +16,8 @@ import type { Account, Operation as OperationType } from '@ledgerhq/wallet-commo import noop from 'lodash/noop' import keyBy from 'lodash/keyBy' +import { rgba } from 'styles/helpers' + import type { T } from 'types/common' import { MODAL_OPERATION_DETAILS } from 'config/constants' @@ -71,7 +73,7 @@ const OperationRaw = styled(Box).attrs({ } &:hover { - background: ${p => p.theme.colors.lightFog}; + background: ${p => rgba(p.theme.colors.wallet, 0.04)}; } ` diff --git a/src/components/SelectAccount/index.js b/src/components/SelectAccount/index.js index c08ac6bc..823de202 100644 --- a/src/components/SelectAccount/index.js +++ b/src/components/SelectAccount/index.js @@ -3,9 +3,10 @@ import React from 'react' import { connect } from 'react-redux' import { translate } from 'react-i18next' -import noop from 'lodash/noop' import { getIconByCoinType } from '@ledgerhq/currencies/react' +import noop from 'lodash/noop' + import type { Account } from '@ledgerhq/wallet-common/lib/types' import type { T } from 'types/common' diff --git a/src/components/SelectCurrency/index.js b/src/components/SelectCurrency/index.js new file mode 100644 index 00000000..298a90e9 --- /dev/null +++ b/src/components/SelectCurrency/index.js @@ -0,0 +1,60 @@ +// @flow + +import React from 'react' +import { translate } from 'react-i18next' +import { getIconByCoinType } from '@ledgerhq/currencies/react' +import { listCurrencies } from '@ledgerhq/currencies' + +import noop from 'lodash/noop' + +import type { Currency } from '@ledgerhq/currencies' +import type { T } from 'types/common' + +import Select from 'components/base/Select' +import Box from 'components/base/Box' + +const renderItem = a => { + const { color, name, coinType } = a + const Icon = getIconByCoinType(coinType) + return ( + + {Icon && ( + + + + )} + + {name} + + + ) +} + +const currencies = listCurrencies() + +type Props = { + onChange: Function, + value?: Currency, + t: T, +} + +const SelectCurrency = ({ onChange, value, t, ...props }: Props) => ( + this.handleChangeInput('language')(item.key)} - renderSelected={item => item && item.name} - value={currentLanguage} - items={languages} - /> - - - - - -
- ) - } -} - -export default TabProfile diff --git a/src/components/SettingsPage/Money.js b/src/components/SettingsPage/Money.js deleted file mode 100644 index 9028d1c6..00000000 --- a/src/components/SettingsPage/Money.js +++ /dev/null @@ -1,88 +0,0 @@ -// @flow - -import React, { PureComponent } from 'react' -import { getFiatUnit } from '@ledgerhq/currencies' - -import type { SettingsMoney, T } from 'types/common' - -import Box, { Card } from 'components/base/Box' -import Button from 'components/base/Button' -import Label from 'components/base/Label' -import Select from 'components/base/Select' - -const counterValues = ['USD', 'EUR', 'JPY', 'GBP'].sort().map(c => { - const { name } = getFiatUnit(c) - return { - key: c, - name, - } -}) - -type InputValue = SettingsMoney - -type Props = { - t: T, - settings: SettingsMoney, - onSaveSettings: Function, -} - -type State = { - inputValue: InputValue, -} - -class TabProfile extends PureComponent { - state = { - inputValue: { - counterValue: this.props.settings.counterValue, - }, - } - - handleChangeInput = (key: $Keys) => (value: $Values) => - this.setState(prev => ({ - inputValue: { - ...prev.inputValue, - [key]: value, - }, - })) - - handleSubmit = (e: SyntheticEvent) => { - e.preventDefault() - - const { onSaveSettings } = this.props - const { inputValue } = this.state - - onSaveSettings({ - ...inputValue, - }) - } - - render() { - const { t } = this.props - const { inputValue } = this.state - - const currentCounterValues = counterValues.find(l => l.key === inputValue.counterValue) - - return ( -
- - - - - - )} - - - - -
- ) - } -} - -export default connect(null, mapDispatchToProps)(TabProfile) diff --git a/src/components/SettingsPage/SettingsSection.js b/src/components/SettingsPage/SettingsSection.js new file mode 100644 index 00000000..4efc4199 --- /dev/null +++ b/src/components/SettingsPage/SettingsSection.js @@ -0,0 +1,120 @@ +// @flow + +import React from 'react' +import styled from 'styled-components' + +import { rgba } from 'styles/helpers' + +import Box, { Card } from 'components/base/Box' + +export const SettingsSection = styled(Card).attrs({ p: 0 })`` + +const SettingsSectionHeaderContainer = styled(Box).attrs({ + p: 4, + horizontal: true, + align: 'center', +})` + border-bottom: 1px solid ${p => p.theme.colors.lightFog}; + line-height: normal; +` + +const RoundIconContainer = styled(Box).attrs({ + align: 'center', + justify: 'center', + bg: p => rgba(p.theme.colors.wallet, 0.2), + color: 'wallet', +})` + height: 30px; + width: 30px; + border-radius: 50%; +` + +export const SettingsSectionBody = styled(Box)` + > * + * { + &:after { + background: ${p => p.theme.colors.lightFog}; + content: ''; + display: block; + height: 1px; + left: ${p => p.theme.space[4]}px; + position: absolute; + right: ${p => p.theme.space[4]}px; + top: 0; + } + } +` + +export function SettingsSectionHeader({ + title, + desc, + icon, + renderRight, +}: { + title: string, + desc: string, + icon: any, + renderRight?: any, +}) { + return ( + + {icon} + + + {title} + + + {desc} + + + {renderRight && ( + + {renderRight} + + )} + + ) +} + +SettingsSectionHeader.defaultProps = { + renderRight: undefined, +} + +const SettingsSectionRowContainer = styled(Box).attrs({ + p: 4, + horizontal: true, + align: 'center', + relative: true, +})` + cursor: ${p => (p.onClick ? 'pointer' : '')}; +` + +export function SettingsSectionRow({ + title, + desc, + children, + onClick, +}: { + title: string, + desc: string, + children?: any, + onClick?: ?Function, +}) { + return ( + + + + {title} + + + {desc} + + + {children} + + ) +} + +SettingsSectionRow.defaultProps = { + children: null, + onClick: null, +} diff --git a/src/components/SettingsPage/index.js b/src/components/SettingsPage/index.js index 725549f2..5b480b8d 100644 --- a/src/components/SettingsPage/index.js +++ b/src/components/SettingsPage/index.js @@ -4,8 +4,9 @@ import React, { PureComponent } from 'react' import { compose } from 'redux' import { connect } from 'react-redux' import { translate } from 'react-i18next' -import moment from 'moment' +import { Switch, Route } from 'react-router' +import type { RouterHistory, Match, Location } from 'react-router' import type { Settings, T } from 'types/common' import type { SaveSettings } from 'actions/settings' import type { FetchCounterValues } from 'actions/counterValues' @@ -13,14 +14,13 @@ import type { FetchCounterValues } from 'actions/counterValues' import { saveSettings } from 'actions/settings' import { fetchCounterValues } from 'actions/counterValues' +import Pills from 'components/base/Pills' import Box from 'components/base/Box' -import Text from 'components/base/Text' -import Tabs from 'components/base/Tabs' -import TabDisplay from './Display' -import TabProfile from './Profile' -import TabTools from './Tools' -import TabMoney from './Money' +import SectionDisplay from './sections/Display' +import SectionCurrencies from './sections/Currencies' +import SectionProfile from './sections/Profile' +import SectionAbout from './sections/About' const mapStateToProps = state => ({ settings: state.settings, @@ -32,33 +32,80 @@ const mapDispatchToProps = { } type Props = { + fetchCounterValues: FetchCounterValues, + history: RouterHistory, i18n: Object, + location: Location, + match: Match, saveSettings: SaveSettings, settings: Settings, - fetchCounterValues: FetchCounterValues, t: T, } type State = { - tab: number, + tab: Object, } class SettingsPage extends PureComponent { - state = { - tab: 0, + constructor(props) { + super(props) + + this._items = [ + { + key: 'display', + label: props.t('settings:tabs.display'), + value: p => () => , + }, + { + key: 'currencies', + label: props.t('settings:tabs.currencies'), + value: p => () => , + }, + { + key: 'profile', + label: props.t('settings:tabs.profile'), + value: p => () => , + }, + { + key: 'about', + label: props.t('settings:tabs.about'), + value: p => () => , + }, + ] + + this.state = { + tab: this.getCurrentTab({ url: props.match.url, pathname: props.location.pathname }), + } } - handleChangeTab = (tab: number) => this.setState({ tab }) + componentWillReceiveProps(nextProps) { + if (nextProps.location !== this.props.location) { + this.setState({ + tab: this.getCurrentTab({ + url: nextProps.match.url, + pathname: nextProps.location.pathname, + }), + }) + } + } - handleSaveSettings = newSettings => { - const { fetchCounterValues, saveSettings, i18n, settings } = this.props + getCurrentTab = ({ url, pathname }) => + this._items.find(i => `${url}/${i.key}` === pathname) || this._items[0] - saveSettings(newSettings) + _items = [] - if (newSettings.language !== settings.language) { - i18n.changeLanguage(newSettings.language) - moment.locale(newSettings.language) + handleChangeTab = (item: any) => { + const { match, history, location } = this.props + const url = `${match.url}/${item.key}` + if (location.pathname !== url) { + history.push(`${match.url}/${item.key}`) } + } + + handleSaveSettings = newSettings => { + const { fetchCounterValues, saveSettings, settings } = this.props + + saveSettings(newSettings) if (newSettings.counterValue !== settings.counterValue) { fetchCounterValues() @@ -66,62 +113,29 @@ class SettingsPage extends PureComponent { } render() { - const { settings, t } = this.props + const { match, settings, t, i18n, saveSettings } = this.props const { tab } = this.state - const props = { t, settings, - onSaveSettings: this.handleSaveSettings, + saveSettings, + i18n, } + const defaultItem = this._items[0] + return ( - - {t('settings:title')} - , - }, - { - key: 'money', - title: t('settings:tabs.money'), - render: () => , - }, - { - key: 'material', - isDisabled: true, - title: t('settings:tabs.material'), - render: () =>
{'Matériel'}
, - }, - { - key: 'app', - isDisabled: true, - title: t('settings:tabs.app'), - render: () =>
{'App (beta)'}
, - }, - { - key: 'tools', - title: t('settings:tabs.tools'), - render: () => , - }, - { - key: 'blockchain', - isDisabled: true, - title: t('settings:tabs.blockchain'), - render: () =>
{'Blockchain'}
, - }, - { - key: 'profile', - title: t('settings:tabs.profile'), - render: () => , - }, - ]} - /> + + + {t('settings:title')} + + + + {this._items.map(i => ( + + ))} + + ) } diff --git a/src/components/SettingsPage/sections/About.js b/src/components/SettingsPage/sections/About.js new file mode 100644 index 00000000..e8fba224 --- /dev/null +++ b/src/components/SettingsPage/sections/About.js @@ -0,0 +1,62 @@ +// @flow + +import React, { PureComponent } from 'react' +import { shell } from 'electron' + +import type { T } from 'types/common' + +import IconHelp from 'icons/Help' +import IconChevronRight from 'icons/ChevronRight' + +import { + SettingsSection as Section, + SettingsSectionHeader as Header, + SettingsSectionBody as Body, + SettingsSectionRow as Row, +} from '../SettingsSection' + +type Props = { + t: T, +} + +class SectionAbout extends PureComponent { + handleOpenLink = (url: string) => () => shell.openExternal(url) + + render() { + const { t } = this.props + return ( +
+
} + title={t('settings:tabs.about')} + desc="Lorem ipsum dolor sit amet" + /> + + + + + + + + + + + +
+ ) + } +} + +export default SectionAbout diff --git a/src/components/SettingsPage/sections/Currencies.js b/src/components/SettingsPage/sections/Currencies.js new file mode 100644 index 00000000..92cf36a1 --- /dev/null +++ b/src/components/SettingsPage/sections/Currencies.js @@ -0,0 +1,72 @@ +// @flow + +import React, { PureComponent } from 'react' + +import { listCurrencies } from '@ledgerhq/currencies' + +import type { Currency } from '@ledgerhq/currencies' +import type { T } from 'types/common' + +import SelectCurrency from 'components/SelectCurrency' + +import IconCurrencies from 'icons/Currencies' + +import { + SettingsSection as Section, + SettingsSectionHeader as Header, + SettingsSectionBody as Body, + SettingsSectionRow as Row, +} from '../SettingsSection' + +type Props = { + t: T, +} + +type State = { + currency: Currency, +} + +class TabCurrencies extends PureComponent { + state = { + currency: listCurrencies()[0], + } + + handleChangeCurrency = (currency: Currency) => this.setState({ currency }) + + render() { + const { t } = this.props + const { currency } = this.state + return ( +
+
} + title={t('settings:tabs.currencies')} + desc="Lorem ipsum dolor sit amet" + renderRight={ + + } + /> + + + + + + +
+ ) + } +} + +export default TabCurrencies diff --git a/src/components/SettingsPage/sections/Display.js b/src/components/SettingsPage/sections/Display.js new file mode 100644 index 00000000..326ad6f8 --- /dev/null +++ b/src/components/SettingsPage/sections/Display.js @@ -0,0 +1,120 @@ +// @flow + +import React, { PureComponent } from 'react' +import moment from 'moment' +import { listFiats } from '@ledgerhq/currencies' + +import type { Settings, T } from 'types/common' + +import Select from 'components/base/Select' +import IconDisplay from 'icons/Display' + +import { + SettingsSection as Section, + SettingsSectionHeader as Header, + SettingsSectionBody as Body, + SettingsSectionRow as Row, +} from '../SettingsSection' + +const fiats = listFiats().map(fiat => ({ + key: fiat.code, + fiat, + name: `${fiat.name} - ${fiat.code}${fiat.symbol ? ` (${fiat.symbol})` : ''}`, +})) + +type Props = { + t: T, + settings: Settings, + saveSettings: Function, + i18n: Object, +} + +type State = { + cachedLanguageKey: string, + cachedCounterValue: ?Object, +} + +class TabProfile extends PureComponent { + state = { + cachedLanguageKey: this.props.settings.language, + cachedCounterValue: fiats.find(fiat => fiat.fiat.code === this.props.settings.counterValue), + } + + getDatas() { + const { t } = this.props + return { + languages: [{ key: 'en', name: t('language:en') }, { key: 'fr', name: t('language:fr') }], + } + } + + handleChangeCounterValue = (item: Object) => { + const { saveSettings } = this.props + this.setState({ cachedCounterValue: item.fiat }) + window.requestIdleCallback(() => { + saveSettings({ counterValue: item.fiat.code }) + }) + } + + handleChangeLanguage = (languageKey: string) => { + const { i18n, saveSettings } = this.props + this.setState({ cachedLanguageKey: languageKey }) + window.requestIdleCallback(() => { + i18n.changeLanguage(languageKey) + moment.locale(languageKey) + saveSettings({ language: languageKey }) + }) + } + + render() { + const { t } = this.props + const { cachedLanguageKey, cachedCounterValue } = this.state + const { languages } = this.getDatas() + const currentLanguage = languages.find(l => l.key === cachedLanguageKey) + + return ( +
+
} + title={t('settings:tabs.display')} + desc="Lorem ipsum dolor sit amet" + /> + + + this.handleChangeLanguage(item.key)} + renderSelected={item => item && item.name} + value={currentLanguage} + items={languages} + /> + + + {'-'} + + + {'-'} + + +
+ ) + } +} + +export default TabProfile diff --git a/src/components/SettingsPage/sections/Profile.js b/src/components/SettingsPage/sections/Profile.js new file mode 100644 index 00000000..62e2498b --- /dev/null +++ b/src/components/SettingsPage/sections/Profile.js @@ -0,0 +1,172 @@ +// @flow + +import React, { PureComponent } from 'react' +import { connect } from 'react-redux' +import { remote } from 'electron' +import bcrypt from 'bcryptjs' + +import type { Settings, T } from 'types/common' + +import debounce from 'lodash/debounce' + +import { unlock } from 'reducers/application' +import db, { setEncryptionKey } from 'helpers/db' + +import Input from 'components/base/Input' +import CheckBox from 'components/base/CheckBox' +import Box from 'components/base/Box' +import Button from 'components/base/Button' +import { ConfirmModal } from 'components/base/Modal' +import IconUser from 'icons/User' +import PasswordModal from '../PasswordModal' + +import { + SettingsSection as Section, + SettingsSectionHeader as Header, + SettingsSectionBody as Body, + SettingsSectionRow as Row, +} from '../SettingsSection' + +const mapDispatchToProps = { + unlock, +} + +type Props = { + t: T, + settings: Settings, + unlock: Function, + saveSettings: Function, +} + +type State = { + isHardResetModalOpened: boolean, + isPasswordModalOpened: boolean, + username: string, +} + +class TabProfile extends PureComponent { + state = { + username: this.props.settings.username, + isHardResetModalOpened: false, + isPasswordModalOpened: false, + } + + setPassword = password => { + const { saveSettings, unlock } = this.props + window.requestIdleCallback(() => { + setEncryptionKey('accounts', password) + const hash = password ? bcrypt.hashSync(password, 8) : undefined + saveSettings({ + password: { + isEnabled: hash !== undefined, + value: hash, + }, + }) + unlock() + }) + } + + debounceSaveUsername = debounce( + v => this.props.saveSettings({ username: v.trim() || 'Anonymous' }), + 250, + ) + + handleChangeUsername = username => { + this.setState({ username }) + this.debounceSaveUsername(username) + } + + handleOpenHardResetModal = () => this.setState({ isHardResetModalOpened: true }) + handleCloseHardResetModal = () => this.setState({ isHardResetModalOpened: false }) + handleOpenPasswordModal = () => this.setState({ isPasswordModalOpened: true }) + handleClosePasswordModal = () => this.setState({ isPasswordModalOpened: false }) + + handleHardReset = () => { + db.resetAll() + remote.app.relaunch() + remote.app.exit() + } + + handleChangePasswordCheck = isChecked => { + if (isChecked) { + this.handleOpenPasswordModal() + } else { + this.setPassword(undefined) + } + } + + handleChangePassword = (password: ?string) => { + if (password) { + this.setPassword(password) + this.handleClosePasswordModal() + } + } + + render() { + const { t, settings } = this.props + const { username, isHardResetModalOpened, isPasswordModalOpened } = this.state + const isPasswordEnabled = settings.password.isEnabled === true + return ( +
+
} + title={t('settings:tabs.profile')} + desc="Lorem ipsum dolor sit amet" + /> + + + + + + + {isPasswordEnabled && ( + + )} + + + + + + + + + + + + + + + + + +
+ ) + } +} + +export default connect(null, mapDispatchToProps)(TabProfile) diff --git a/src/components/SettingsPage/Tools.js b/src/components/SettingsPage/sections/Tools.js similarity index 100% rename from src/components/SettingsPage/Tools.js rename to src/components/SettingsPage/sections/Tools.js diff --git a/src/components/SideBar/Item.js b/src/components/SideBar/Item.js index 94fb387f..e7f1a637 100644 --- a/src/components/SideBar/Item.js +++ b/src/components/SideBar/Item.js @@ -3,7 +3,7 @@ import React from 'react' import styled from 'styled-components' import { compose } from 'redux' -import { withRouter } from 'react-router' +import { matchPath, withRouter } from 'react-router' import { push } from 'react-router-redux' import { connect } from 'react-redux' @@ -77,7 +77,13 @@ function Item({ openModal, }: Props) { const { pathname } = location - const isActive = pathname === linkTo + const isActive = linkTo + ? linkTo === '/' + ? linkTo === pathname + : matchPath(pathname, { + path: linkTo, + }) + : false return ( ({ + username: state.settings.username, hasAccounts: getAccounts(state).length > 0, hasPassword: hasPassword(state), }) @@ -84,10 +87,13 @@ const mapDispatchToProps = { } type Props = { - t: T, hasAccounts: boolean, hasPassword: boolean, + history: RouterHistory, + location: Location, lock: Function, + t: T, + username: string, } type State = { @@ -145,7 +151,7 @@ class TopBar extends PureComponent { handleLock = () => this.props.lock() render() { - const { hasPassword, hasAccounts, t } = this.props + const { location, hasPassword, history, hasAccounts, username, t } = this.props const { sync } = this.state return ( @@ -171,6 +177,13 @@ class TopBar extends PureComponent { key: 'profile', label: t('common:editProfile'), icon: , + onClick: () => { + const url = '/settings/profile' + + if (location.pathname !== url) { + history.push(url) + } + }, }, ...(hasPassword ? [ @@ -197,7 +210,7 @@ class TopBar extends PureComponent { justifyContent="center" offsetTop={-2} > - {'Khalil Benihoud'} + {username}
@@ -207,4 +220,6 @@ class TopBar extends PureComponent { } } -export default compose(connect(mapStateToProps, mapDispatchToProps), translate())(TopBar) +export default compose(withRouter, connect(mapStateToProps, mapDispatchToProps), translate())( + TopBar, +) diff --git a/src/components/base/Box/index.js b/src/components/base/Box/index.js index bfa54a6c..9900d28e 100644 --- a/src/components/base/Box/index.js +++ b/src/components/base/Box/index.js @@ -11,12 +11,18 @@ import { fontSize, justifyContent, space, + style, } from 'styled-system' import fontFamily from 'styles/styled/fontFamily' import Text from 'components/base/Text' +const textAlign = style({ + prop: 'textAlign', + cssProperty: 'textAlign', +}) + const Box = styled.div` ${alignItems}; ${borderRadius}; @@ -27,6 +33,7 @@ const Box = styled.div` ${fontSize}; ${justifyContent}; ${space}; + ${textAlign}; display: flex; flex-shrink: ${p => (p.noShrink === true ? '0' : p.shrink === true ? '1' : '')}; diff --git a/src/components/base/Button/index.js b/src/components/base/Button/index.js index 51f7116e..1f2255b0 100644 --- a/src/components/base/Button/index.js +++ b/src/components/base/Button/index.js @@ -9,36 +9,90 @@ import { darken, lighten } from 'styles/helpers' import fontFamily from 'styles/styled/fontFamily' +const buttonStyles = { + primary: { + default: p => ` + background: ${p.disabled ? p.theme.colors.lightFog : p.theme.colors.wallet}; + color: ${p.disabled ? p.theme.colors.grey : p.theme.colors.white}; + `, + hover: p => ` + background: ${darken(p.theme.colors.wallet, 0.05)}; + `, + active: p => ` + background: ${darken(p.theme.colors.wallet, 0.05)}; + `, + }, + danger: { + default: p => ` + background: ${p.disabled ? p.theme.colors.lightFog : p.theme.colors.alertRed}; + color: ${p.disabled ? p.theme.colors.grey : p.theme.colors.white}; + `, + hover: p => ` + background: ${lighten(p.theme.colors.alertRed, 0.2)}; + `, + active: p => ` + background: ${lighten(p.theme.colors.alertRed, 0.2)}; + `, + }, + outline: { + default: p => ` + background: transparent; + border: 1px solid ${p.theme.colors.wallet}; + color: ${p.theme.colors.wallet}; + `, + active: p => ` + color: ${darken(p.theme.colors.wallet, 0.1)}; + border-color: ${darken(p.theme.colors.wallet, 0.1)}; + `, + }, + icon: { + default: () => ` + font-size: ${fontSize[3]}px; + padding-left: ${space[1]}px; + padding-right: ${space[1]}px; + `, + }, +} + +function getStyles(props, state) { + let output = `` + for (const s in buttonStyles) { + if (buttonStyles.hasOwnProperty(s) && props[s] === true) { + const style = buttonStyles[s][state] + if (style) { + output += style(props) + } + } + } + return output +} + const Base = styled.button.attrs({ ff: 'Museo Sans|Regular', fontSize: p => p.fontSize || 3, - px: p => (p.primary ? (p.small ? 2 : 3) : 2), + px: 2, + color: 'grey', + bg: 'transparent', })` ${space}; ${color}; ${fontSize}; ${fontWeight}; ${fontFamily}; + border: none; border-radius: ${p => p.theme.radii[1]}px; - border: ${p => (p.outline ? `1px solid ${p.theme.colors.wallet}` : 'none')}; - color: ${p => (p.outline ? p.theme.colors.wallet : '')}; cursor: ${p => (p.disabled ? 'default' : 'pointer')}; height: ${p => (p.small ? 30 : 36)}px; + pointer-events: ${p => (p.disabled ? 'none' : '')}; outline: none; - &:hover { - background: ${p => (p.disabled ? '' : p.primary ? lighten(p.theme.colors.wallet, 0.05) : '')}; + ${p => getStyles(p, 'default')}; + &:hover, + &:focus { + ${p => getStyles(p, 'hover')}; } - &:active { - color: ${p => - p.primary - ? '' - : p.outline - ? darken(p.theme.colors.wallet, 0.1) - : darken(p.theme.colors.grey, 0.2)}; - border-color: ${p => (p.outline ? darken(p.theme.colors.wallet, 0.1) : '')}; - background: ${p => (p.primary ? darken(p.theme.colors.wallet, 0.1) : '')}; + ${p => getStyles(p, 'active')}; } ` @@ -46,54 +100,17 @@ type Props = { children?: any, icon?: string, primary?: boolean, + danger?: boolean, disabled?: boolean, onClick?: Function, small?: boolean, } -function getProps({ disabled, icon, primary }: Object) { - const props = (predicate, props, defaults = {}) => (predicate ? props : defaults) - - return { - color: 'grey', - ...props( - icon, - { - fontSize: 3, - px: 1, - }, - { - fontSize: 4, - px: 3, - }, - ), - ...props( - primary, - { - color: 'white', - bg: 'wallet', - }, - { - bg: 'transparent', - }, - ), - ...props(disabled, { - color: 'grey', - bg: 'lightFog', - }), - } -} - const Button = (props: Props) => { - const { onClick, children, primary, disabled } = props + const { onClick, children, disabled } = props return ( - + {children} ) @@ -106,6 +123,7 @@ Button.defaultProps = { onClick: noop, primary: false, small: false, + danger: false, } export default Button diff --git a/src/components/base/Button/stories.js b/src/components/base/Button/stories.js index 039b553a..78ee935b 100644 --- a/src/components/base/Button/stories.js +++ b/src/components/base/Button/stories.js @@ -47,6 +47,17 @@ stories.add('Button', () => ( + + danger + + + + + + + outline diff --git a/src/components/base/CheckBox/index.js b/src/components/base/CheckBox/index.js index 0898313e..effa2d15 100644 --- a/src/components/base/CheckBox/index.js +++ b/src/components/base/CheckBox/index.js @@ -7,30 +7,29 @@ import styled from 'styled-components' import { Tabbable } from 'components/base/Box' const Base = styled(Tabbable).attrs({ - bg: p => (p.isChecked ? 'wallet' : 'fog'), + bg: p => (p.isChecked ? 'wallet' : 'lightFog'), horizontal: true, align: 'center', })` backround: red; width: 50px; - height: 24px; - border-radius: 16px; + height: 26px; + border-radius: 13px; transition: 250ms linear background-color; cursor: pointer; &:focus { - box-shadow: rgba(0, 0, 0, 0.1) 0 2px 2px; outline: none; } ` const Ball = styled.div` - width: 22px; - height: 22px; + width: 20px; + height: 20px; border-radius: 50%; background: white; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2); transition: 250ms ease-in-out transform; - transform: translate3d(${p => (p.isChecked ? '28px' : '0')}, 0, 0); + transform: translate3d(${p => (p.isChecked ? '27px' : '3px')}, 0, 0); ` type Props = { diff --git a/src/components/base/FormattedVal/__tests__/__snapshots__/FormattedVal.test.js.snap b/src/components/base/FormattedVal/__tests__/__snapshots__/FormattedVal.test.js.snap index d785fdf0..6fc26571 100644 --- a/src/components/base/FormattedVal/__tests__/__snapshots__/FormattedVal.test.js.snap +++ b/src/components/base/FormattedVal/__tests__/__snapshots__/FormattedVal.test.js.snap @@ -2,7 +2,7 @@ exports[`components FormattedVal renders a fiat 1`] = `
20.00 @@ -11,7 +11,7 @@ exports[`components FormattedVal renders a fiat 1`] = ` exports[`components FormattedVal renders a formatted val 1`] = `
4 @@ -20,7 +20,7 @@ exports[`components FormattedVal renders a formatted val 1`] = ` exports[`components FormattedVal renders a percent 1`] = `
30 % @@ -29,7 +29,7 @@ exports[`components FormattedVal renders a percent 1`] = ` exports[`components FormattedVal shows code 1`] = `
BTC 4 @@ -38,7 +38,7 @@ exports[`components FormattedVal shows code 1`] = ` exports[`components FormattedVal shows sign 1`] = `
+ 4 @@ -47,7 +47,7 @@ exports[`components FormattedVal shows sign 1`] = ` exports[`components FormattedVal shows sign 2`] = `
- 4 diff --git a/src/components/base/Input/index.js b/src/components/base/Input/index.js index 0db390ce..b03206fd 100644 --- a/src/components/base/Input/index.js +++ b/src/components/base/Input/index.js @@ -16,17 +16,17 @@ const Container = styled(Box).attrs({ border-radius: ${p => p.theme.radii[1]}px; border: 1px solid ${p => (p.isFocus ? p.theme.colors.wallet : p.theme.colors.fog)}; box-shadow: ${p => (p.isFocus ? `rgba(0, 0, 0, 0.05) 0 2px 2px` : 'none')}; - height: 40px; + height: ${p => (p.small ? '34' : '40')}px; ` const Base = styled.input.attrs({ - ff: p => p.ff || 'Open Sans|SemiBold', + ff: p => (p.ff || p.small ? 'Open Sans' : 'Open Sans|SemiBold'), fontSize: 4, })` ${fontFamily}; ${fontSize}; border: 0; - color: ${p => p.theme.colors.dark}; + color: ${p => p.theme.colors.graphite}; height: 100%; outline: none; padding: 0; @@ -65,6 +65,7 @@ type Props = { renderLeft?: any, renderRight?: any, containerProps?: Object, + small?: boolean, } type State = { @@ -77,6 +78,7 @@ class Input extends PureComponent { onFocus: noop, renderLeft: null, renderRight: null, + small: false, } state = { @@ -93,34 +95,41 @@ class Input extends PureComponent { handleClick = () => this._input && this._input.focus() - handleFocus = () => { + handleFocus = (e: SyntheticInputEvent) => { const { onFocus } = this.props this.setState({ isFocus: true, }) - onFocus() + onFocus(e) } - handleBlur = () => { + handleBlur = (e: SyntheticInputEvent) => { const { onBlur } = this.props this.setState({ isFocus: false, }) - onBlur() + onBlur(e) } _input = null render() { const { isFocus } = this.state - const { renderLeft, renderRight, containerProps } = this.props + const { renderLeft, renderRight, containerProps, small } = this.props return ( - + {renderLeft} (this._input = n)} onFocus={this.handleFocus} onBlur={this.handleBlur} diff --git a/src/components/base/InputPassword/index.js b/src/components/base/InputPassword/index.js index 9072f69c..692afd43 100644 --- a/src/components/base/InputPassword/index.js +++ b/src/components/base/InputPassword/index.js @@ -1,6 +1,6 @@ // @flow -import React, { PureComponent } from 'react' +import React, { Fragment, PureComponent } from 'react' import styled from 'styled-components' import { translate } from 'react-i18next' import zxcvbn from 'zxcvbn' @@ -50,6 +50,7 @@ type Props = { onChange: Function, t: T, value: string, + withStrength: boolean, } class InputPassword extends PureComponent { @@ -84,7 +85,7 @@ class InputPassword extends PureComponent { } render() { - const { t, value, maxLength } = this.props + const { t, value, maxLength, withStrength } = this.props const { passwordStrength, inputType } = this.state const hasValue = value.trim() !== '' @@ -102,19 +103,23 @@ class InputPassword extends PureComponent { } /> - - {[0, 1, 2, 3, 4].map(v => ( - = v} - /> - ))} - - {hasValue && ( - - {t(`password:warning_${passwordStrength}`)} - + {withStrength && ( + + + {[0, 1, 2, 3, 4].map(v => ( + = v} + /> + ))} + + {hasValue && ( + + {t(`password:warning_${passwordStrength}`)} + + )} + )} ) diff --git a/src/components/base/Label.js b/src/components/base/Label.js index c24d2cea..eca826c4 100644 --- a/src/components/base/Label.js +++ b/src/components/base/Label.js @@ -8,6 +8,7 @@ export default styled.label.attrs({ ff: 'Museo Sans|Regular', color: 'grey', align: 'center', + display: 'block', })` ${alignItems}; ${color}; diff --git a/src/components/base/Modal/ConfirmModal.js b/src/components/base/Modal/ConfirmModal.js new file mode 100644 index 00000000..0dccc693 --- /dev/null +++ b/src/components/base/Modal/ConfirmModal.js @@ -0,0 +1,74 @@ +// @flow + +import React, { PureComponent } from 'react' +import { translate } from 'react-i18next' + +import type { T } from 'types/common' + +import Button from 'components/base/Button' +import Box from 'components/base/Box' + +import { Modal, ModalContent, ModalBody, ModalTitle, ModalFooter } from './index' + +type Props = { + isOpened: boolean, + isDanger: boolean, + title: string, + subTitle: string, + desc: string, + confirmText: string, + cancelText: string, + onReject: Function, + onConfirm: Function, + t: T, +} + +class ConfirmModal extends PureComponent { + render() { + const { + isOpened, + title, + subTitle, + desc, + confirmText, + cancelText, + isDanger, + onReject, + onConfirm, + t, + ...props + } = this.props + + const realConfirmText = confirmText || t('common:confirm') + const realCancelText = cancelText || t('common:cancel') + return ( + ( + + {title} + + {subTitle && ( + + {subTitle} + + )} + + {desc} + + + + + + + + )} + /> + ) + } +} + +export default translate()(ConfirmModal) diff --git a/src/components/base/Modal/index.js b/src/components/base/Modal/index.js index 48e9c22d..9e36938f 100644 --- a/src/components/base/Modal/index.js +++ b/src/components/base/Modal/index.js @@ -21,6 +21,7 @@ import GrowScroll from 'components/base/GrowScroll' import Defer from 'components/base/Defer' export { default as ModalBody } from './ModalBody' +export { default as ConfirmModal } from './ConfirmModal' const springConfig = { stiffness: 320, @@ -54,8 +55,6 @@ const mapDispatchToProps: Function = (dispatch, { name, onClose = noop }): * => const Container = styled(Box).attrs({ color: 'grey', - alignItems: 'center', - justifyContent: 'flex-start', sticky: true, style: p => ({ pointerEvents: p.isVisible ? 'auto' : 'none', @@ -78,8 +77,6 @@ const Backdrop = styled(Box).attrs({ const Wrapper = styled(Tabbable).attrs({ bg: 'transparent', flow: 4, - mt: 100, - mb: 100, style: p => ({ opacity: p.op, transform: `scale3d(${p.scale}, ${p.scale}, ${p.scale})`, @@ -174,12 +171,7 @@ export class Modal extends Component { {(m, isVisible, isAnimated) => ( - + { - const isOpened = boolean('isOpened', true) - return ( - ( - - {'modal title'} - {'this is the modal content'} - - {'modal footer'} - - - - )} - /> - ) -}) +stories.add('Modal', () => ( + ( + + {'modal title'} + {'this is the modal content'} + + {'modal footer'} + + + + )} + /> +)) + +stories.add('ConfirmModal', () => ( + +)) diff --git a/src/components/base/Select/index.js b/src/components/base/Select/index.js index ab74e11d..1baa0fcb 100644 --- a/src/components/base/Select/index.js +++ b/src/components/base/Select/index.js @@ -34,20 +34,21 @@ type Props = { searchable?: boolean, value?: Object | null, disabled: boolean, + small?: boolean, } const Container = styled(Box).attrs({ relative: true, color: 'graphite' })`` const TriggerBtn = styled(Box).attrs({ alignItems: 'center', - ff: 'Open Sans|SemiBold', + ff: p => (p.small ? 'Open Sans' : 'Open Sans|SemiBold'), flow: 2, - fontSize: 4, + fontSize: p => (p.small ? 3 : 4), horizontal: true, px: 3, })` ${space}; - height: 40px; + height: ${p => (p.small ? '34' : '40')}px; background: ${p => (p.disabled ? p.theme.colors.lightGrey : p.bg || p.theme.colors.white)}; border-bottom-left-radius: ${p => (p.flatLeft ? 0 : p.theme.radii[1])}px; border-bottom-right-radius: ${p => (p.flatRight ? 0 : p.theme.radii[1])}px; @@ -149,6 +150,7 @@ class Select extends PureComponent { static defaultProps = { bg: undefined, disabled: false, + small: false, fakeFocusRight: false, flatLeft: false, flatRight: false, @@ -251,6 +253,7 @@ class Select extends PureComponent { renderSelected, searchable, value, + small, ...props } = this.props @@ -276,7 +279,7 @@ class Select extends PureComponent { if (disabled) { return ( - + {renderSelectedItem({ selectedItem, renderSelected, placeholder })} @@ -294,10 +297,11 @@ class Select extends PureComponent { {searchable ? ( } + {...getInputProps({ placeholder })} /> ) : ( @@ -308,6 +312,7 @@ class Select extends PureComponent { flatLeft={flatLeft} flatRight={flatRight} tabIndex={0} + small={small} > {renderSelectedItem({ selectedItem, renderSelected, placeholder })} diff --git a/src/components/base/Tabs/index.js b/src/components/base/Tabs/index.js deleted file mode 100644 index f2db1445..00000000 --- a/src/components/base/Tabs/index.js +++ /dev/null @@ -1,68 +0,0 @@ -// @flow - -import React, { Fragment } from 'react' -import styled from 'styled-components' - -import type { Element } from 'react' - -import Box, { Tabbable } from 'components/base/Box' - -const WrapperTab = styled(Box).attrs({ - horizontal: true, -})` - border-bottom: 1px solid ${p => p.theme.colors.fog}; -` - -const Tab = styled(Tabbable).attrs({ - flex: 1, - pb: 2, - alignItems: 'center', - justifyContent: 'center', - fontSize: 3, -})` - border-bottom: 2px solid transparent; - border-bottom-color: ${p => (p.isActive ? p.theme.colors.wallet : '')}; - color: ${p => - p.isActive - ? p.theme.colors.wallet - : p.isDisabled - ? p.theme.colors.grey - : p.theme.colors.graphite}; - margin-bottom: -1px; - outline: none; - cursor: ${p => (p.isActive ? 'default' : p.isDisabled ? 'not-allowed' : 'pointer')}; - max-width: 200px; -` - -type Item = { - key: string | number, - isDisabled?: boolean, - title: string | Element, - render: () => Element, -} - -type Props = { - items: Array, - index: number, - onTabClick: number => void, -} - -const Tabs = ({ items, index, onTabClick }: Props) => ( - - - {items.map((item, i) => ( - onTabClick(i)} - > - {item.title} - - ))} - - {items[index] && items[index].render()} - -) - -export default Tabs diff --git a/src/components/base/Tabs/stories.js b/src/components/base/Tabs/stories.js deleted file mode 100644 index bb89efcc..00000000 --- a/src/components/base/Tabs/stories.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react' - -import { number } from '@storybook/addon-knobs' -import { action } from '@storybook/addon-actions' -import { storiesOf } from '@storybook/react' - -import Tabs from 'components/base/Tabs' - -const stories = storiesOf('Components/base', module) - -stories.add('Tabs', () => ( -
{'first tab content'}
, - }, - { - key: 'second', - title: 'second tab', - render: () =>
{'second tab content'}
, - }, - ]} - /> -)) diff --git a/src/components/layout/Default.js b/src/components/layout/Default.js index 59020cc7..454dbbf4 100644 --- a/src/components/layout/Default.js +++ b/src/components/layout/Default.js @@ -6,6 +6,7 @@ import { ipcRenderer } from 'electron' import styled from 'styled-components' import { Route, withRouter } from 'react-router' import { translate } from 'react-i18next' + import type { Location } from 'react-router' import * as modals from 'components/modals' diff --git a/src/components/layout/Print.js b/src/components/layout/Print.js index bc760816..6051d353 100644 --- a/src/components/layout/Print.js +++ b/src/components/layout/Print.js @@ -31,12 +31,13 @@ class Print extends PureComponent { if (!data) { return null } - const { address, amount } = data + const { address, amount, accountName } = data return ( (this._node = n)} - amount={amount} + accountName={accountName} address={address} + amount={amount} + innerRef={n => (this._node = n)} withQRCode /> ) diff --git a/src/components/modals/Receive/04-step-receive-funds.js b/src/components/modals/Receive/04-step-receive-funds.js index 9a51f66f..efe220f7 100644 --- a/src/components/modals/Receive/04-step-receive-funds.js +++ b/src/components/modals/Receive/04-step-receive-funds.js @@ -8,7 +8,6 @@ import type { T } from 'types/common' import Box from 'components/base/Box' import CurrentAddress from 'components/CurrentAddress' import Label from 'components/base/Label' -import SelectAccount from 'components/SelectAccount' import RequestAmount from 'components/RequestAmount' type Props = { @@ -22,10 +21,6 @@ type Props = { export default (props: Props) => ( - - - - ( /> ( + + + +) diff --git a/src/icons/Display.js b/src/icons/Display.js new file mode 100644 index 00000000..0251d1e4 --- /dev/null +++ b/src/icons/Display.js @@ -0,0 +1,12 @@ +// @flow + +import React from 'react' + +export default ({ size, ...p }: { size: number }) => ( + + + +) diff --git a/src/icons/Help.js b/src/icons/Help.js new file mode 100644 index 00000000..ca30247f --- /dev/null +++ b/src/icons/Help.js @@ -0,0 +1,12 @@ +// @flow + +import React from 'react' + +export default ({ size, ...p }: { size: number }) => ( + + + +) diff --git a/src/internals/usb/manager/helpers.js b/src/internals/usb/manager/helpers.js index 9c488c65..0b80262f 100644 --- a/src/internals/usb/manager/helpers.js +++ b/src/internals/usb/manager/helpers.js @@ -214,6 +214,7 @@ export async function getFirmwareInfo(transport: Transport<*>) { */ function log(namespace: string, str: string = '', color?: string) { namespace = namespace.padEnd(15) + // $FlowFixMe const coloredNamespace = color ? chalk[color](namespace) : namespace if (__DEV__) { console.log(`${chalk.bold(`> ${coloredNamespace}`)} ${str}`) // eslint-disable-line no-console diff --git a/src/reducers/accounts.js b/src/reducers/accounts.js index 2a6bcb38..49c9633a 100644 --- a/src/reducers/accounts.js +++ b/src/reducers/accounts.js @@ -94,10 +94,10 @@ export function canCreateAccount(state: State): boolean { // such a simple thing, let's put any, right? I don't care. export function serializeAccounts(accounts: any): Account[] { // ensure that accounts are always wrapped in data key - if (accounts.length && !accounts[0].data) { + if (accounts && accounts.length && !accounts[0].data) { accounts = accounts.map(account => ({ data: account })) } - return accounts.map(accountModel.decode) + return accounts ? accounts.map(accountModel.decode) : [] } export function deserializeAccounts(accounts: Account[]) { diff --git a/src/reducers/settings.js b/src/reducers/settings.js index 0ab84c52..67c90041 100644 --- a/src/reducers/settings.js +++ b/src/reducers/settings.js @@ -10,11 +10,13 @@ import type { Settings } from 'types/common' export type SettingsState = Object const defaultState: SettingsState = { + username: 'Anonymous', counterValue: 'USD', language: 'en', orderAccounts: 'balance|asc', password: { - state: false, + isEnabled: false, + value: '', }, } @@ -34,7 +36,7 @@ const handlers: Object = { } export const hasPassword = (state: Object) => - get(state.settings, 'password.state', defaultState.password.state) + get(state.settings, 'password.isEnabled', defaultState.password.isEnabled) export const getCounterValueCode = (state: Object) => get(state.settings, 'counterValue', defaultState.counterValue) diff --git a/src/types/common.js b/src/types/common.js index 11181284..13d68fb8 100644 --- a/src/types/common.js +++ b/src/types/common.js @@ -12,23 +12,16 @@ export type Devices = Array // -------------------- Settings -export type SettingsProfile = { +export type Settings = { + language: string, + username: string, + counterValue: string, password: { - state: boolean, + isEnabled: boolean, value: string, }, } -export type SettingsDisplay = { - language: string, -} - -export type SettingsMoney = { - counterValue: string, -} - -export type Settings = SettingsProfile & SettingsDisplay & SettingsMoney - export type T = (?string, ?Object) => string // -------------------- Manager diff --git a/static/i18n/en/common.yml b/static/i18n/en/common.yml index 9a052f48..2202fe86 100644 --- a/static/i18n/en/common.yml +++ b/static/i18n/en/common.yml @@ -1,8 +1,10 @@ ok: Okay +confirm: Confirm cancel: Cancel chooseWalletPlaceholder: Choose a wallet... currency: Currency selectAccount: Select an account +selectCurrency: Select an currency sortBy: Sort by search: Search save: Save diff --git a/static/i18n/en/currentAddress.yml b/static/i18n/en/currentAddress.yml index 01c83432..6cefd17e 100644 --- a/static/i18n/en/currentAddress.yml +++ b/static/i18n/en/currentAddress.yml @@ -1 +1,2 @@ label: Current address +labelFrom: Address from <1><0>{{accountName}} diff --git a/static/i18n/en/settings.yml b/static/i18n/en/settings.yml index 3957a724..d6bb007f 100644 --- a/static/i18n/en/settings.yml +++ b/static/i18n/en/settings.yml @@ -1,16 +1,55 @@ title: Settings tabs: display: Display - money: Money - material: Material - app: App (beta) - tools: Tools - blockchain: Blockchain + currencies: Currencies profile: Profile + about: About display: - language: Language - counterValue: Counter Value - orderAccounts: Order accounts + language: Interface language + languageDesc: Lorem ipsum dolor sit amet + counterValue: Countervalue + counterValueDesc: Lorem ipsum dolor sit amet + region: Region + regionDesc: Lorem ipsum dolor sit amet + stock: Stock market indicators + stockDesc: Lorem ipsum dolor sit amet +currencies: + confirmationsToSpend: Confirmations to spend + confirmationsToSpendDesc: Lorem ipsum dolor sit amet + confirmationsNb: Number of confirmations + confirmationsNbDesc: Lorem ipsum dolor sit amet + transactionsFees: Transactions fees + transactionsFeesDesc: Lorem ipsum dolor sit amet + explorer: Blockchain explorer + explorerDesc: Lorem ipsum dolor sit amet profile: - protectWithPassword: Protect local data with a password + username: Username + usernameDesc: Lorem ipsum dolor sit amet password: Password + passwordDesc: Lorem ipsum dolor sit amet + changePassword: Change password + passwordModalTitle: Password + passwordModalSubtitle: Set a password to lock your application + passwordModalDesc: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer non nibh diam. + passwordModalPasswordInput: Current password + passwordModalNewPasswordInput: New password + passwordModalRepeatPasswordInput: Repeat password + passwordModalSave: Save + sync: Sync accounts + syncDesc: Lorem ipsum dolor sit amet + export: Export logs + exportDesc: Lorem ipsum dolor sit amet + reset: Reset application + resetDesc: Lorem ipsum dolor sit amet + resetButton: Hard reset +about: + faq: FAQ + faqDesc: Lorem ipsum dolor sit amet + contactUs: Contact us + contactUsDesc: Lorem ipsum dolor sit amet + terms: Terms and Privacy policy + termsDesc: Lorem ipsum dolor sit amet +hardResetModal: + title: Hard reset + subTitle: Are you sure houston? + desc: Lorem ipsum dolor sit amet diff --git a/yarn.lock b/yarn.lock index 7448044d..f385bbb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1002,11 +1002,11 @@ version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" -"@storybook/addon-actions@3.4.1", "@storybook/addon-actions@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-3.4.1.tgz#6ec5dc337e4af301d2f0f8fbc0ad2dee812cfa29" +"@storybook/addon-actions@3.4.2", "@storybook/addon-actions@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-3.4.2.tgz#ab45c37f57027257530577a9c1af6896ffb40156" dependencies: - "@storybook/components" "3.4.1" + "@storybook/components" "3.4.2" babel-runtime "^6.26.0" deep-equal "^1.0.1" glamor "^2.20.40" @@ -1017,11 +1017,11 @@ react-inspector "^2.2.2" uuid "^3.2.1" -"@storybook/addon-knobs@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-3.4.1.tgz#9c23abf62944280d2d681f0a356fea67683a892f" +"@storybook/addon-knobs@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-3.4.2.tgz#31baf535cafa9740d96b2f93197d688fa30b97f2" dependencies: - "@storybook/components" "3.4.1" + "@storybook/components" "3.4.2" babel-runtime "^6.26.0" deep-equal "^1.0.1" global "^4.3.2" @@ -1034,58 +1034,58 @@ react-textarea-autosize "^5.2.1" util-deprecate "^1.0.2" -"@storybook/addon-links@3.4.1", "@storybook/addon-links@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-3.4.1.tgz#b5c5e942b8865b2489d8d1537699316d0b154b1b" +"@storybook/addon-links@3.4.2", "@storybook/addon-links@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-3.4.2.tgz#09531263bd332669807b2e94cc70bd15e173f421" dependencies: - "@storybook/components" "3.4.1" + "@storybook/components" "3.4.2" babel-runtime "^6.26.0" global "^4.3.2" prop-types "^15.6.1" -"@storybook/addon-options@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/addon-options/-/addon-options-3.4.1.tgz#309f46c298b110442824b066e73df6dee17fc8b9" +"@storybook/addon-options@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/addon-options/-/addon-options-3.4.2.tgz#5acc5f8e6c00f803bb0f69e86b9e4b4c942fa283" dependencies: babel-runtime "^6.26.0" -"@storybook/addons@3.4.1", "@storybook/addons@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-3.4.1.tgz#ff80dc65a87607681b811a8cc4ff92124643f5ac" +"@storybook/addons@3.4.2", "@storybook/addons@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-3.4.2.tgz#77f0d5cb3b9443da6765600d83cd5acda6115af6" -"@storybook/channel-postmessage@3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-3.4.1.tgz#17a84b8df1613196554f0450733a0b13d0954907" +"@storybook/channel-postmessage@3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-3.4.2.tgz#08476f2b5b04ae83714137f6916e142c92222513" dependencies: - "@storybook/channels" "3.4.1" + "@storybook/channels" "3.4.2" global "^4.3.2" json-stringify-safe "^5.0.1" -"@storybook/channels@3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-3.4.1.tgz#13536c0211f0b49d24b63c5e7cef87b11ae43f85" +"@storybook/channels@3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-3.4.2.tgz#da26b3116fae1f83ccdb44881537cd9a073aefe9" -"@storybook/client-logger@3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-3.4.1.tgz#5b24ea0fa105f0683a5e9797a41466e4267d2c7f" +"@storybook/client-logger@3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-3.4.2.tgz#33a7b5c924e2960f9c129a934fc905ed1b271017" -"@storybook/components@3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-3.4.1.tgz#74e3bcf9590cb314a4845d2f3264aada79856c1f" +"@storybook/components@3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/components/-/components-3.4.2.tgz#1124cf22a54e36aa07c291608c652746919cf375" dependencies: glamor "^2.20.40" glamorous "^4.12.1" prop-types "^15.6.1" -"@storybook/core@3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/core/-/core-3.4.1.tgz#5ddbe754faa95c48ba272cfa30ca2e3272481aeb" +"@storybook/core@3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/core/-/core-3.4.2.tgz#d74b9232ef404e3dfc7c19539473699e83a2800a" dependencies: - "@storybook/addons" "3.4.1" - "@storybook/channel-postmessage" "3.4.1" - "@storybook/client-logger" "3.4.1" - "@storybook/node-logger" "3.4.1" - "@storybook/ui" "3.4.1" + "@storybook/addons" "3.4.2" + "@storybook/channel-postmessage" "3.4.2" + "@storybook/client-logger" "3.4.2" + "@storybook/node-logger" "3.4.2" + "@storybook/ui" "3.4.2" autoprefixer "^7.2.6" babel-runtime "^6.26.0" chalk "^2.3.2" @@ -1117,9 +1117,9 @@ "@storybook/react-simple-di" "^1.2.1" babel-runtime "6.x.x" -"@storybook/node-logger@3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-3.4.1.tgz#d1bddbaa5bcf995b97d408e46c1c2125d04b6e58" +"@storybook/node-logger@3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-3.4.2.tgz#1b5d909a1ab611b89da68216a81c4b22bf668c36" dependencies: npmlog "^4.1.2" @@ -1155,18 +1155,18 @@ dependencies: babel-runtime "^6.5.0" -"@storybook/react@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/react/-/react-3.4.1.tgz#db2b1c7980d9ed084aff4e28c5017e182b04bf3d" - dependencies: - "@storybook/addon-actions" "3.4.1" - "@storybook/addon-links" "3.4.1" - "@storybook/addons" "3.4.1" - "@storybook/channel-postmessage" "3.4.1" - "@storybook/client-logger" "3.4.1" - "@storybook/core" "3.4.1" - "@storybook/node-logger" "3.4.1" - "@storybook/ui" "3.4.1" +"@storybook/react@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/react/-/react-3.4.2.tgz#d48952a01cc2fa6bb143a1042bfa178f7d634ec3" + dependencies: + "@storybook/addon-actions" "3.4.2" + "@storybook/addon-links" "3.4.2" + "@storybook/addons" "3.4.2" + "@storybook/channel-postmessage" "3.4.2" + "@storybook/client-logger" "3.4.2" + "@storybook/core" "3.4.2" + "@storybook/node-logger" "3.4.2" + "@storybook/ui" "3.4.2" airbnb-js-shims "^1.4.1" babel-loader "^7.1.4" babel-plugin-macros "^2.2.0" @@ -1199,11 +1199,11 @@ webpack "^3.11.0" webpack-hot-middleware "^2.21.2" -"@storybook/ui@3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-3.4.1.tgz#2f0109d806d7922e45b7f4dea67584d61536df46" +"@storybook/ui@3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-3.4.2.tgz#8e6bcb6ebdf88e7d7bb3d7dfaf4151620daca0ad" dependencies: - "@storybook/components" "3.4.1" + "@storybook/components" "3.4.2" "@storybook/mantra-core" "^1.7.2" "@storybook/podda" "^1.2.3" "@storybook/react-komposer" "^2.0.3" @@ -1427,6 +1427,10 @@ app-builder-bin-linux@1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/app-builder-bin-linux/-/app-builder-bin-linux-1.8.3.tgz#4bf638a7bd29365e5534d2ba554baf1350fb4a87" +app-builder-bin-linux@1.8.5: + version "1.8.5" + resolved "https://registry.yarnpkg.com/app-builder-bin-linux/-/app-builder-bin-linux-1.8.5.tgz#bf001d3ef347e1179680a1760fea83d0832fc344" + app-builder-bin-mac@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/app-builder-bin-mac/-/app-builder-bin-mac-1.7.2.tgz#c4ee0d950666c97c12a45ac74ec6396be3357644" @@ -1435,6 +1439,10 @@ app-builder-bin-mac@1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/app-builder-bin-mac/-/app-builder-bin-mac-1.8.3.tgz#8e2c63e9d822fce2eee8db2f9f817d7b68532df7" +app-builder-bin-mac@1.8.5: + version "1.8.5" + resolved "https://registry.yarnpkg.com/app-builder-bin-mac/-/app-builder-bin-mac-1.8.5.tgz#31282504d232081a9de94d377736bf904bbfbd53" + app-builder-bin-win@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/app-builder-bin-win/-/app-builder-bin-win-1.7.2.tgz#7acac890782f4118f09941b343ba06c56452a6f6" @@ -1443,6 +1451,10 @@ app-builder-bin-win@1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/app-builder-bin-win/-/app-builder-bin-win-1.8.3.tgz#3598ec1c523dd197e8bb5dfeab3e2fe70905ae79" +app-builder-bin-win@1.8.5: + version "1.8.5" + resolved "https://registry.yarnpkg.com/app-builder-bin-win/-/app-builder-bin-win-1.8.5.tgz#d7eefc1dff6052e137a3c5d68cd6e68ba862054b" + app-builder-bin@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-1.7.2.tgz#daf67060a6bad8f5f611a0d2876d9db897a83f06" @@ -1459,6 +1471,14 @@ app-builder-bin@1.8.3: app-builder-bin-mac "1.8.3" app-builder-bin-win "1.8.3" +app-builder-bin@1.8.5: + version "1.8.5" + resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-1.8.5.tgz#ac0c0fad3c348ff3bde367e49b25cf5edc414407" + optionalDependencies: + app-builder-bin-linux "1.8.5" + app-builder-bin-mac "1.8.5" + app-builder-bin-win "1.8.5" + app-root-path@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46" @@ -3178,6 +3198,25 @@ builder-util@5.7.4, builder-util@^5.6.7, builder-util@^5.7.0, builder-util@^5.7. stat-mode "^0.2.2" temp-file "^3.1.1" +builder-util@5.7.6, builder-util@^5.7.6: + version "5.7.6" + resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-5.7.6.tgz#2480c8a233ab7ab05a4f1689892cc39819e768bb" + dependencies: + "7zip-bin" "~3.1.0" + app-builder-bin "1.8.5" + bluebird-lst "^1.0.5" + builder-util-runtime "^4.2.0" + chalk "^2.3.2" + debug "^3.1.0" + fs-extra-p "^4.5.2" + is-ci "^1.1.0" + js-yaml "^3.11.0" + lazy-val "^1.0.3" + semver "^5.5.0" + source-map-support "^0.5.4" + stat-mode "^0.2.2" + temp-file "^3.1.1" + builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -3362,6 +3401,14 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.3 escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" @@ -4321,9 +4368,9 @@ d3-zoom@1: d3-selection "1" d3-transition "1" -d3@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/d3/-/d3-5.0.0.tgz#b373ce8ccc953cbe09cef4c1e7e2223b42441df9" +d3@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/d3/-/d3-5.1.0.tgz#2506c4f070fe8a5a1e9a16308caacf96ae51f522" dependencies: d3-array "1" d3-axis "1" @@ -4579,6 +4626,19 @@ dmg-builder@4.1.3: parse-color "^1.0.0" sanitize-filename "^1.6.1" +dmg-builder@4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-4.1.5.tgz#f8dc24cd911e0e4a8cdcf9c8a2c829317403985a" + dependencies: + bluebird-lst "^1.0.5" + builder-util "^5.7.6" + electron-builder-lib "~20.9.0" + fs-extra-p "^4.5.2" + iconv-lite "^0.4.21" + js-yaml "^3.11.0" + parse-color "^1.0.0" + sanitize-filename "^1.6.1" + dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" @@ -4785,6 +4845,35 @@ electron-builder-lib@20.8.1: semver "^5.5.0" temp-file "^3.1.1" +electron-builder-lib@20.9.0, electron-builder-lib@~20.9.0: + version "20.9.0" + resolved "https://registry.yarnpkg.com/electron-builder-lib/-/electron-builder-lib-20.9.0.tgz#bb4725a796e80d15c5512e50a1ed0be08fea0e4f" + dependencies: + "7zip-bin" "~3.1.0" + app-builder-bin "1.8.5" + async-exit-hook "^2.0.1" + bluebird-lst "^1.0.5" + builder-util "5.7.6" + builder-util-runtime "4.2.0" + chromium-pickle-js "^0.2.0" + debug "^3.1.0" + ejs "^2.5.8" + electron-osx-sign "0.4.10" + electron-publish "20.9.0" + fs-extra-p "^4.5.2" + hosted-git-info "^2.6.0" + is-ci "^1.1.0" + isbinaryfile "^3.0.2" + js-yaml "^3.11.0" + lazy-val "^1.0.3" + minimatch "^3.0.4" + normalize-package-data "^2.4.0" + plist "^3.0.1" + read-config-file "3.0.0" + sanitize-filename "^1.6.1" + semver "^5.5.0" + temp-file "^3.1.1" + electron-builder-lib@~20.6.2: version "20.6.2" resolved "https://registry.yarnpkg.com/electron-builder-lib/-/electron-builder-lib-20.6.2.tgz#34f38b6172c05f90d34b6b5ed2f2b6922e731a39" @@ -4814,7 +4903,7 @@ electron-builder-lib@~20.6.2: semver "^5.5.0" temp-file "^3.1.1" -electron-builder@^20.0.4, electron-builder@^20.8.1: +electron-builder@^20.0.4: version "20.8.1" resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-20.8.1.tgz#3d19607a7f7d3ee7f3e110a6fc66c720ed1d2cc0" dependencies: @@ -4833,6 +4922,25 @@ electron-builder@^20.0.4, electron-builder@^20.8.1: update-notifier "^2.4.0" yargs "^11.0.0" +electron-builder@^20.9.0: + version "20.9.0" + resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-20.9.0.tgz#3010d5fbd927c0e1d5c4db6984d797f4b87cd239" + dependencies: + bluebird-lst "^1.0.5" + builder-util "5.7.6" + builder-util-runtime "4.2.0" + chalk "^2.3.2" + dmg-builder "4.1.5" + electron-builder-lib "20.9.0" + electron-download-tf "4.3.4" + fs-extra-p "^4.5.2" + is-ci "^1.1.0" + lazy-val "^1.0.3" + read-config-file "3.0.0" + sanitize-filename "^1.6.1" + update-notifier "^2.5.0" + yargs "^11.0.0" + electron-devtools-installer@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-2.2.3.tgz#58b9a4ec507377bc46e091cd43714188e0c369be" @@ -4909,6 +5017,18 @@ electron-publish@20.8.1: lazy-val "^1.0.3" mime "^2.2.0" +electron-publish@20.9.0: + version "20.9.0" + resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-20.9.0.tgz#095c02fe39674079d90a29eb404dbc894188ca16" + dependencies: + bluebird-lst "^1.0.5" + builder-util "^5.7.6" + builder-util-runtime "^4.2.0" + chalk "^2.3.2" + fs-extra-p "^4.5.2" + lazy-val "^1.0.3" + mime "^2.3.1" + electron-rebuild@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/electron-rebuild/-/electron-rebuild-1.7.3.tgz#24ae06ad9dd61cb7e4d688961f49118c40a110eb" @@ -4938,9 +5058,9 @@ electron-to-chromium@^1.3.40: version "1.3.40" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.40.tgz#1fbd6d97befd72b8a6f921dc38d22413d2f6fddf" -electron-updater@^2.21.4: - version "2.21.4" - resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-2.21.4.tgz#56326defc8072e78e339cc656838ac78e708f50c" +electron-updater@^2.21.8: + version "2.21.8" + resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-2.21.8.tgz#3881fff1fc7c57a66be0665bd7ffe02b7ecb5566" dependencies: bluebird-lst "^1.0.5" builder-util-runtime "~4.2.0" @@ -6752,6 +6872,12 @@ iconv-lite@0.4, iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@^0.4.19, iconv version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" +iconv-lite@^0.4.21: + version "0.4.21" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.21.tgz#c47f8733d02171189ebc4a400f3218d348094798" + dependencies: + safer-buffer "^2.1.0" + icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -8013,9 +8139,6 @@ ledger-test-library@KhalilBellakrid/ledger-test-library-nodejs#7d37482: dependencies: axios "^0.17.1" bindings "^1.3.0" - electron "^1.8.2" - electron-builder "^20.0.4" - electron-rebuild "^1.7.3" nan "^2.6.2" prebuild-install "^2.2.2" @@ -8522,6 +8645,10 @@ mime@^2.0.3, mime@^2.1.0, mime@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/mime/-/mime-2.2.0.tgz#161e541965551d3b549fa1114391e3a3d55b923b" +mime@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -9795,9 +9922,9 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -prettier@^1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.0.tgz#d26fc5894b9230de97629b39cae225b503724ce8" +prettier@^1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" prettier@^1.5.3: version "1.11.1" @@ -10135,9 +10262,9 @@ react-docgen@^3.0.0-beta11: node-dir "^0.1.10" recast "^0.12.6" -react-dom@^16.3.1: - version "16.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.1.tgz#6a3c90a4fb62f915bdbcf6204422d93a7d4ca573" +react-dom@^16.3.2: + version "16.3.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.2.tgz#cb90f107e09536d683d84ed5d4888e9640e0e4df" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -10208,6 +10335,10 @@ react-is@^16.3.1: version "16.3.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.1.tgz#ee66e6d8283224a83b3030e110056798488359ba" +react-is@^16.3.2: + version "16.3.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22" + react-modal@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.3.2.tgz#b13da9490653a7c76bc0e9600323eb1079c620e7" @@ -10311,14 +10442,14 @@ react-style-proptype@^3.0.0: dependencies: prop-types "^15.5.4" -react-test-renderer@^16.3.1: - version "16.3.1" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.1.tgz#d9257936d8535bd40f57f3d5a84e7b0452fb17f2" +react-test-renderer@^16.3.2: + version "16.3.2" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.2.tgz#3d1ed74fda8db42521fdf03328e933312214749a" dependencies: fbjs "^0.8.16" object-assign "^4.1.1" prop-types "^15.6.0" - react-is "^16.3.1" + react-is "^16.3.2" react-textarea-autosize@^5.2.1: version "5.2.1" @@ -10356,9 +10487,9 @@ react@^16.0.0, react@^16.2.0: object-assign "^4.1.1" prop-types "^15.6.0" -react@^16.3.1: - version "16.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.3.1.tgz#4a2da433d471251c69b6033ada30e2ed1202cfd8" +react@^16.3.2: + version "16.3.2" + resolved "https://registry.yarnpkg.com/react/-/react-16.3.2.tgz#fdc8420398533a1e58872f59091b272ce2f91ea9" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -10985,6 +11116,10 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" +safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + sane@^2.0.0: version "2.4.1" resolved "https://registry.yarnpkg.com/sane/-/sane-2.4.1.tgz#29f991208cf28636720efdc584293e7fd66663a5" @@ -11015,7 +11150,7 @@ schema-utils@^0.3.0: dependencies: ajv "^5.0.0" -schema-utils@^0.4.0, schema-utils@^0.4.2, schema-utils@^0.4.3, schema-utils@^0.4.5: +schema-utils@^0.4.0, schema-utils@^0.4.3, schema-utils@^0.4.4, schema-utils@^0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" dependencies: @@ -11707,9 +11842,9 @@ style-loader@^0.20.3: loader-utils "^1.1.0" schema-utils "^0.4.5" -styled-components@^3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.2.5.tgz#b5d5d7d618ab240ff10602b5ca5886b8db3d0a0d" +styled-components@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.2.6.tgz#99e6e75a746bdedd295a17e03dd1493055a1cc3b" dependencies: buffer "^5.0.3" css-to-react-native "^2.0.3" @@ -11717,6 +11852,7 @@ styled-components@^3.2.5: hoist-non-react-statics "^2.5.0" is-plain-object "^2.0.1" prop-types "^15.5.4" + react-is "^16.3.1" stylis "^3.5.0" stylis-rule-sheet "^0.0.10" supports-color "^3.2.3" @@ -12304,6 +12440,21 @@ update-notifier@^2.4.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" +update-notifier@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" + dependencies: + boxen "^1.2.1" + chalk "^2.0.1" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-ci "^1.0.10" + is-installed-globally "^0.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + upper-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" @@ -12755,9 +12906,9 @@ webpack@^3.11.0: webpack-sources "^1.0.1" yargs "^8.0.2" -webpack@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.5.0.tgz#1e6f71e148ead02be265ff2879c9cd6bb30b8848" +webpack@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.6.0.tgz#363eafa733710eb0ed28c512b2b9b9f5fb01e69b" dependencies: acorn "^5.0.0" acorn-dynamic-import "^3.0.0" @@ -12773,7 +12924,7 @@ webpack@^4.5.0: mkdirp "~0.5.0" neo-async "^2.5.0" node-libs-browser "^2.0.0" - schema-utils "^0.4.2" + schema-utils "^0.4.4" tapable "^1.0.0" uglifyjs-webpack-plugin "^1.2.4" watchpack "^1.5.0"