diff --git a/src/components/base/AccountsList/AccountRow.js b/src/components/base/AccountsList/AccountRow.js index 580c8355..0b3fce50 100644 --- a/src/components/base/AccountsList/AccountRow.js +++ b/src/components/base/AccountsList/AccountRow.js @@ -11,100 +11,79 @@ import Radio from 'components/base/Radio' import CryptoCurrencyIcon from 'components/CryptoCurrencyIcon' import FormattedVal from 'components/base/FormattedVal' import Input from 'components/base/Input' -import IconEdit from 'icons/Edit' -import IconCheck from 'icons/Check' -import type { T } from 'types/common' +import { MAX_ACCOUNT_NAME_SIZE } from 'config/constants' type Props = { account: Account, isChecked: boolean, isDisabled?: boolean, - onClick: Account => void, - onAccountUpdate: Account => void, - t: T, + autoFocusInput?: boolean, + accountName: string, + onToggleAccount?: (Account, boolean) => void, + onEditName?: (Account, string) => void, } -type State = { - isEditing: boolean, - accountNameCopy: string, -} - -export default class AccountRow extends PureComponent { - state = { - isEditing: false, - accountNameCopy: '', - } - - componentDidUpdate(prevProps: Props, prevState: State) { - const startedEditing = !prevState.isEditing && this.state.isEditing - if (startedEditing) { - this._input && this._input.handleSelectEverything() - } +export default class AccountRow extends PureComponent { + handlePreventSubmit = (e: SyntheticEvent<*>) => { + e.preventDefault() + e.stopPropagation() } - handleEditClick = (e: SyntheticEvent) => { - this.handlePreventSubmit(e) - const { account } = this.props - this.setState({ isEditing: true, accountNameCopy: account.name }) + onToggleAccount = () => { + const { onToggleAccount, account, isChecked } = this.props + if (onToggleAccount) onToggleAccount(account, !isChecked) } - handleSubmitName = (e: SyntheticEvent) => { - this.handlePreventSubmit(e) - const { account, onAccountUpdate, isChecked, onClick } = this.props - const { accountNameCopy } = this.state - const updatedAccount = { ...account, name: accountNameCopy } - this.setState({ isEditing: false, accountNameCopy: '' }) - onAccountUpdate(updatedAccount) - if (!isChecked) { - onClick(updatedAccount) - } + handleChangeName = (name: string) => { + const { onEditName, account } = this.props + if (onEditName) onEditName(account, name) } - handlePreventSubmit = (e: SyntheticEvent) => { - // prevent account row to be submitted + onClickInput = (e: SyntheticEvent<*>) => { e.preventDefault() e.stopPropagation() } - handleChangeName = (accountNameCopy: string) => this.setState({ accountNameCopy }) - - handleReset = () => this.setState({ isEditing: false, accountNameCopy: '' }) + onFocus = (e: *) => { + e.target.select() + } + onBlur = (e: *) => { + const { onEditName, account } = this.props + const { value } = e.target + if (!value && onEditName) { + // don't leave an empty input on blur + onEditName(account, account.name) + } + } _input = null render() { - const { account, isChecked, onClick, isDisabled, t } = this.props - const { isEditing, accountNameCopy } = this.state - + const { account, isChecked, onEditName, accountName, isDisabled, autoFocusInput } = this.props return ( - onClick(account)} isDisabled={isDisabled}> + - {isEditing ? ( + {onEditName ? ( - - - } - ref={input => (this._input = input)} + onClick={this.onClickInput} + onEnter={this.handlePreventSubmit} + onFocus={this.onFocus} + onBlur={this.onBlur} + maxLength={MAX_ACCOUNT_NAME_SIZE} + editInPlace + autoFocus={autoFocusInput} /> ) : ( -
{account.name}
+
{accountName}
)}
- {!isEditing && ( - - - {t('app:addAccounts.editName')} - - )} { fontSize={4} color="grey" /> - + {!isDisabled ? ( + + ) : ( +
+ )} ) } @@ -140,30 +123,3 @@ const AccountRowContainer = styled(Tabbable).attrs({ background-color: ${p => darken(p.theme.colors.lightGrey, 0.03)}; } ` - -const Edit = styled(Box).attrs({ - color: 'wallet', - fontSize: 3, - horizontal: true, - align: 'center', - flow: 1, - py: 1, -})` - display: none; - ${AccountRowContainer}:hover & { - display: flex; - } - &:hover { - text-decoration: underline; - } -` - -const InputRight = styled(Box).attrs({ - bg: 'wallet', - color: 'white', - align: 'center', - justify: 'center', - shrink: 0, -})` - width: 40px; -` diff --git a/src/components/base/AccountsList/index.js b/src/components/base/AccountsList/index.js index bba0c95e..3dc55fdf 100644 --- a/src/components/base/AccountsList/index.js +++ b/src/components/base/AccountsList/index.js @@ -1,99 +1,127 @@ // @flow -import React from 'react' -import styled from 'styled-components' +import React, { Component } from 'react' import { translate } from 'react-i18next' import type { Account } from '@ledgerhq/live-common/lib/types' import Box from 'components/base/Box' import FakeLink from 'components/base/FakeLink' -import Spinner from 'components/base/Spinner' import type { T } from 'types/common' +import { SpoilerIcon } from '../Spoiler' import AccountRow from './AccountRow' -const AccountsList = ({ - accounts, - checkedIds, - onToggleAccount, - onUpdateAccount, - onSelectAll, - onUnselectAll, - isLoading, - title, - emptyText, - t, -}: { - accounts: Account[], - checkedIds: string[], - onToggleAccount: Account => void, - onUpdateAccount: Account => void, - onSelectAll: () => void, - onUnselectAll: () => void, - isLoading?: boolean, - title?: string, - emptyText?: string, - t: T, -}) => { - const withToggleAll = !!onSelectAll && !!onUnselectAll && accounts.length > 1 - const isAllSelected = accounts.every(acc => !!checkedIds.find(id => acc.id === id)) - return ( - - {(title || withToggleAll) && ( - - {title && ( - - {title} - - )} - {withToggleAll && ( - - {isAllSelected ? t('app:addAccounts.unselectAll') : t('app:addAccounts.selectAll')} - - )} - - )} - {accounts.length || isLoading ? ( - - {accounts.map(account => ( - id === account.id) !== undefined} - onClick={onToggleAccount} - onAccountUpdate={onUpdateAccount} - t={t} - /> - ))} - {isLoading && ( - - - - )} - - ) : emptyText && !isLoading ? ( - - {emptyText} - - ) : null} - - ) +class AccountsList extends Component< + { + accounts: Account[], + checkedIds?: string[], + editedNames: { [accountId: string]: string }, + setAccountName?: (Account, string) => void, + onToggleAccount?: Account => void, + onSelectAll?: (Account[]) => void, + onUnselectAll?: (Account[]) => void, + title?: string, + emptyText?: string, + autoFocusFirstInput?: boolean, + collapsible?: boolean, + t: T, + }, + { + collapsed: boolean, + }, +> { + state = { + collapsed: false, + } + toggleCollapse = () => { + this.setState(({ collapsed }) => ({ collapsed: !collapsed })) + } + onSelectAll = () => { + const { accounts, onSelectAll } = this.props + if (onSelectAll) onSelectAll(accounts) + } + onUnselectAll = () => { + const { accounts, onUnselectAll } = this.props + if (onUnselectAll) onUnselectAll(accounts) + } + render() { + const { + accounts, + checkedIds, + onToggleAccount, + editedNames, + setAccountName, + onSelectAll, + onUnselectAll, + title, + emptyText, + autoFocusFirstInput, + collapsible, + t, + } = this.props + const { collapsed } = this.state + const withToggleAll = !!onSelectAll && !!onUnselectAll && accounts.length > 1 + const isAllSelected = + !checkedIds || accounts.every(acc => !!checkedIds.find(id => acc.id === id)) + return ( + + {(title || withToggleAll) && ( + + {title && ( + + {collapsible ? : null} + {title} + + )} + {withToggleAll && ( + + {isAllSelected + ? t('app:addAccounts.unselectAll', { count: accounts.length }) + : t('app:addAccounts.selectAll', { count: accounts.length })} + + )} + + )} + {collapsed ? null : accounts.length ? ( + + {accounts.map((account, i) => ( + id === account.id) !== undefined} + onToggleAccount={onToggleAccount} + onEditName={setAccountName} + accountName={ + typeof editedNames[account.id] === 'string' + ? editedNames[account.id] + : account.name + } + /> + ))} + + ) : emptyText ? ( + + {emptyText} + + ) : null} + + ) + } } -const LoadingRow = styled(Box).attrs({ - horizontal: true, - borderRadius: 1, - px: 3, - align: 'center', - justify: 'center', -})` - height: 48px; - border: 1px dashed ${p => p.theme.colors.grey}; -` - export default translate()(AccountsList) diff --git a/src/components/base/Input/index.js b/src/components/base/Input/index.js index 4f4388fe..e4affb40 100644 --- a/src/components/base/Input/index.js +++ b/src/components/base/Input/index.js @@ -15,12 +15,18 @@ const Container = styled(Box).attrs({ })` background: ${p => p.theme.colors.white}; border-radius: ${p => p.theme.radii[1]}px; - border: 1px solid - ${p => - p.error ? p.theme.colors.pearl : p.isFocus ? p.theme.colors.wallet : p.theme.colors.fog}; + border-width: 1px; + border-style: solid; + border-color: ${p => + p.error ? p.theme.colors.pearl : 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: ${p => (p.small ? '34' : '40')}px; position: relative; + + &:not(:hover) { + background: ${p => (!p.isFocus && p.editInPlace ? 'transparent' : undefined)}; + border-color: ${p => (!p.isFocus && p.editInPlace ? 'transparent' : undefined)}; + } ` const ErrorDisplay = styled(Box)` @@ -44,6 +50,7 @@ const Base = styled.input.attrs({ outline: none; padding: 0; width: 100%; + background: none; &::placeholder { color: ${p => p.theme.colors.fog}; @@ -82,6 +89,7 @@ type Props = { containerProps?: Object, error?: string | boolean, small?: boolean, + editInPlace?: boolean, } type State = { @@ -152,7 +160,7 @@ class Input extends PureComponent { render() { const { isFocus } = this.state - const { renderLeft, renderRight, containerProps, small, error } = this.props + const { renderLeft, renderRight, containerProps, editInPlace, small, error } = this.props return ( { {...containerProps} small={small} error={error} + editInPlace={editInPlace} > {renderLeft} diff --git a/src/components/base/Spoiler/index.js b/src/components/base/Spoiler/index.js index 1810223f..59302755 100644 --- a/src/components/base/Spoiler/index.js +++ b/src/components/base/Spoiler/index.js @@ -1,6 +1,7 @@ // @flow import React, { PureComponent, Fragment } from 'react' +import uncontrollable from 'uncontrollable' import styled from 'styled-components' import Box from 'components/base/Box' @@ -10,6 +11,8 @@ import IconChevronRight from 'icons/ChevronRight' type Props = { children: any, title: string, + opened: boolean, + onOpen: boolean => void, } type State = { @@ -24,7 +27,6 @@ const Title = styled(Text).attrs({ })` text-transform: ${p => (!p.textTransform ? 'auto' : 'uppercase')}; letter-spacing: 1px; - cursor: pointer; outline: none; ` @@ -33,30 +35,47 @@ const IconContainer = styled(Box)` transition: 150ms linear transform; ` -class Spoiler extends PureComponent { - state = { - isOpened: false, +export class SpoilerIcon extends PureComponent<{ isOpened: boolean }> { + render() { + const { isOpened, ...rest } = this.props + return ( + + + + ) } +} + +/* eslint-disable react/no-multi-comp */ - toggle = () => this.setState({ isOpened: !this.state.isOpened }) +class Spoiler extends PureComponent { + toggle = () => { + const { opened, onOpen } = this.props + onOpen(!opened) + } render() { - const { title, children, ...p } = this.props - const { isOpened } = this.state + const { title, opened, onOpen, children, ...p } = this.props return ( - - - - - - {title} - + + + {title} - {isOpened && children} + {opened && children} ) } } -export default Spoiler +export default uncontrollable(Spoiler, { + opened: 'onOpen', +}) diff --git a/src/components/modals/AccountSettingRenderBody.js b/src/components/modals/AccountSettingRenderBody.js index c4aef19d..373b391c 100644 --- a/src/components/modals/AccountSettingRenderBody.js +++ b/src/components/modals/AccountSettingRenderBody.js @@ -9,7 +9,8 @@ import { translate } from 'react-i18next' import type { Account, Unit, Currency } from '@ledgerhq/live-common/lib/types' import type { T } from 'types/common' -import { MODAL_SETTINGS_ACCOUNT } from 'config/constants' +import { MODAL_SETTINGS_ACCOUNT, MAX_ACCOUNT_NAME_SIZE } from 'config/constants' +import { validateNameEdition } from 'helpers/accountName' import { updateAccount, removeAccount } from 'actions/accounts' import { setDataModal } from 'reducers/modals' @@ -131,23 +132,18 @@ class HelperComp extends PureComponent { const { updateAccount, setDataModal } = this.props const { accountName, accountUnit, endpointConfig, endpointConfigError } = this.state - const sanitizedAccountName = accountName ? accountName.replace(/\s+/g, ' ').trim() : null - - if (account.name || sanitizedAccountName) { - account = { - ...account, - unit: accountUnit || account.unit, - name: sanitizedAccountName || account.name, - } - if (endpointConfig && !endpointConfigError) { - account.endpointConfig = endpointConfig - } - updateAccount(account) - setDataModal(MODAL_SETTINGS_ACCOUNT, { account }) - onClose() - } else { - this.setState({ accountNameError: true }) + const name = validateNameEdition(account, accountName) + account = { + ...account, + unit: accountUnit || account.unit, + name, + } + if (endpointConfig && !endpointConfigError) { + account.endpointConfig = endpointConfig } + updateAccount(account) + setDataModal(MODAL_SETTINGS_ACCOUNT, { account }) + onClose() } handleFocus = (e: any, name: string) => { @@ -211,7 +207,7 @@ class HelperComp extends PureComponent { } onFocus={e => this.handleFocus(e, 'accountName')} diff --git a/src/components/modals/AddAccounts/index.js b/src/components/modals/AddAccounts/index.js index 31aed232..ba0388f8 100644 --- a/src/components/modals/AddAccounts/index.js +++ b/src/components/modals/AddAccounts/index.js @@ -23,6 +23,7 @@ import { closeModal } from 'reducers/modals' import Modal from 'components/base/Modal' import Stepper from 'components/base/Stepper' +import { validateNameEdition } from 'helpers/accountName' import StepChooseCurrency, { StepChooseCurrencyFooter } from './steps/01-step-choose-currency' import StepConnectDevice, { StepConnectDeviceFooter } from './steps/02-step-connect-device' @@ -91,7 +92,9 @@ type State = { currency: ?Currency, scannedAccounts: Account[], checkedAccountsIds: string[], + editedNames: { [_: string]: string }, err: ?Error, + reset: number, } export type StepProps = DefaultStepProps & { @@ -104,12 +107,15 @@ export type StepProps = DefaultStepProps & { checkedAccountsIds: string[], scanStatus: ScanStatus, err: ?Error, - onClickAdd: void => Promise, - onCloseModal: void => void, - resetScanState: void => void, + onClickAdd: () => Promise, + onGoStep1: () => void, + onCloseModal: () => void, + resetScanState: () => void, setCurrency: (?Currency) => void, setAppOpened: boolean => void, setScanStatus: (ScanStatus, ?Error) => string, + setAccountName: (Account, string) => void, + editedNames: { [_: string]: string }, setScannedAccounts: ({ scannedAccounts?: Account[], checkedAccountsIds?: string[] }) => void, } @@ -129,8 +135,10 @@ const INITIAL_STATE = { currency: null, scannedAccounts: [], checkedAccountsIds: [], + editedNames: {}, err: null, scanStatus: 'idle', + reset: 0, } class AddAccounts extends PureComponent { @@ -139,15 +147,16 @@ class AddAccounts extends PureComponent { handleClickAdd = async () => { const { addAccount } = this.props - const { scannedAccounts, checkedAccountsIds } = this.state + const { scannedAccounts, checkedAccountsIds, editedNames } = this.state const accountsIdsMap = checkedAccountsIds.reduce((acc, cur) => { acc[cur] = true return acc }, {}) const accountsToAdd = scannedAccounts.filter(account => accountsIdsMap[account.id] === true) - for (let i = 0; i < accountsToAdd.length; i++) { + for (const account of accountsToAdd) { await idleCallback() - addAccount(accountsToAdd[i]) + const name = validateNameEdition(account, editedNames[account.id]) + addAccount({ ...account, name }) } } @@ -160,6 +169,12 @@ class AddAccounts extends PureComponent { this.setState({ scanStatus, err }) } + handleSetAccountName = (account: Account, name: string) => { + this.setState(({ editedNames }) => ({ + editedNames: { ...editedNames, [account.id]: name }, + })) + } + handleSetScannedAccounts = ({ checkedAccountsIds, scannedAccounts, @@ -184,6 +199,10 @@ class AddAccounts extends PureComponent { handleSetAppOpened = (isAppOpened: boolean) => this.setState({ isAppOpened }) + onGoStep1 = () => { + this.setState(({ reset }) => ({ ...INITIAL_STATE, reset: reset + 1 })) + } + render() { const { t, device, existingAccounts } = this.props const { @@ -194,9 +213,11 @@ class AddAccounts extends PureComponent { checkedAccountsIds, scanStatus, err, + editedNames, + reset, } = this.state - const addtionnalProps = { + const stepperProps = { currency, device, existingAccounts, @@ -212,6 +233,9 @@ class AddAccounts extends PureComponent { setScannedAccounts: this.handleSetScannedAccounts, resetScanState: this.handleResetScanState, setAppOpened: this.handleSetAppOpened, + setAccountName: this.handleSetAccountName, + onGoStep1: this.onGoStep1, + editedNames, } return ( @@ -221,12 +245,13 @@ class AddAccounts extends PureComponent { onHide={() => this.setState({ ...INITIAL_STATE })} render={({ onClose }) => ( diff --git a/src/components/modals/AddAccounts/steps/03-step-import.js b/src/components/modals/AddAccounts/steps/03-step-import.js index 8f960a82..7c91b17f 100644 --- a/src/components/modals/AddAccounts/steps/03-step-import.js +++ b/src/components/modals/AddAccounts/steps/03-step-import.js @@ -1,6 +1,8 @@ // @flow import invariant from 'invariant' +import styled from 'styled-components' +import { Trans } from 'react-i18next' import React, { PureComponent, Fragment } from 'react' import type { Account } from '@ledgerhq/live-common/lib/types' import uniq from 'lodash/uniq' @@ -14,9 +16,23 @@ import Button from 'components/base/Button' import AccountsList from 'components/base/AccountsList' import IconExclamationCircleThin from 'icons/ExclamationCircleThin' import TranslatedError from '../../../TranslatedError' +import Spinner from '../../../base/Spinner' +import Text from '../../../base/Text' import type { StepProps } from '../index' +const LoadingRow = styled(Box).attrs({ + horizontal: true, + borderRadius: 1, + px: 3, + align: 'center', + justify: 'center', + mt: 1, +})` + height: 48px; + border: 1px dashed ${p => p.theme.colors.grey}; +` + class StepImport extends PureComponent { componentDidMount() { this.props.setScanStatus('scanning') @@ -118,27 +134,20 @@ class StepImport extends PureComponent { } } - handleUpdateAccount = (updatedAccount: Account) => { - const { scannedAccounts, setScannedAccounts } = this.props + handleSelectAll = (accountsToSelect: Account[]) => { + const { setScannedAccounts, checkedAccountsIds } = this.props setScannedAccounts({ - scannedAccounts: scannedAccounts.map(account => { - if (account.id !== updatedAccount.id) { - return account - } - return updatedAccount - }), + checkedAccountsIds: uniq(checkedAccountsIds.concat(accountsToSelect.map(a => a.id))), }) } - handleSelectAll = () => { - const { scannedAccounts, setScannedAccounts } = this.props + handleUnselectAll = (accountsToRemove: Account[]) => { + const { setScannedAccounts, checkedAccountsIds } = this.props setScannedAccounts({ - checkedAccountsIds: scannedAccounts.filter(a => a.operations.length > 0).map(a => a.id), + checkedAccountsIds: checkedAccountsIds.filter(id => !accountsToRemove.some(a => id === a.id)), }) } - handleUnselectAll = () => this.props.setScannedAccounts({ checkedAccountsIds: [] }) - renderError() { const { err, t } = this.props invariant(err, 'Trying to render inexisting error') @@ -168,66 +177,111 @@ class StepImport extends PureComponent { scannedAccounts, checkedAccountsIds, existingAccounts, + setAccountName, + editedNames, t, } = this.props if (err) { + // TODO prefer rendering a component return this.renderError() } const currencyName = currency ? currency.name : '' - const importableAccounts = scannedAccounts.filter(acc => { - if (acc.operations.length <= 0) { - return false + const importedAccounts = [] + const importableAccounts = [] + const creatableAccounts = [] + let alreadyEmptyAccount + scannedAccounts.forEach(acc => { + const existingAccount = existingAccounts.find(a => a.id === acc.id) + const empty = acc.operations.length === 0 + if (existingAccount) { + importedAccounts.push(existingAccount) + if (empty) { + alreadyEmptyAccount = existingAccount + } + } else if (empty) { + creatableAccounts.push(acc) + } else { + importableAccounts.push(acc) } - return existingAccounts.find(a => a.id === acc.id) === undefined }) - const creatableAccounts = scannedAccounts.filter(acc => { - if (acc.operations.length > 0) { - return false - } - return existingAccounts.find(a => a.id === acc.id) === undefined + const importableAccountsListTitle = t('app:addAccounts.accountToImportSubtitle', { + count: importableAccounts.length, }) - const importableAccountsListTitle = t('app:addAccounts.accountToImportSubtitle', { + const importedAccountsListTitle = t('app:addAccounts.accountAlreadyImportedSubtitle', { count: importableAccounts.length, }) const importableAccountsEmpty = t('app:addAccounts.noAccountToImport', { currencyName }) - const alreadyEmptyAccount = scannedAccounts.find(a => a.operations.length === 0) + + const shouldShowNew = scanStatus !== 'scanning' return ( - - - + + {importedAccounts.length === 0 ? null : ( + + )} + {importableAccounts.length === 0 ? null : ( + + )} + {!shouldShowNew ? null : ( + + {' '} + + {alreadyEmptyAccount.name} + {' '} + + ) : ( + + {' '} + + {currencyName} + {' '} + + ) + } + accounts={creatableAccounts} + checkedIds={checkedAccountsIds} + onToggleAccount={this.handleToggleAccount} + setAccountName={setAccountName} + editedNames={editedNames} + /> + )} + {scanStatus === 'scanning' ? ( + + + + ) : null} {err && {err.message}} @@ -264,9 +318,7 @@ export const StepImportFooter = ({ const ctaWording = scanStatus === 'scanning' ? t('app:common.sync.syncing') - : willCreateAccount || willAddAccounts - ? t('app:addAccounts.cta.add', { count }) - : t('app:common.close') + : t('app:addAccounts.cta.add', { count }) const willClose = !willCreateAccount && !willAddAccounts const onClick = willClose @@ -291,7 +343,10 @@ export const StepImportFooter = ({ )} + {t('app:addAccounts.success')} + + + + ) } diff --git a/src/config/constants.js b/src/config/constants.js index f873cdcc..4d0c94a7 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -82,6 +82,8 @@ export const EXPERIMENTAL_HTTP_ON_RENDERER = boolFromEnv('EXPERIMENTAL_HTTP_ON_R // Other constants +export const MAX_ACCOUNT_NAME_SIZE = 30 + export const MODAL_ADD_ACCOUNTS = 'MODAL_ADD_ACCOUNTS' export const MODAL_OPERATION_DETAILS = 'MODAL_OPERATION_DETAILS' export const MODAL_RECEIVE = 'MODAL_RECEIVE' diff --git a/src/helpers/accountName.js b/src/helpers/accountName.js index fd230c68..dd319a5e 100644 --- a/src/helpers/accountName.js +++ b/src/helpers/accountName.js @@ -1,10 +1,19 @@ // @flow -import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types' +import type { Account, CryptoCurrency } from '@ledgerhq/live-common/lib/types' +import { MAX_ACCOUNT_NAME_SIZE } from 'config/constants' export const getAccountPlaceholderName = ( c: CryptoCurrency, index: number, isLegacy: boolean = false, -) => `${c.name} ${index}${isLegacy ? ' (legacy)' : ''}` +) => `${c.name} ${index + 1}${isLegacy ? ' (legacy)' : ''}` -export const getNewAccountPlaceholderName = (_c: CryptoCurrency, _index: number) => `New Account` +export const getNewAccountPlaceholderName = getAccountPlaceholderName // same naming +// export const getNewAccountPlaceholderName = (_c: CryptoCurrency, _index: number) => `New Account` + +export const validateNameEdition = (account: Account, name: ?string): string => + ( + (name || account.name || '').replace(/\s+/g, ' ').trim() || + account.name || + getAccountPlaceholderName(account.currency, account.index) + ).slice(0, MAX_ACCOUNT_NAME_SIZE) diff --git a/static/i18n/en/app.yml b/static/i18n/en/app.yml index 4ca5e314..760074f8 100644 --- a/static/i18n/en/app.yml +++ b/static/i18n/en/app.yml @@ -146,10 +146,11 @@ addAccounts: connectDevice: Connect device import: Select accounts finish: Confirmation - accountToImportSubtitle: Select existing accounts - accountToImportSubtitle_plural: 'Select ({{count}}) existing accounts' - selectAll: Select all - unselectAll: Deselect all + accountAlreadyImportedSubtitle: Already in portfolio + accountToImportSubtitle: 'Select account' + accountToImportSubtitle_plural: 'Select accounts' + selectAll: Select all ({{count}}) + unselectAll: Deselect all ({{count}}) editName: Edit name newAccount: New account legacyAccount: '{{accountName}} (legacy)' @@ -157,11 +158,12 @@ addAccounts: success: Account added to your portfolio # success_plural: Accounts successfully added to your portfolio. createNewAccount: - title: Create new account - noOperationOnLastAccount: 'You have to receive crypto assets on {{accountName}} before you can create a new account.' - noAccountToCreate: No {{currencyName}} account was found to create + title: Create a new account + noOperationOnLastAccount: 'You have to receive crypto assets on <1><0>{{accountName}} before you can create a new account.' + noAccountToCreate: No <1><0>{{currencyName}} account was found to create somethingWentWrong: Something went wrong during synchronization, please try again. cta: + addMore: 'Add more' add: 'Add account' add_plural: 'Add accounts' operationDetails: