diff --git a/striker-ui/hooks/useFormUtils.ts b/striker-ui/hooks/useFormUtils.ts index f0ae1ea3..58d6e9bb 100644 --- a/striker-ui/hooks/useFormUtils.ts +++ b/striker-ui/hooks/useFormUtils.ts @@ -1,10 +1,13 @@ import { MutableRefObject, useCallback, useMemo, useState } from 'react'; +import api from '../lib/api'; import buildObjectStateSetterCallback, { buildRegExpObjectStateSetterCallback, } from '../lib/buildObjectStateSetterCallback'; +import handleAPIError from '../lib/handleAPIError'; import { Message } from '../components/MessageBox'; import { MessageGroupForwardedRefContent } from '../components/MessageGroup'; +import useProtectedState from './useProtectedState'; const useFormUtils = < U extends string, @@ -14,6 +17,7 @@ const useFormUtils = < ids: I, messageGroupRef: MutableRefObject, ): FormUtils => { + const [formSubmitting, setFormSubmitting] = useProtectedState(false); const [formValidity, setFormValidity] = useState>({}); const setMessage = useCallback( @@ -80,7 +84,32 @@ const useFormUtils = < [unsetKey], ); - const isFormInvalid = useMemo( + const submitForm = useCallback( + ({ body, getErrorMsg, msgKey = 'api', method, successMsg, url }) => { + setFormSubmitting(true); + + api + .request({ data: body, method, url }) + .then(() => { + messageGroupRef?.current?.setMessage?.call(null, msgKey, { + children: successMsg, + }); + }) + .catch((apiError) => { + const emsg = handleAPIError(apiError); + + emsg.children = getErrorMsg(emsg.children); + + messageGroupRef?.current?.setMessage?.call(null, msgKey, emsg); + }) + .finally(() => { + setFormSubmitting(false); + }); + }, + [messageGroupRef, setFormSubmitting], + ); + + const formInvalid = useMemo( () => Object.values(formValidity).some((isInputValid) => !isInputValid), [formValidity], ); @@ -90,12 +119,14 @@ const useFormUtils = < buildInputFirstRenderFunction, buildInputUnmountFunction, formValidity, - isFormInvalid, + isFormInvalid: formInvalid, + isFormSubmitting: formSubmitting, setFormValidity, setMessage, setMessageRe, setValidity, setValidityRe, + submitForm, unsetKey, unsetKeyRe, }; diff --git a/striker-ui/types/FormUtils.d.ts b/striker-ui/types/FormUtils.d.ts index b65f506c..2341f3ab 100644 --- a/striker-ui/types/FormUtils.d.ts +++ b/striker-ui/types/FormUtils.d.ts @@ -20,12 +20,24 @@ type InputUnmountFunctionBuilder = ( key: keyof M, ) => InputUnmountFunction; +type SubmitFormFunction = (args: { + body: Record; + getErrorMsg: ( + parentMsg: import('react').ReactNode, + ) => import('react').ReactNode; + msgKey?: string; + method: 'delete' | 'post' | 'put'; + successMsg?: import('react').ReactNode; + url: string; +}) => void; + type FormUtils = { buildFinishInputTestBatchFunction: InputTestBatchFinishCallbackBuilder; buildInputFirstRenderFunction: InputFirstRenderFunctionBuilder; buildInputUnmountFunction: InputUnmountFunctionBuilder; formValidity: FormValidity; isFormInvalid: boolean; + isFormSubmitting: boolean; setFormValidity: import('react').Dispatch< import('react').SetStateAction> >; @@ -39,6 +51,7 @@ type FormUtils = { ) => void; setValidity: (key: keyof M, value?: boolean) => void; setValidityRe: (re: RegExp, value?: boolean) => void; + submitForm: SubmitFormFunction; unsetKey: (key: keyof M) => void; unsetKeyRe: (re: RegExp) => void; };