import { json } from 'remix' ; import type { NonNullProperties } from '~/types' ; import { getErrorMessage , getNonNull } from './misc' ; type ErrorMessage = string ; type NoError = null ; type FormValue = string | null ; async function handleFormSubmission < ActionData extends { status : 'success' | 'error' ; fields : { [ field ] : FormValue ; } ; errors : { [ field ] : ErrorMessage | NoError ; } ; } > ( { form , request , validators , actionData = { fields : { } , errors : { } } , handleFormValues , } ) { try { if ( ! form ) { const requestText = await request ! . text ( ) ; form = new URLSearchParams ( requestText ) ; } for ( const fieldName of Object . keys ( validators ) ) { const formValue = form . get ( fieldName ) ; actionData . fields [ fieldName ] = formValue ?? '' ; } await Promise . all ( Object . entries ( validators ) . map ( async ( [ fieldName , validator ] ) => { const formValue = form ! . get ( fieldName ) ; actionData . errors [ fieldName ] = await validator ( formValue , actionData . fields ) ; } ) ) ; if ( Object . values ( actionData . errors ) . some ( err => err !== null ) ) { return json ( { ... actionData , status : 'error' } , 400 ) ; } const nonNullFields = getNonNull ( actionData . fields ) ; const response = await handleFormValues ( nonNullFields as NonNullProperties < ActionData [ 'fields' ] > ) ; return response ; } catch ( error ) { actionData . errors . generalError = getErrorMessage ( error ) ; return json ( actionData , 500 ) ; } } export { handleFormSubmission } ;