// @ts-nocheck import React, { FC, useState, useEffect, useRef } from 'react'; import { InputGroup } from '@blueprintjs/core'; import { CurrencyInputProps } from './CurrencyInputProps'; import { isNumber, cleanValue, fixedDecimalValue, formatValue, padTrimValue, CleanValueOptions, } from './utils'; export const CurrencyInput: FC = ({ allowDecimals = true, allowNegativeValue = true, id, name, className, decimalsLimit, defaultValue, disabled = false, maxLength: userMaxLength, value: userValue, onChange, onBlurValue, fixedDecimalLength, placeholder, precision, prefix, step, decimalSeparator = '.', groupSeparator = ',', turnOffSeparators = false, turnOffAbbreviations = false, ...props }: CurrencyInputProps) => { if (decimalSeparator === groupSeparator) { throw new Error('decimalSeparator cannot be the same as groupSeparator'); } if (isNumber(decimalSeparator)) { throw new Error('decimalSeparator cannot be a number'); } if (isNumber(groupSeparator)) { throw new Error('groupSeparator cannot be a number'); } const formatValueOptions = { decimalSeparator, groupSeparator, turnOffSeparators, prefix, }; const cleanValueOptions: Partial = { decimalSeparator, groupSeparator, allowDecimals, decimalsLimit: decimalsLimit || fixedDecimalLength || 2, allowNegativeValue, turnOffAbbreviations, prefix, }; const _defaultValue = defaultValue !== undefined ? formatValue({ value: String(defaultValue), ...formatValueOptions }) : ''; const [stateValue, setStateValue] = useState(_defaultValue); const [cursor, setCursor] = useState(0); const inputRef = useRef(null); const onFocus = (): number => (stateValue ? stateValue.length : 0); const processChange = ( value: string, selectionStart?: number | null, ): void => { const valueOnly = cleanValue({ value, ...cleanValueOptions }); if (!valueOnly) { onChange && onChange(undefined, name); setStateValue(''); return; } if (userMaxLength && valueOnly.replace(/-/g, '').length > userMaxLength) { return; } if (valueOnly === '-') { onChange && onChange(undefined, name); setStateValue(value); return; } const formattedValue = formatValue({ value: valueOnly, ...formatValueOptions, }); /* istanbul ignore next */ if (selectionStart !== undefined && selectionStart !== null) { const cursor = selectionStart + (formattedValue.length - value.length) || 1; setCursor(cursor); } setStateValue(formattedValue); onChange && onChange(valueOnly, name); }; const handleOnChange = ({ target: { value, selectionStart }, }: React.ChangeEvent): void => { processChange(value, selectionStart); }; const handleOnBlur = ({ target: { value }, }: React.ChangeEvent): void => { const valueOnly = cleanValue({ value, ...cleanValueOptions }); if (valueOnly === '-' || !valueOnly) { onBlurValue && onBlurValue(undefined, name); setStateValue(''); return; } const fixedDecimals = fixedDecimalValue( valueOnly, decimalSeparator, fixedDecimalLength, ); // Add padding or trim value to precision const newValue = padTrimValue( fixedDecimals, decimalSeparator, precision || fixedDecimalLength, ); onChange && onChange(newValue, name); onBlurValue && onBlurValue(newValue, name); const formattedValue = formatValue({ value: newValue, ...formatValueOptions, }); setStateValue(formattedValue); }; const handleOnKeyDown = ({ key }: React.KeyboardEvent) => { if (step && (key === 'ArrowUp' || key === 'ArrowDown')) { const currentValue = Number( userValue !== undefined ? userValue : cleanValue({ value: stateValue, ...cleanValueOptions }), ) || 0; const newValue = key === 'ArrowUp' ? String(currentValue + Number(step)) : String(currentValue - Number(step)); processChange(newValue); } }; /* istanbul ignore next */ useEffect(() => { if (inputRef && inputRef.current) { inputRef.current.setSelectionRange(cursor, cursor); } }, [cursor, inputRef]); const formattedPropsValue = userValue !== undefined ? formatValue({ value: String(userValue), ...formatValueOptions }) : undefined; const handleInputRef = (ref: HTMLInputElement | null) => { inputRef.current = ref; return null; }; return ( ); }; export { CurrencyInput as MoneyInputGroup };