import { OutlinedInputProps } from '@mui/material'; import { FormikConfig, FormikValues, useFormik } from 'formik'; import { useCallback, useMemo } from 'react'; import debounce from '../lib/debounce'; import getFormikErrorMessages from '../lib/getFormikErrorMessages'; const useFormikUtils = ( formikConfig: FormikConfig, ): FormikUtils => { const formik = useFormik({ ...formikConfig }); const getFieldChanged = useCallback( (field: string) => { const parts = field.split('.'); const traverse = (values: Tree): boolean => parts.reduce((previous, part) => { if (!(part in values)) { return false; } const value = values[part]; if (value !== null && typeof value === 'object') { return traverse(value as Tree); } return value === formik.initialValues[part]; }, false); return traverse(formik.values); }, [formik.initialValues, formik.values], ); const disableAutocomplete = useCallback( (overwrite?: Partial): OutlinedInputProps => ({ readOnly: true, onFocus: (event) => { event.target.readOnly = false; }, ...overwrite, }), [], ); const debounceHandleChange = useMemo( () => debounce(formik.handleChange), [formik.handleChange], ); const disabledSubmit = useMemo( () => !formik.dirty || !formik.isValid || formik.isValidating || formik.isSubmitting, [formik.dirty, formik.isSubmitting, formik.isValid, formik.isValidating], ); const formikErrors = useMemo( () => getFormikErrorMessages(formik.errors, { skip: (field) => !getFieldChanged(field), }), [formik.errors, getFieldChanged], ); return { disableAutocomplete, disabledSubmit, formik, formikErrors, handleChange: debounceHandleChange, }; }; export default useFormikUtils;