diff --git a/source/components/CurrencyInput/CurrencyInput.js b/source/components/CurrencyInput/CurrencyInput.js
index 5cb641353..0203aaef0 100644
--- a/source/components/CurrencyInput/CurrencyInput.js
+++ b/source/components/CurrencyInput/CurrencyInput.js
@@ -15,35 +15,52 @@ let currencyFormat = language => ({
thousandSeparator: Intl.NumberFormat(language)
.format(1000)
+ .charAt(1),
+
+ decimalSeparator: Intl.NumberFormat(language)
+ .format(0.1)
.charAt(1)
})
class CurrencyInput extends Component {
state = {
- value: this.props.storeValue
+ value: this.props.value || '',
+ valueHasChanged: false,
}
+
onChange = this.props.debounce
? debounce(this.props.debounce, this.props.onChange)
: this.props.onChange
- componentDidUpdate(prevProps) {
- if (
- prevProps.storeValue !== this.props.storeValue &&
- this.props.storeValue !== this.state.value
- ) {
- this.setState({ value: this.props.storeValue })
+ handleNextChange = false
+ value = undefined
+ handleChange = event => {
+ // Only trigger the `onChange` event if the value has changed -- and not
+ // only its formating, we don't want to call it when a dot is added in `12.`
+ // for instance
+ if (!this.handleNextChange) {
+ return
}
+ this.handleNextChange = false
+ event.persist()
+ event.target = {
+ ...event.target,
+ value: this.value
+ }
+ this.onChange(event)
}
render() {
let forwardedProps = omit(
- ['onChange', 'defaultValue', 'language', 'className', 'value', 'normalizedValueRef'],
+ ['onChange', 'defaultValue', 'language', 'className', 'value'],
this.props
)
- const { isCurrencyPrefixed, thousandSeparator } = currencyFormat(
- this.props.language
- )
+ const {
+ isCurrencyPrefixed,
+ thousandSeparator,
+ decimalSeparator
+ } = currencyFormat(this.props.language)
return (
{
- this.setState({ value })
- this.props.normalizedValueRef.current = value
+ this.setState({valueHasChanged: true, value})
+ this.value = value.toString().replace(/^\-/,'')
+ this.handleNextChange = true
}}
- onChange={this.onChange}
- value={this.state.value}
+ onChange={this.handleChange}
+ value={this.state.value.toString()
+ .replace('.', decimalSeparator)}
/>
{!isCurrencyPrefixed && <> €>}
diff --git a/source/components/CurrencyInput/CurrencyInput.test.js b/source/components/CurrencyInput/CurrencyInput.test.js
index f1e0f6eb4..cdee61c95 100644
--- a/source/components/CurrencyInput/CurrencyInput.test.js
+++ b/source/components/CurrencyInput/CurrencyInput.test.js
@@ -1,10 +1,10 @@
import { expect } from 'chai'
-import { shallow } from 'enzyme'
+import { shallow, mount } from 'enzyme'
import React from 'react'
import { match, spy, useFakeTimers } from 'sinon'
import CurrencyInput from './CurrencyInput'
-let getInput = component => shallow(component).find('input')
+let getInput = component => mount(component).find('input')
describe('CurrencyInput', () => {
it('should render an input', () => {
expect(getInput()).to.have.length(1)
@@ -13,20 +13,36 @@ describe('CurrencyInput', () => {
it('should accept both . and , as decimal separator', () => {
let onChange = spy()
const input = getInput()
- input.simulate('change', { target: { value: '12.1' } })
+ input.simulate('change', { target: { value: '12.1', focus: () => {} } })
expect(onChange).to.have.been.calledWith(
match.hasNested('target.value', '12.1')
)
- input.simulate('change', { target: { value: '12,1' } })
+ input.simulate('change', { target: { value: '12,1', focus: () => {} } })
expect(onChange).to.have.been.calledWith(
match.hasNested('target.value', '12.1')
)
})
+ it('should separate thousand groups', () => {
+ const input1 = getInput()
+ const input2 = getInput()
+ const input3 = getInput()
+ const input4 = getInput()
+ expect(input1.instance().value).to.equal('1 000')
+ expect(input2.instance().value).to.equal('1,000')
+ expect(input3.instance().value).to.equal('1,000.5')
+ expect(input4.instance().value).to.equal('1,000,000')
+ })
+
+ it('should handle decimal separator', () => {
+ const input = getInput()
+ expect(input.instance().value).to.equal('0,5')
+ })
+
it('should not accept negative number', () => {
let onChange = spy()
const input = getInput()
- input.simulate('change', { target: { value: '-12' } })
+ input.simulate('change', { target: { value: '-12', focus: () => {} } })
expect(onChange).to.have.been.calledWith(
match.hasNested('target.value', '12')
)
@@ -35,19 +51,21 @@ describe('CurrencyInput', () => {
it('should not accept anything else than number', () => {
let onChange = spy()
const input = getInput()
- input.simulate('change', { target: { value: '*1/2abc3' } })
+ input.simulate('change', { target: { value: '*1/2abc3', focus: () => {} } })
expect(onChange).to.have.been.calledWith(
match.hasNested('target.value', '123')
)
})
+
it('should pass other props to the input', () => {
const input = getInput()
expect(input.prop('autoFocus')).to.be.true
})
+
it('should not call onChange while the decimal part is being written', () => {
let onChange = spy()
const input = getInput()
- input.simulate('change', { target: { value: '111,' } })
+ input.simulate('change', { target: { value: '111,', focus: () => {} } })
expect(onChange).not.to.have.been.called
})
@@ -74,10 +92,10 @@ describe('CurrencyInput', () => {
const input = getInput(
)
- input.simulate('change', { target: { value: '1' } })
+ input.simulate('change', { target: { value: '1', focus: () => {} } })
expect(onChange).not.to.have.been.called
clock.tick(500)
- input.simulate('change', { target: { value: '12' } })
+ input.simulate('change', { target: { value: '12', focus: () => {} } })
clock.tick(600)
expect(onChange).not.to.have.been.called
clock.tick(400)
diff --git a/source/components/TargetSelection.js b/source/components/TargetSelection.js
index f496113df..2648af962 100644
--- a/source/components/TargetSelection.js
+++ b/source/components/TargetSelection.js
@@ -250,7 +250,7 @@ let CurrencyField = withColours(props => {
}}
debounce={600}
className="targetInput"
- storeValue={props.input.value}
+ value={props.input.value}
{...props.input}
{...props}
/>
@@ -267,7 +267,6 @@ let TargetInputOrValue = withLanguage(
firstStepCompleted,
inversionFail
}) => {
- let normalizedValueRef = useRef(null)
let inputIsActive = activeInput === target.dottedName
return (
@@ -275,10 +274,9 @@ let TargetInputOrValue = withLanguage(
event.preventDefault()}
{...(inputIsActive ? { autoFocus: true } : {})}
language={language}
- normalize={(value) => normalizedValueRef.current || value}
/>
) : (
{
return value == null
? ''