AmountField

by Sébastien Castiel

HTML

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="container" />

CSS

input {
  padding: 3px;
  border-radius: 3px;
  border: 0.5px solid lightgray;
  font-size: large;
}

Babel + JSX

class AmountField extends React.Component {
	constructor(props) {
  	super(props);
    this.state = this._createStateFromProps(props);
  }
  componentWillReceiveProps(newProps) {
  	this.setState(this._createStateFromProps(newProps));
  }
  _createStateFromProps(props) {
  	return { amountString: amountToString(props.amount) };
  }
  handleChange = event => {
  	this.setState({ amountString: cleanAmountString(event.target.value) });
  }
  handleFocus = () => {
  	this.setState({ amountString: amountToString(this.props.amount) });
  }
  handleBlur = () => {
  	const amount = amountFromString(this.state.amountString);
    const roundedAmount = Math.round(amount * 100) / 100;
    this.props.onChange(roundedAmount);
  }
  render() {
  	const { amountString } = this.state;
  	return (
      <input
        type='text'
        value={amountString}
        onChange={this.handleChange}
        onFocus={this.handleFocus}
        onBlur={this.handleBlur}
        />
    );
  }
}

class App extends React.Component {
	constructor(props) {
  	super(props);
  	this.state = { amount: 2123.45 };
  }
  onAmountChange = (amount) => {
  	this.setState({ amount });
  }
	render() {
  	return (
      <div>
        <div><AmountField onChange={this.onAmountChange} amount={this.state.amount} /></div>
        <div>Amount: <code>{this.state.amount}</code></div>
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('container')
);

// UTILITY FUNCTIONS /////////////////////////////////////////////////////////////////////////////

function cleanAmountString(amountString) {
	return amountString.replace(/[^\d\.,\s\$]/g, '');
}

function amountToString(amount) {
  return typeof amount === 'number'
    ? amount.toLocaleString(
      	undefined,
      	{ minimumFractionDigits: 2, maximumFractionDigits: 2 }
  		) + ' $'
    : '';
}

function amountFromString(amountString) {
  const cleanedAmountString = amountString.replace(/[^\d\.,]/g, '').replace(',', '.');
  const...