Skip to content

Commit

Permalink
Fix submit handling
Browse files Browse the repository at this point in the history
  • Loading branch information
ph-fritsche committed Sep 27, 2020
1 parent 516784c commit de6d921
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 32 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"react-test-renderer": "^16.13.1"
},
"dependencies": {
"liform-util": "^0.1.0"
"liform-util": "^0.2.1"
},
"peerDependencies": {
"final-form": "^4.20",
Expand Down
26 changes: 2 additions & 24 deletions src/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useMemo, useState, useCallback, useRef } from 'react';
import PropTypes from 'prop-types';
import arrayMutators from 'final-form-arrays'
import { Form as FinalForm, FormRenderProps as FinalFormRenderProps } from 'react-final-form';
import { buildSubmitHandler, buildSubmitHandlerProps } from './submit';
import { buildSubmitHandlerProps, useSubmitHandler } from './submit';
import { buildFlatValidatorStack, buildFlatAjvValidate, buildFlatValidatorHandler, translateAjv } from './validate';
import { compileSchema, SchemaProp } from './schema';

Expand Down Expand Up @@ -88,29 +88,7 @@ export function Liform(props) {
updateData,
])

const onSubmit = useMemo(() => (props.buildSubmitHandler || buildSubmitHandler)(liformApi, {
action: props.action,
prepareRequest: props.prepareRequest,
handleSubmitError: props.handleSubmitError,
handleSubmitResponse: props.handleSubmitResponse,
handleSubmitRedirectResponse: props.handleSubmitRedirectResponse,
onSubmitRedirect: props.onSubmitRedirect,
onSubmitHtmlResponse: props.onSubmitHtmlResponse,
onSubmitSuccess: props.onSubmitSuccess,
onSubmitFail: props.onSubmitFail,
}), [
props.buildSubmitHandler,
liformApi,
props.action,
props.prepareRequest,
props.handleSubmitError,
props.handleSubmitResponse,
props.handleSubmitRedirectResponse,
props.onSubmitRedirect,
props.onSubmitHtmlResponse,
props.onSubmitSuccess,
props.onSubmitFail,
])
const onSubmit = useSubmitHandler(liformApi, props)

const onValidate = useMemo(() => buildFlatValidatorHandler(buildFlatValidatorStack(
buildFlatAjvValidate(props.ajv, liformApi.schema, props.ajvTranslator || translateAjv),
Expand Down
47 changes: 45 additions & 2 deletions src/submit.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import PropTypes from 'prop-types'
import { FORM_ERROR } from 'final-form'
import { htmlizeName } from './util'
import { useMemo } from 'react'
import { filterObject } from 'liform-util'

export const defaultHandlers = {
prepareRequest (values, liform) {
Expand Down Expand Up @@ -113,19 +115,20 @@ export const defaultHandlers = {
}

export function buildSubmitHandler (liform, {action = '', ...handlers}) {
const effectiveHandlers = { ...defaultHandlers, ...filterObject(handlers, v => typeof(v) === 'function') }
const {
prepareRequest,
handleSubmitResponse,
handleSubmitError,
} = {...defaultHandlers, ...handlers}
} = effectiveHandlers

return (values) => {
const liformValue = values?._
const request = prepareRequest(liformValue, liform, defaultHandlers.prepareRequest)

return new Promise((resolve, reject) => {
fetch(action, request).then(
response => handleSubmitResponse({resolve, reject}, response, liform, {...defaultHandlers, ...handlers}),
response => handleSubmitResponse({ resolve, reject }, response, liform, effectiveHandlers),
reason => handleSubmitError({resolve, reject}, reason, action, request),
)
})
Expand All @@ -144,3 +147,43 @@ export const buildSubmitHandlerProps = {
onSubmitSuccess: PropTypes.func,
onSubmitFail: PropTypes.func,
}

export function useSubmitHandler(liform, {
buildSubmitHandler: buildFn = buildSubmitHandler,
action,
prepareRequest,
handleSubmitError,
handleSubmitResponse,
handleSubmitRedirectResponse,
onSubmitRedirect,
onSubmitHtmlResponse,
onSubmitResult,
onSubmitSuccess,
onSubmitFail,
} = {}) {
return useMemo(() => buildFn(liform, {
action,
prepareRequest,
handleSubmitError,
handleSubmitResponse,
handleSubmitRedirectResponse,
onSubmitRedirect,
onSubmitHtmlResponse,
onSubmitResult,
onSubmitSuccess,
onSubmitFail,
}), [
buildFn,
liform,
action,
prepareRequest,
handleSubmitError,
handleSubmitResponse,
handleSubmitRedirectResponse,
onSubmitRedirect,
onSubmitHtmlResponse,
onSubmitResult,
onSubmitSuccess,
onSubmitFail,
])
}
47 changes: 46 additions & 1 deletion test/submit.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { buildSubmitHandler } from '../src/submit'
import React from 'react'
import { buildSubmitHandler, useSubmitHandler } from '../src/submit'
import { FORM_ERROR } from 'final-form'
import { create } from 'react-test-renderer'

let realDocument
let realFetch
Expand Down Expand Up @@ -33,6 +35,49 @@ function mockFetch(...results) {
}

describe('Submit handler', () => {
it('useSubmitHandler hook provides submit handler', () => {
const builtResult = () => {}
const builtFn = jest.fn(() => builtResult)
const prepareRequestFn = () => {}
const liform = {}

let handler
create(React.createElement(() => {
handler = useSubmitHandler(liform, {
buildSubmitHandler: builtFn,
action: 'foo',
prepareRequest: prepareRequestFn,
})
return null
}))

expect(builtFn).toBeCalled()
expect(builtFn.mock.calls[0][0]).toBe(liform)
const handlerProps = builtFn.mock.calls[0][1]
expect(handlerProps).toHaveProperty('action', 'foo')
expect(handlerProps).toHaveProperty('prepareRequest', prepareRequestFn)

expect(handler).toBe(builtResult)
})

it('builtSubmitHandler filters non-function handler props', async () => {
const response = {}
const fetch = mockFetch(response)
const handleSubmitResponseFn = jest.fn(({resolve}, res) => resolve(res))

const promise = buildSubmitHandler({}, {prepareRequest: 'foo', handleSubmitResponse: handleSubmitResponseFn})({_: 'bar'})

expect(fetch).toBeCalled()
expect(typeof(fetch.mock.calls[0][1])).toBe('object')

expect(promise).toBeInstanceOf(Promise)

await promise

expect(handleSubmitResponseFn).toBeCalled()
expect(handleSubmitResponseFn.mock.calls[0][1]).toBe(response)
})

it('Inject prepareRequest', () => {
const fetch = mockFetch()
const handler = jest.fn(() => ({}))
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5857,10 +5857,10 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"

liform-util@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/liform-util/-/liform-util-0.1.0.tgz#31465cac2d0001825b9d271eb5f4ce938cc2ec36"
integrity sha512-tzvP3W1JipmDwIMqedONM6qIM2UpLBMVjBaiQEVLnUB5DXIXMNXw/np0PO08laqPqZ57wJn6q7TWNHjeEPfL3w==
liform-util@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/liform-util/-/liform-util-0.2.1.tgz#0f84a111b1d5825ff72909dc0128b7454ae051e6"
integrity sha512-rFI6zdJ1r5tmGiDdCeymE0JhmSgXkAb0vj4YHJd7mMyCXKfvwrlrMwnEdT8yXuo7kWpIIIM6sBhevhBs+0IvRA==

lines-and-columns@^1.1.6:
version "1.1.6"
Expand Down

0 comments on commit de6d921

Please sign in to comment.