Skip to content

Instantly share code, notes, and snippets.

@steida
Created April 24, 2020 22:00
Show Gist options
  • Save steida/b48c6c77169e8a84d0bf94368e7086b3 to your computer and use it in GitHub Desktop.
Save steida/b48c6c77169e8a84d0bf94368e7086b3 to your computer and use it in GitHub Desktop.
import { either } from 'fp-ts';
import { constVoid } from 'fp-ts/lib/function';
import { pipe } from 'fp-ts/lib/pipeable';
import * as t from 'io-ts';
import { useCallback } from 'react';
import { Api } from '../types';
import { useApi } from './useApi';
import { Form, useForm } from './useForm';
export const useMutation = <
Name extends keyof Api,
Endpoint extends typeof Api['props'][Name]
>(
name: Name,
// t.Output type, because that's what useForm uses. Check useForm.ts to see why.
initialState: t.OutputOf<Endpoint['props']['input']>,
{
beforeSubmit,
handleError,
handleSuccess,
}: {
beforeSubmit?: () => void | boolean;
handleError?: (
error: t.TypeOf<Endpoint['props']['error']>,
form: Form<Endpoint['props']['input']['props']>,
) => void;
handleSuccess?: (
payload: t.TypeOf<Endpoint['props']['payload']>,
form: Form<Endpoint['props']['input']['props']>,
) => void;
},
): Form<Endpoint['props']['input']['props']> => {
const api = useApi();
const endpoint = Api.props[name];
const handleSubmit = useCallback(
(form: Form<Endpoint['props']['input']['props']>) =>
pipe(
form.validated,
either.fold(constVoid, (data) => {
if (form.isDisabled) return;
form.disable();
// any, because we would have to help TypeScript compiler, yolo
api<any, any>(name, data)().then((output) => {
form.enable();
pipe(
output,
either.fold(
(error) => {
if (endpoint.props.inputError.is(error))
// any, because we would have to help TypeScript compiler, yolo
form.setAsyncErrors(error.errors as any);
if (handleError) handleError(error, form);
},
(payload) => {
form.reset();
if (handleSuccess) handleSuccess(payload, form);
},
),
);
});
}),
),
[api, endpoint.props.inputError, handleError, handleSuccess, name],
);
// any, because we would have to help TypeScript compiler, yolo
const form = useForm<any>(endpoint.props.input, initialState, {
beforeSubmit,
handleSubmit,
});
return form;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment