From df75ea4432618c0b9f304dd79f94de2b2c4dbf37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Fri, 15 Jun 2018 08:53:27 +0200 Subject: [PATCH 01/25] Fix LibcoreBridge to not validate if amount=0 --- src/bridge/LibcoreBridge.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bridge/LibcoreBridge.js b/src/bridge/LibcoreBridge.js index 45321d7e..b3ee7ff9 100644 --- a/src/bridge/LibcoreBridge.js +++ b/src/bridge/LibcoreBridge.js @@ -48,7 +48,7 @@ const EditAdvancedOptions = ({ onChange, value }: EditProps) => ( const recipientValidLRU = LRU({ max: 100 }) -const isRecipientValid = (currency, recipient): Promise => { +const isRecipientValid = (currency, recipient) => { const key = `${currency.id}_${recipient}` let promise = recipientValidLRU.get(key) if (promise) return promise @@ -172,14 +172,18 @@ const LibcoreBridge: WalletBridge = { isValidTransaction: (a, t) => (t.amount > 0 && t.recipient && true) || false, canBeSpent: (a, t) => - getFees(a, t) - .then(fees => fees !== null) - .catch(() => false), + !t.amount + ? Promise.resolve(true) + : getFees(a, t) + .then(fees => fees !== null) + .catch(() => false), getTotalSpent: (a, t) => - getFees(a, t) - .then(totalFees => t.amount + (totalFees || 0)) - .catch(() => 0), + !t.amount + ? Promise.resolve(0) + : getFees(a, t) + .then(totalFees => t.amount + (totalFees || 0)) + .catch(() => 0), getMaxAmount: (a, t) => getFees(a, t) From ff0cb8d9b3c352da7d5c0011da0c4abb4e6ba579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Fri, 15 Jun 2018 09:00:50 +0200 Subject: [PATCH 02/25] Prevent negative values and Infinity to be inputable --- src/components/base/InputCurrency/index.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/base/InputCurrency/index.js b/src/components/base/InputCurrency/index.js index 205d9067..97623746 100644 --- a/src/components/base/InputCurrency/index.js +++ b/src/components/base/InputCurrency/index.js @@ -14,10 +14,6 @@ import Select from 'components/base/LegacySelect' import type { Unit } from '@ledgerhq/live-common/lib/types' -function parseValue(value) { - return value.toString().replace(/,/g, '.') -} - function format(unit: Unit, value: number, { isFocused, showAllDigits, subMagnitude }) { // FIXME do we need locale for the input too ? return formatCurrencyUnit(unit, value, { @@ -104,7 +100,9 @@ class InputCurrency extends PureComponent { } handleChange = (v: string) => { - v = parseValue(v) + // FIXME this is to refactor. this is hacky and don't cover everything.. + + v = v.toString().replace(/,/g, '.') // allow to type directly `.` in input to have `0.` if (v.startsWith('.')) { @@ -120,7 +118,8 @@ class InputCurrency extends PureComponent { } // Check if value is valid Number - if (isNaN(Number(v))) { + const asNumber = parseFloat(v) + if (isNaN(asNumber) || !isFinite(asNumber) || asNumber < 0) { return } From 2d77bf0da98a115e81b9480206667a312300796c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Fri, 15 Jun 2018 10:09:39 +0200 Subject: [PATCH 03/25] Improve InputCurrency - you have more control on what you type, no more weird "empty input" cases - it prevents to type more digits than the currency allows of magnitude - it do everything to prevent you from typing weird things --- src/components/base/InputCurrency/index.js | 85 ++++++++++++---------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/src/components/base/InputCurrency/index.js b/src/components/base/InputCurrency/index.js index 97623746..da1963b0 100644 --- a/src/components/base/InputCurrency/index.js +++ b/src/components/base/InputCurrency/index.js @@ -6,7 +6,6 @@ import styled from 'styled-components' import { formatCurrencyUnit } from '@ledgerhq/live-common/lib/helpers/currencies' import noop from 'lodash/noop' -import isNaN from 'lodash/isNaN' import Box from 'components/base/Box' import Input from 'components/base/Input' @@ -14,6 +13,43 @@ import Select from 'components/base/LegacySelect' import type { Unit } from '@ledgerhq/live-common/lib/types' +// TODO move this back to live common +const numbers = '0123456789' +const sanitizeValueString = ( + unit: Unit, + valueString: string, +): { + display: string, + value: string, +} => { + let display = '' + let value = '' + let decimals = -1 + for (let i = 0; i < valueString.length; i++) { + const c = valueString[i] + if (numbers.indexOf(c) !== -1) { + if (decimals >= 0) { + decimals++ + if (decimals > unit.magnitude) break + value += c + display += c + } else if (value !== '0') { + value += c + display += c + } + } else if (decimals === -1 && (c === ',' || c === '.')) { + if (i === 0) display = '0' + decimals = 0 + display += '.' + } + } + for (let i = decimals; i < unit.magnitude; ++i) { + value += '0' + } + if (!value) value = '0' + return { display, value } +} + function format(unit: Unit, value: number, { isFocused, showAllDigits, subMagnitude }) { // FIXME do we need locale for the input too ? return formatCurrencyUnit(unit, value, { @@ -81,9 +117,10 @@ class InputCurrency extends PureComponent { componentWillReceiveProps(nextProps: Props) { const { value, showAllDigits, unit } = this.props const needsToBeReformatted = - value !== nextProps.value || - showAllDigits !== nextProps.showAllDigits || - unit !== nextProps.unit + !this.state.isFocused && + (value !== nextProps.value || + showAllDigits !== nextProps.showAllDigits || + unit !== nextProps.unit) if (needsToBeReformatted) { const { isFocused } = this.state this.setState({ @@ -100,31 +137,13 @@ class InputCurrency extends PureComponent { } handleChange = (v: string) => { - // FIXME this is to refactor. this is hacky and don't cover everything.. - - v = v.toString().replace(/,/g, '.') - - // allow to type directly `.` in input to have `0.` - if (v.startsWith('.')) { - v = `0${v}` - } - - // forbid multiple 0 at start - if (v === '' || v.startsWith('00')) { - const { onChange, unit } = this.props - onChange(0, unit) - this.setState({ displayValue: '' }) - return - } - - // Check if value is valid Number - const asNumber = parseFloat(v) - if (isNaN(asNumber) || !isFinite(asNumber) || asNumber < 0) { - return + const { onChange, unit, value } = this.props + const r = sanitizeValueString(unit, v) + const satoshiValue = parseInt(r.value, 10) + if (value !== satoshiValue) { + onChange(satoshiValue, unit) } - - this.emitOnChange(v) - this.setState({ displayValue: v || '' }) + this.setState({ displayValue: r.display }) } handleBlur = () => { @@ -148,16 +167,6 @@ class InputCurrency extends PureComponent { }) } - emitOnChange = (v: string) => { - const { onChange, unit } = this.props - const { displayValue } = this.state - - if (displayValue.toString() !== v.toString()) { - const satoshiValue = Number(v) * 10 ** unit.magnitude - onChange(satoshiValue, unit) - } - } - renderItem = item => item.code renderSelected = item => {item.code} From 494dbdcc57bda561bb4bcc4e506c98d8ad050832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Fri, 15 Jun 2018 11:09:09 +0200 Subject: [PATCH 04/25] fix false positive on not enough balance --- src/bridge/LibcoreBridge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bridge/LibcoreBridge.js b/src/bridge/LibcoreBridge.js index b3ee7ff9..67f71138 100644 --- a/src/bridge/LibcoreBridge.js +++ b/src/bridge/LibcoreBridge.js @@ -175,7 +175,7 @@ const LibcoreBridge: WalletBridge = { !t.amount ? Promise.resolve(true) : getFees(a, t) - .then(fees => fees !== null) + .then(() => true) .catch(() => false), getTotalSpent: (a, t) => From 3373ae69e5aabaeab146fd78972f00d647f3e4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Fri, 15 Jun 2018 11:13:23 +0200 Subject: [PATCH 05/25] Fix refuse on device to go on step 4 --- src/components/DeviceConfirm/index.js | 4 ++-- .../modals/Send/03-step-verification.js | 5 ++--- src/components/modals/Send/index.js | 16 ++++++++-------- src/helpers/createCustomErrorClass.js | 3 ++- static/i18n/en/errors.yml | 1 + 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/components/DeviceConfirm/index.js b/src/components/DeviceConfirm/index.js index a9c88790..6e9a4e8b 100644 --- a/src/components/DeviceConfirm/index.js +++ b/src/components/DeviceConfirm/index.js @@ -41,7 +41,7 @@ const WrapperIcon = styled(Box)` } ` -const Check = ({ error }: { error: * }) => ( +const Check = ({ error }: { error?: boolean }) => ( {error ? : } @@ -74,7 +74,7 @@ const PushButton = styled(Box)` ` type Props = { - error: *, + error?: boolean, } const SVG = ( diff --git a/src/components/modals/Send/03-step-verification.js b/src/components/modals/Send/03-step-verification.js index a6df0e6d..1148b617 100644 --- a/src/components/modals/Send/03-step-verification.js +++ b/src/components/modals/Send/03-step-verification.js @@ -27,14 +27,13 @@ const Info = styled(Box).attrs({ ` type Props = { - hasError: boolean, t: T, } -export default ({ t, hasError }: Props) => ( +export default ({ t }: Props) => ( {multiline(t('app:send.steps.verification.warning'))} {t('app:send.steps.verification.body')} - + ) diff --git a/src/components/modals/Send/index.js b/src/components/modals/Send/index.js index 62fdf864..57106659 100644 --- a/src/components/modals/Send/index.js +++ b/src/components/modals/Send/index.js @@ -15,6 +15,7 @@ import { getBridgeForCurrency } from 'bridge' import { accountsSelector } from 'reducers/accounts' import { updateAccountWithUpdater } from 'actions/accounts' +import createCustomErrorClass from 'helpers/createCustomErrorClass' import { MODAL_SEND } from 'config/constants' import Modal, { ModalBody, ModalContent, ModalTitle } from 'components/base/Modal' @@ -32,6 +33,8 @@ import StepAmount from './01-step-amount' import StepVerification from './03-step-verification' import StepConfirmation from './04-step-confirmation' +export const UserRefusedOnDevice = createCustomErrorClass('UserRefusedOnDevice') + type Props = { updateAccountWithUpdater: (string, (Account) => Account) => void, accounts: Account[], @@ -226,14 +229,11 @@ class SendModal extends Component> { }) } - onOperationError = (error: Error) => { - // $FlowFixMe - if (error.statusCode === 0x6985) { - // User denied on device - this.setState({ error }) - } else { - this.setState({ error, stepIndex: 3 }) - } + onOperationError = (error: *) => { + this.setState({ + error: error.statusCode === 0x6985 ? new UserRefusedOnDevice() : error, + stepIndex: 3, + }) } onChangeAccount = account => { diff --git a/src/helpers/createCustomErrorClass.js b/src/helpers/createCustomErrorClass.js index 78738ef5..698dc61e 100644 --- a/src/helpers/createCustomErrorClass.js +++ b/src/helpers/createCustomErrorClass.js @@ -1,6 +1,6 @@ // @flow -export default (name: string) => { +export default (name: string): Class => { const C = function CustomError(message?: string, fields?: Object) { this.name = name this.message = message || name @@ -9,5 +9,6 @@ export default (name: string) => { } // $FlowFixMe C.prototype = new Error() + // $FlowFixMe we can't easily type a subset of Error for now... return C } diff --git a/static/i18n/en/errors.yml b/static/i18n/en/errors.yml index 34d4f713..7b6596f8 100644 --- a/static/i18n/en/errors.yml +++ b/static/i18n/en/errors.yml @@ -11,3 +11,4 @@ LedgerAPINotAvailable: 'Ledger API is not available for currency {{currencyName} LedgerAPIError: 'A problem occurred with Ledger API. Please try again later. (HTTP {{status}})' NetworkDown: 'Your internet connection seems down. Please try again later.' NoAddressesFound: 'No accounts found' +UserRefusedOnDevice: Transaction have been aborted From e684879b6f03c7ae92d890eab0a7c99368044bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Fri, 15 Jun 2018 11:16:41 +0200 Subject: [PATCH 06/25] fix calculation --- src/components/base/InputCurrency/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/base/InputCurrency/index.js b/src/components/base/InputCurrency/index.js index da1963b0..c32377fc 100644 --- a/src/components/base/InputCurrency/index.js +++ b/src/components/base/InputCurrency/index.js @@ -43,7 +43,7 @@ const sanitizeValueString = ( display += '.' } } - for (let i = decimals; i < unit.magnitude; ++i) { + for (let i = Math.max(0, decimals); i < unit.magnitude; ++i) { value += '0' } if (!value) value = '0' From 36e40948a8999893f650b451f1cc283d833cf6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Fri, 15 Jun 2018 11:25:18 +0200 Subject: [PATCH 07/25] In the OUT case we need to add the fees --- src/helpers/libcore.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/helpers/libcore.js b/src/helpers/libcore.js index 0cc0232d..5607fda8 100644 --- a/src/helpers/libcore.js +++ b/src/helpers/libcore.js @@ -312,7 +312,7 @@ function buildOperationRaw({ const bitcoinLikeTransaction = bitcoinLikeOperation.getTransaction() const hash = bitcoinLikeTransaction.getHash() const operationType = op.getOperationType() - const value = op.getAmount().toLong() + let value = op.getAmount().toLong() const fee = op.getFees().toLong() const OperationTypeMap: { [_: $Keys]: OperationType } = { @@ -323,6 +323,10 @@ function buildOperationRaw({ // if transaction is a send, amount becomes negative const type = OperationTypeMap[operationType] + if (type === 'OUT') { + value += fee + } + return { id, hash, From a91f3c912e3d97a32bc121ceeb80ba39098d4f0f Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 15 Jun 2018 11:36:45 +0200 Subject: [PATCH 08/25] Prevent lock issues due to double internal processes --- src/main/bridge.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/bridge.js b/src/main/bridge.js index bd118629..2b71fcd1 100644 --- a/src/main/bridge.js +++ b/src/main/bridge.js @@ -27,12 +27,17 @@ sentry(() => sentryEnabled, userId) const killInternalProcess = () => { if (internalProcess) { logger.log('killing internal process...') + internalProcess.removeListener('exit', handleExit) internalProcess.kill('SIGINT') internalProcess = null } } const forkBundlePath = path.resolve(__dirname, `${__DEV__ ? '../../' : './'}dist/internals`) +const handleExit = code => { + logger.warn(`Internal process ended with code ${code}`) + internalProcess = null +} const bootInternalProcess = () => { logger.log('booting internal process...') @@ -45,10 +50,7 @@ const bootInternalProcess = () => { }, }) internalProcess.on('message', handleGlobalInternalMessage) - internalProcess.on('exit', code => { - logger.warn(`Internal process ended with code ${code}`) - internalProcess = null - }) + internalProcess.on('exit', handleExit) } process.on('exit', () => { From 469e21995ef81398fcc1c30729fc7f61f7d7a8cd Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 15 Jun 2018 11:37:00 +0200 Subject: [PATCH 09/25] ActivityIndicator fix --- src/components/TopBar/ActivityIndicator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/TopBar/ActivityIndicator.js b/src/components/TopBar/ActivityIndicator.js index 64c2373a..a606ce93 100644 --- a/src/components/TopBar/ActivityIndicator.js +++ b/src/components/TopBar/ActivityIndicator.js @@ -70,7 +70,7 @@ class ActivityIndicatorInner extends Component { render() { const { isPending, isError, t } = this.props const { hasClicked, isFirstSync } = this.state - const isDisabled = isFirstSync || hasClicked || isError + const isDisabled = isError || (isPending && (isFirstSync || hasClicked)) const isRotating = isPending && (hasClicked || isFirstSync) return ( From 972c73ecd37a8a5d924ffd951ae77c5dc88d90ff Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 15 Jun 2018 11:45:16 +0200 Subject: [PATCH 10/25] Change sync max concurrency --- src/config/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/constants.js b/src/config/constants.js index 4cbd1cf2..343b4ed5 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -9,7 +9,7 @@ const intFromEnv = (key: string, def: number) => { export const GET_CALLS_TIMEOUT = intFromEnv('GET_CALLS_TIMEOUT', 30 * 1000) export const GET_CALLS_RETRY = intFromEnv('GET_CALLS_RETRY', 2) -export const SYNC_MAX_CONCURRENT = intFromEnv('LEDGER_SYNC_MAX_CONCURRENT', 2) +export const SYNC_MAX_CONCURRENT = intFromEnv('LEDGER_SYNC_MAX_CONCURRENT', 6) export const SYNC_BOOT_DELAY = 2 * 1000 export const SYNC_ALL_INTERVAL = 60 * 1000 From 5be26bff9f1e452ee50bbf7f28d080e927b76124 Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Fri, 15 Jun 2018 10:22:29 +0200 Subject: [PATCH 11/25] add lost password hard reset the app on the lock screen --- src/components/IsUnlocked.js | 44 ++++++++++++++++++++++++++++++++++-- static/i18n/en/app.yml | 1 + 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/components/IsUnlocked.js b/src/components/IsUnlocked.js index 136b1066..f6dadf2e 100644 --- a/src/components/IsUnlocked.js +++ b/src/components/IsUnlocked.js @@ -4,6 +4,7 @@ import bcrypt from 'bcryptjs' import React, { Component } from 'react' import { connect } from 'react-redux' import { compose } from 'redux' +import { remote } from 'electron' import styled from 'styled-components' import { translate } from 'react-i18next' @@ -14,12 +15,15 @@ import IconLockScreen from 'icons/LockScreen' import get from 'lodash/get' import { setEncryptionKey } from 'helpers/db' +import hardReset from 'helpers/hardReset' import { fetchAccounts } from 'actions/accounts' import { isLocked, unlock } from 'reducers/application' import Box from 'components/base/Box' import InputPassword from 'components/base/InputPassword' +import Button from './base/Button/index' +import ConfirmModal from './base/Modal/ConfirmModal' type InputValue = { password: string, @@ -36,6 +40,8 @@ type Props = { type State = { inputValue: InputValue, incorrectPassword: boolean, + isHardResetting: boolean, + isHardResetModalOpened: boolean, } const mapStateToProps = state => ({ @@ -53,6 +59,8 @@ const defaultState = { password: '', }, incorrectPassword: false, + isHardResetting: false, + isHardResetModalOpened: false, } export const PageTitle = styled(Box).attrs({ @@ -96,6 +104,7 @@ class IsUnlocked extends Component { ...prev.inputValue, [key]: value, }, + incorrectPassword: false, })) handleSubmit = async (e: SyntheticEvent) => { @@ -117,8 +126,21 @@ class IsUnlocked extends Component { } } + handleOpenHardResetModal = () => this.setState({ isHardResetModalOpened: true }) + handleCloseHardResetModal = () => this.setState({ isHardResetModalOpened: false }) + + handleHardReset = async () => { + this.setState({ isHardResetting: true }) + try { + await hardReset() + remote.getCurrentWindow().webContents.reloadIgnoringCache() + } catch (err) { + this.setState({ isHardResetting: false }) + } + } + render() { - const { inputValue, incorrectPassword } = this.state + const { inputValue, incorrectPassword, isHardResetting, isHardResetModalOpened } = this.state const { isLocked, t } = this.props if (isLocked) { @@ -140,11 +162,29 @@ class IsUnlocked extends Component { type="password" onChange={this.handleChangeInput('password')} value={inputValue.password} - error={incorrectPassword && t('app:password.errorMessageIncorrectPassword')} + error={ + incorrectPassword && + inputValue.password.length && + t('app:password.errorMessageIncorrectPassword') + } /> + + ) } diff --git a/static/i18n/en/app.yml b/static/i18n/en/app.yml index 4ed1a761..e969be12 100644 --- a/static/i18n/en/app.yml +++ b/static/i18n/en/app.yml @@ -31,6 +31,7 @@ common: subTitle: Your application is locked description: Please enter your password to continue inputPlaceholder: Type your password + lostPassword: I lost my password sync: syncing: Syncing... upToDate: Up to date From 40116daf6080e6fa7dd71dc4327f5d3061ce422f Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Fri, 15 Jun 2018 10:26:02 +0200 Subject: [PATCH 12/25] defaulting analytics toggle to false --- src/components/Onboarding/steps/Analytics.js | 2 +- src/reducers/settings.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Onboarding/steps/Analytics.js b/src/components/Onboarding/steps/Analytics.js index 40969dc8..d92720bc 100644 --- a/src/components/Onboarding/steps/Analytics.js +++ b/src/components/Onboarding/steps/Analytics.js @@ -19,7 +19,7 @@ type State = { } const INITIAL_STATE = { - analyticsToggle: true, + analyticsToggle: false, sentryLogsToggle: true, } diff --git a/src/reducers/settings.js b/src/reducers/settings.js index 2c28e884..eb6b8ec3 100644 --- a/src/reducers/settings.js +++ b/src/reducers/settings.js @@ -72,7 +72,7 @@ const INITIAL_STATE: SettingsState = { region, developerMode: !!process.env.__DEV__, loaded: false, - shareAnalytics: true, + shareAnalytics: false, sentryLogs: true, lastUsedVersion: __APP_VERSION__, } From e013682fcdb20908da0d46bd5c39c092d6c34323 Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Fri, 15 Jun 2018 11:46:07 +0200 Subject: [PATCH 13/25] update reset hard modal and add ledger blue text to genuine check --- src/components/IsUnlocked.js | 21 ++++++++++++++++--- .../Onboarding/steps/GenuineCheck.js | 7 ++++++- src/components/base/Modal/ConfirmModal.js | 9 +++++++- src/icons/TriangleWarning.js | 16 ++++++++++++++ static/i18n/en/app.yml | 7 +++---- static/i18n/en/onboarding.yml | 3 ++- 6 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 src/icons/TriangleWarning.js diff --git a/src/components/IsUnlocked.js b/src/components/IsUnlocked.js index f6dadf2e..edfc44bb 100644 --- a/src/components/IsUnlocked.js +++ b/src/components/IsUnlocked.js @@ -11,7 +11,7 @@ import { translate } from 'react-i18next' import type { SettingsState as Settings } from 'reducers/settings' import type { T } from 'types/common' import IconLockScreen from 'icons/LockScreen' - +import IconTriangleWarning from 'icons/TriangleWarning' import get from 'lodash/get' import { setEncryptionKey } from 'helpers/db' @@ -138,7 +138,13 @@ class IsUnlocked extends Component { this.setState({ isHardResetting: false }) } } - + hardResetIconRender = () => { + return ( + + + + ) + } render() { const { inputValue, incorrectPassword, isHardResetting, isHardResetModalOpened } = this.state const { isLocked, t } = this.props @@ -182,8 +188,8 @@ class IsUnlocked extends Component { onReject={this.handleCloseHardResetModal} onConfirm={this.handleHardReset} title={t('app:settings.hardResetModal.title')} - subTitle={t('app:settings.hardResetModal.subTitle')} desc={t('app:settings.hardResetModal.desc')} + renderIcon={this.hardResetIconRender} /> ) @@ -204,3 +210,12 @@ export default compose( ), translate(), )(IsUnlocked) + +const IconWrapperCircle = styled(Box).attrs({})` + width: 50px; + height: 50px; + border-radius: 50%; + background: #ea2e4919; + text-align: -webkit-center; + justify-content: center; +` diff --git a/src/components/Onboarding/steps/GenuineCheck.js b/src/components/Onboarding/steps/GenuineCheck.js index bff77501..c4f97654 100644 --- a/src/components/Onboarding/steps/GenuineCheck.js +++ b/src/components/Onboarding/steps/GenuineCheck.js @@ -129,7 +129,12 @@ class GenuineCheck extends PureComponent { {t('onboarding:genuineCheck.title')} - {t('onboarding:genuineCheck.desc')} + {onboarding.isLedgerNano ? ( + {t('onboarding:genuineCheck.descNano')} + ) : ( + {t('onboarding:genuineCheck.descBlue')} + )} + diff --git a/src/components/base/Modal/ConfirmModal.js b/src/components/base/Modal/ConfirmModal.js index 750f9b3f..c4c29f7e 100644 --- a/src/components/base/Modal/ConfirmModal.js +++ b/src/components/base/Modal/ConfirmModal.js @@ -14,8 +14,9 @@ type Props = { isOpened: boolean, isDanger: boolean, title: string, - subTitle: string, + subTitle?: string, desc: string, + renderIcon?: Function, confirmText?: string, cancelText?: string, onReject: Function, @@ -37,6 +38,7 @@ class ConfirmModal extends PureComponent { onReject, onConfirm, isLoading, + renderIcon, t, ...props } = this.props @@ -57,6 +59,11 @@ class ConfirmModal extends PureComponent { {subTitle} )} + {renderIcon && ( + + {renderIcon()} + + )} {desc} diff --git a/src/icons/TriangleWarning.js b/src/icons/TriangleWarning.js new file mode 100644 index 00000000..569fff9d --- /dev/null +++ b/src/icons/TriangleWarning.js @@ -0,0 +1,16 @@ +// @flow + +import React from 'react' + +const path = ( + +) + +export default ({ height, width, ...p }: { height: number, width: number }) => ( + + {path} + +) diff --git a/static/i18n/en/app.yml b/static/i18n/en/app.yml index e969be12..4b00bb11 100644 --- a/static/i18n/en/app.yml +++ b/static/i18n/en/app.yml @@ -119,7 +119,7 @@ exchange: coinmama: 'Coinmama is a financial service that makes it fast, safe and fun to buy digital currency, anywhere in the world.' genuinecheck: modal: - title: Genuine check, bro + title: Genuine check addAccounts: title: Add accounts breadcrumb: @@ -307,9 +307,8 @@ settings: 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 + title: Reset Ledger Live + desc: Resetting will erase all Ledger Live data stored on your computer, including your profile, accounts, transaction history and application settings. The keys to access your crypto assets in the blockchain remain secure on your Ledger device. softResetModal: title: Clean application cache subTitle: Are you sure houston? diff --git a/static/i18n/en/onboarding.yml b/static/i18n/en/onboarding.yml index 2fa67577..d09f78e2 100644 --- a/static/i18n/en/onboarding.yml +++ b/static/i18n/en/onboarding.yml @@ -74,7 +74,8 @@ writeSeed: note4: Never use a device supplied with a recovery phrase and/or a PIN code. genuineCheck: title: Final security check - desc: Your Ledger Nano S should now display Your device is now ready. Before getting started, please confirm that + descNano: Your Ledger Nano S should now display Your device is now ready. Before getting started, please confirm that + descBlue: Your Ledger Blue should now display Your device is now ready. Before getting started, please confirm that steps: step1: title: Did you choose your PIN code by yourself? From ff620becdb6e9a299649d2a26e4262d1fdb7e4e1 Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Fri, 15 Jun 2018 11:55:04 +0200 Subject: [PATCH 14/25] account name input length increased to 30 --- src/components/modals/AccountSettingRenderBody.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/modals/AccountSettingRenderBody.js b/src/components/modals/AccountSettingRenderBody.js index 60968fd2..95bb68fa 100644 --- a/src/components/modals/AccountSettingRenderBody.js +++ b/src/components/modals/AccountSettingRenderBody.js @@ -151,6 +151,7 @@ class HelperComp extends PureComponent { } onFocus={e => this.handleFocus(e, 'accountName')} From 4e3a8a7204584d3b9807e9ad536f3af0309a36bb Mon Sep 17 00:00:00 2001 From: ledger-bot <37080477+ledger-bot@users.noreply.github.com> Date: Fri, 15 Jun 2018 11:55:52 +0200 Subject: [PATCH 15/25] New translations errors.yml (French) --- static/i18n/fr/errors.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/static/i18n/fr/errors.yml b/static/i18n/fr/errors.yml index 731ccdc7..3a00f039 100644 --- a/static/i18n/fr/errors.yml +++ b/static/i18n/fr/errors.yml @@ -16,3 +16,4 @@ LedgerAPINotAvailable: 'Ledger API is not available for currency {{currencyName} LedgerAPIError: 'A problem occurred with Ledger API. Please try again later. (HTTP {{status}})' NetworkDown: 'Your internet connection seems down. Please try again later.' NoAddressesFound: 'No accounts found' +UserRefusedOnDevice: Transaction have been aborted From ae326792a44254ec934a6b49e75a9134a81257fe Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Fri, 15 Jun 2018 11:58:09 +0200 Subject: [PATCH 16/25] lint fix --- src/components/IsUnlocked.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/IsUnlocked.js b/src/components/IsUnlocked.js index edfc44bb..e8ca9c8a 100644 --- a/src/components/IsUnlocked.js +++ b/src/components/IsUnlocked.js @@ -138,13 +138,11 @@ class IsUnlocked extends Component { this.setState({ isHardResetting: false }) } } - hardResetIconRender = () => { - return ( + hardResetIconRender = () => ( ) - } render() { const { inputValue, incorrectPassword, isHardResetting, isHardResetModalOpened } = this.state const { isLocked, t } = this.props From b6a1045716763a2df409b65f902aa9169e1e0c0d Mon Sep 17 00:00:00 2001 From: Anastasia Poupeney Date: Fri, 15 Jun 2018 12:06:50 +0200 Subject: [PATCH 17/25] adding design style to reset modal in settings as well --- src/components/IsUnlocked.js | 14 +++++-------- .../SettingsPage/sections/Profile.js | 20 ++++++++++++++++++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/components/IsUnlocked.js b/src/components/IsUnlocked.js index e8ca9c8a..c0cb10e3 100644 --- a/src/components/IsUnlocked.js +++ b/src/components/IsUnlocked.js @@ -139,10 +139,10 @@ class IsUnlocked extends Component { } } hardResetIconRender = () => ( - - - - ) + + + + ) render() { const { inputValue, incorrectPassword, isHardResetting, isHardResetModalOpened } = this.state const { isLocked, t } = this.props @@ -166,11 +166,7 @@ class IsUnlocked extends Component { type="password" onChange={this.handleChangeInput('password')} value={inputValue.password} - error={ - incorrectPassword && - inputValue.password.length && - t('app:password.errorMessageIncorrectPassword') - } + error={incorrectPassword && t('app:password.errorMessageIncorrectPassword')} />