Browse Source

Merge pull request #578 from gre/fixes-15june

Polishes
master
Meriadec Pillet 7 years ago
committed by GitHub
parent
commit
3724de2140
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      src/bridge/LibcoreBridge.js
  2. 4
      src/components/DeviceConfirm/index.js
  3. 82
      src/components/base/InputCurrency/index.js
  4. 5
      src/components/modals/Send/03-step-verification.js
  5. 16
      src/components/modals/Send/index.js
  6. 3
      src/helpers/createCustomErrorClass.js
  7. 6
      src/helpers/libcore.js
  8. 1
      static/i18n/en/errors.yml

18
src/bridge/LibcoreBridge.js

@ -48,7 +48,7 @@ const EditAdvancedOptions = ({ onChange, value }: EditProps<Transaction>) => (
const recipientValidLRU = LRU({ max: 100 })
const isRecipientValid = (currency, recipient): Promise<boolean> => {
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<Transaction> = {
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(() => true)
.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)

4
src/components/DeviceConfirm/index.js

@ -41,7 +41,7 @@ const WrapperIcon = styled(Box)`
}
`
const Check = ({ error }: { error: * }) => (
const Check = ({ error }: { error?: boolean }) => (
<WrapperIcon error={error}>
{error ? <IconCross size={10} /> : <IconCheck size={10} />}
</WrapperIcon>
@ -74,7 +74,7 @@ const PushButton = styled(Box)`
`
type Props = {
error: *,
error?: boolean,
}
const SVG = (

82
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,8 +13,41 @@ import Select from 'components/base/LegacySelect'
import type { Unit } from '@ledgerhq/live-common/lib/types'
function parseValue(value) {
return value.toString().replace(/,/g, '.')
// 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 = Math.max(0, decimals); i < unit.magnitude; ++i) {
value += '0'
}
if (!value) value = '0'
return { display, value }
}
function format(unit: Unit, value: number, { isFocused, showAllDigits, subMagnitude }) {
@ -85,9 +117,10 @@ class InputCurrency extends PureComponent<Props, State> {
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({
@ -104,28 +137,13 @@ class InputCurrency extends PureComponent<Props, State> {
}
handleChange = (v: string) => {
v = parseValue(v)
// 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
if (isNaN(Number(v))) {
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 = () => {
@ -149,16 +167,6 @@ class InputCurrency extends PureComponent<Props, State> {
})
}
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 => <Currency>{item.code}</Currency>

5
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) => (
<Container>
<WarnBox>{multiline(t('app:send.steps.verification.warning'))}</WarnBox>
<Info>{t('app:send.steps.verification.body')}</Info>
<DeviceConfirm error={hasError} />
<DeviceConfirm />
</Container>
)

16
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<Props, State<*>> {
})
}
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 => {

3
src/helpers/createCustomErrorClass.js

@ -1,6 +1,6 @@
// @flow
export default (name: string) => {
export default (name: string): Class<any> => {
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
}

6
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<typeof core.OPERATION_TYPES>]: 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,

1
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

Loading…
Cancel
Save