Files
bigcapital/client/src/components/MoneyInputGroup.js
2020-09-04 00:41:22 +02:00

110 lines
2.7 KiB
JavaScript

import React, { useState, useMemo, useEffect, useCallback } from 'react';
import { InputGroup } from '@blueprintjs/core';
const joinIntegerAndDecimal = (integer, decimal, separator) => {
let output = `${integer}`;
if (separator) {
output += separator;
output += decimal ? decimal : '';
}
return output;
};
const hasSeparator = (input, separator) => {
return -1 !== input.indexOf(separator);
};
const addThousandSeparator = (integer, separator) => {
return integer.replace(/(\d)(?=(?:\d{3})+\b)/gm, `$1${separator}`);
};
const toString = (number) => `${number}`;
const onlyNumbers = (input) => {
return toString(input).replace(/\D+/g, '') || '0';
};
const formatter = (value, options) => {
const input = toString(value);
const navigate = input.indexOf('-') >= 0 ? '-' : '';
const parts = toString(input).split(options.decimal);
const integer = parseInt(onlyNumbers(parts[0]), 10);
const decimal = parts[1] ? onlyNumbers(parts[1]) : null;
const integerThousand = addThousandSeparator(
toString(integer),
options.thousands,
);
const separator = hasSeparator(input, options.decimal)
? options.decimal
: false;
return `${navigate}${options.prefix}${joinIntegerAndDecimal(
integerThousand,
decimal,
separator,
)}${options.suffix}`;
};
const unformatter = (input, options) => {
const navigate = input.indexOf('-') >= 0 ? '-' : '';
const parts = toString(input).split(options.decimal);
const integer = parseInt(onlyNumbers(parts[0]), 10);
const decimal = parts[1] ? onlyNumbers(parts[1]) : null;
const separator = hasSeparator(input, options.decimal)
? options.decimal
: false;
return `${navigate}${joinIntegerAndDecimal(integer, decimal, separator)}`;
};
export default function MoneyFieldGroup({
value,
prefix = '',
suffix = '',
thousands = ',',
decimal = '.',
precision = 2,
inputGroupProps,
onChange,
disabled = false,
}) {
const [state, setState] = useState(value);
const options = useMemo(
() => ({
prefix,
suffix,
thousands,
decimal,
precision,
}),
[prefix, suffix, thousands, decimal, precision],
);
const handleChange = useCallback(
(event) => {
const formatted = formatter(event.target.value, options);
const value = unformatter(event.target.value, options);
setState(formatted);
onChange && onChange(event, value);
},
[onChange, options],
);
useEffect(() => {
const formatted = formatter(value, options);
setState(formatted);
}, [value, options, setState]);
return (
<InputGroup
value={state}
onChange={handleChange}
{...inputGroupProps}
disabled={disabled}
/>
);
}