From 0d0e5f23a926cc724596150cf7296e022f6aea49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ricks?= Date: Tue, 16 Apr 2024 11:23:44 +0200 Subject: [PATCH] Add: Add useValueChange hook for form components All form components should be able to call the onChange handler with the value, name pair. Therefore introduce a generic hook to abstract the event handling. --- .../form/__tests__/useValueChange.jsx | 43 +++++++++++++++ src/web/components/form/useValueChange.jsx | 52 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/web/components/form/__tests__/useValueChange.jsx create mode 100644 src/web/components/form/useValueChange.jsx diff --git a/src/web/components/form/__tests__/useValueChange.jsx b/src/web/components/form/__tests__/useValueChange.jsx new file mode 100644 index 0000000000..c559686db2 --- /dev/null +++ b/src/web/components/form/__tests__/useValueChange.jsx @@ -0,0 +1,43 @@ +/* SPDX-FileCopyrightText: 2024 Greenbone AG + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import {render, screen, fireEvent} from 'web/utils/testing'; + +import useValueChange from '../useValueChange'; + +const TestComponent = ({value, onChange, name, disabled}) => { + const handleChange = useValueChange({onChange, name, disabled}); + + return ( + + ); +}; + +describe('onValueChange Tests', () => { + test('should call onChange when value changes', () => { + const onChange = jest.fn(); + + render(); + + const input = screen.getByRole('textbox'); + + fireEvent.change(input, {target: {value: 'new value'}}); + + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith('new value', 'test'); + }); + + test('should not call onChange when disabled', () => { + const onChange = jest.fn(); + + render(); + + const input = screen.getByRole('textbox'); + + fireEvent.change(input, {target: {value: 'new value'}}); + + expect(onChange).not.toHaveBeenCalled(); + }); +}); diff --git a/src/web/components/form/useValueChange.jsx b/src/web/components/form/useValueChange.jsx new file mode 100644 index 0000000000..b23ecfaf8c --- /dev/null +++ b/src/web/components/form/useValueChange.jsx @@ -0,0 +1,52 @@ +/* SPDX-FileCopyrightText: 2024 Greenbone AG + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import {useCallback} from 'react'; + +import {isDefined} from 'gmp/utils/identity'; + +const eventTargetValue = event => event.target.value; +const noOpConvert = value => value; +/** + * A hook that handles the change of a value of an input field. + * + * It gets the event target value and optionally converts it. + * value and name are passed to the onChange function. + * + * @param {Object} param0 An object with the following properties: + * - disabled: A boolean that indicates if the value can be changed. + * - name: A string that represents the name of the value. + * - onChange: A function that is called when the value changes. + * - convert: A function that converts the value optionally. + * - valueFunc: A function that gets the value from the event. Defaults to event.target.value. + * @returns A function as a callback that handles the change of a value in an input field. + */ +const useValueChange = ({ + disabled, + name, + onChange, + convert = noOpConvert, + valueFunc = eventTargetValue, +}) => { + const notifyChange = useCallback( + value => { + if (isDefined(onChange) && !disabled) { + onChange(value, name); + } + }, + [disabled, name, onChange], + ); + + const handleChange = useCallback( + event => { + notifyChange(convert(valueFunc(event))); + }, + [notifyChange, convert, valueFunc], + ); + + return handleChange; +}; + +export default useValueChange;