From 4adc1a38eddfbccad380772cb0bf22f252a4aedc Mon Sep 17 00:00:00 2001 From: vince-fugnitto Date: Thu, 18 Feb 2021 12:42:00 -0500 Subject: [PATCH] preferences: fix 'number' input validation The following commit fixes the validation for `number` type inputs in the preferences-ui which resulted in false negatives when users attempted to input `0` as a valid value. Signed-off-by: vince-fugnitto --- .../components/preference-number-input.tsx | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/packages/preferences/src/browser/views/components/preference-number-input.tsx b/packages/preferences/src/browser/views/components/preference-number-input.tsx index 2e984d08493e1..45991b644c68f 100644 --- a/packages/preferences/src/browser/views/components/preference-number-input.tsx +++ b/packages/preferences/src/browser/views/components/preference-number-input.tsx @@ -27,7 +27,7 @@ export const PreferenceNumberInput: React.FC = ({ pr const { id } = preferenceDisplayNode; const { data, value } = preferenceDisplayNode.preference; - const externalValue = (value !== undefined ? value : data.defaultValue) || ''; + const externalValue = (value !== undefined ? value : data.defaultValue) ?? ''; const [currentTimeout, setCurrentTimetout] = React.useState(0); const [currentValue, setCurrentValue] = React.useState(externalValue); @@ -46,34 +46,42 @@ export const PreferenceNumberInput: React.FC = ({ pr clearTimeout(currentTimeout); const { value: newValue } = e.target; setCurrentValue(newValue); - const preferenceValue: number = Number(newValue); - const { isValid, message } = getInputValidation(preferenceValue); + const { inputValue, message } = getInputValidation(newValue); setValidationMessage(message); - if (isValid) { - const newTimeout = setTimeout(() => setPreference(id, preferenceValue), 750); + if (!isNaN(inputValue)) { + const newTimeout = setTimeout(() => setPreference(id, inputValue), 750); setCurrentTimetout(Number(newTimeout)); } }, [currentTimeout]); /** - * Validates the input. + * Validate the input value. * @param input the input value. */ - const getInputValidation = (input: number | undefined): { isValid: boolean, message: string } => { + const getInputValidation = (input: string): { + inputValue: number, // the numeric value of the input. `NaN` if there is an error. + message: string // the error message to display. + } => { + const inputValue = Number(input); const errorMessages: string[] = []; - if (!input) { - return { isValid: false, message: 'Value must be a number.' }; - }; - if (data.minimum && input < data.minimum) { + + if (input === '' || isNaN(inputValue)) { + return { inputValue: NaN, message: 'Value must be a number.' }; + } + if (data.minimum && inputValue < data.minimum) { errorMessages.push(`Value must be greater than or equal to ${data.minimum}.`); }; - if (data.maximum && input > data.maximum) { + if (data.maximum && inputValue > data.maximum) { errorMessages.push(`Value must be less than or equal to ${data.maximum}.`); }; - if (data.type === 'integer' && input % 1 !== 0) { + if (data.type === 'integer' && inputValue % 1 !== 0) { errorMessages.push('Value must be an integer.'); } - return { isValid: !errorMessages.length, message: errorMessages.join(' ') }; + + return { + inputValue: errorMessages.length ? NaN : inputValue, + message: errorMessages.join(' ') + }; }; return ( @@ -90,4 +98,5 @@ export const PreferenceNumberInput: React.FC = ({ pr {!!validationMessage.length ?
{validationMessage}
: undefined} ); + };