Skip to content

Commit

Permalink
Merge pull request #847 from kevinhughes27/mutation-helper
Browse files Browse the repository at this point in the history
Mutation helper
  • Loading branch information
kevinhughes27 authored Sep 9, 2018
2 parents 1fcaa23 + bd7eb50 commit 1c59f4c
Show file tree
Hide file tree
Showing 16 changed files with 359 additions and 243 deletions.
73 changes: 73 additions & 0 deletions clients/admin_next/src/components/Confirm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import * as React from "react";
import Modal from "./Modal";
import FormButtons from "./FormButtons";

let showConfirmFn: (message: string, confirm: () => void) => void;

interface State {
open: boolean;
message: string;
confirm: any;
}

class Confirm extends React.Component<{}, State> {
state = {
open: false,
message: "",
confirm: () => null
};

componentDidMount() {
showConfirmFn = this.handleOpen;
}

handleOpen = (message: string, confirm: () => void) => {
if (message) {
this.setState({
open: true,
message,
confirm
});
}
}

handleClose = () => {
this.setState({
open: false,
message: "",
confirm: () => null,
});
}

submit = () => {
this.state.confirm();
this.handleClose();
}

render() {
return (
<Modal
title="Confirmation Required"
open={this.state.open}
onClose={this.handleClose}
>
<p>
{this.state.message}
</p>
<FormButtons
inline={true}
submitIcon={<span>Confirm</span>}
submit={this.submit}
submitting={false}
cancel={this.handleClose}
/>
</Modal>
);
}
}

export function showConfirm(message: string, confirm: () => void) {
showConfirmFn(message, confirm);
}

export default Confirm;
10 changes: 6 additions & 4 deletions clients/admin_next/src/components/ErrorBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ class Warning extends React.Component<Props, State> {
}

handleShow = (message: string) => {
this.setState({
show: true,
message
});
if (message) {
this.setState({
show: true,
message
});
}
}

handleHide = () => {
Expand Down
43 changes: 35 additions & 8 deletions clients/admin_next/src/components/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from "react";
import Confirm from "./Confirm";
import ErrorBanner, { hideErrors } from "./ErrorBanner";
import { onComplete, onError } from "../helpers/formHelpers";
import runMutation from "../helpers/mutationHelper";
import {
Formik,
FormikProps,
Expand All @@ -19,13 +20,18 @@ class Form<T> extends React.Component<T> {
return errors;
}

submit: any = ({}: FormikValues, {}: FormikActions<FormikValues>) => {
throw new Error("You have to implement submit");
mutation: any = () => {
throw new Error("You have to implement mutation");
}

mutationInput: any = ({}: FormikValues) => {
throw new Error("You have to implement mutationInput");
}

render() {
return (
<div style={{padding: 20}}>
<Confirm />
<ErrorBanner />
<Formik
initialValues={this.initialValues()}
Expand All @@ -43,12 +49,33 @@ class Form<T> extends React.Component<T> {

private onSubmit = (values: FormikValues, actions: FormikActions<FormikValues>) => {
hideErrors();
this.submit(values, actions).then((result: any) => {
onComplete(result, actions);
}, (error: Error | undefined) => {
onError(error);
});

runMutation(
this.mutation(),
this.mutationInput(values),
{
complete: () => {
actions.setSubmitting(false);
actions.resetForm();
},
failed: (result: MutationResult) => {
actions.setSubmitting(false);
setFieldErrors(actions, result.userErrors);
}
}
);
}
}

const setFieldErrors = (
actions: FormikActions<FormikValues>,
userErrors: ReadonlyArray<UserError> | null
) => {
const errors = userErrors || [];

errors.forEach((error) => {
actions.setFieldError(error.field, error.message);
});
};

export default Form;
10 changes: 6 additions & 4 deletions clients/admin_next/src/components/Notice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ class Notice extends React.Component<{}, State> {
}

handleOpen = (message: string) => {
this.setState({
open: true,
message,
});
if (message) {
this.setState({
open: true,
message,
});
}
}

handleClose = () => {
Expand Down
35 changes: 0 additions & 35 deletions clients/admin_next/src/helpers/deleteHelper.ts

This file was deleted.

55 changes: 0 additions & 55 deletions clients/admin_next/src/helpers/formHelpers.ts

This file was deleted.

78 changes: 78 additions & 0 deletions clients/admin_next/src/helpers/mutationHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { showNotice } from "../components/Notice";
import { showConfirm } from "../components/Confirm";
import { showErrors } from "../components/ErrorBanner";
import { merge } from "lodash";

type Mutation = any;

interface MutationInput {
input: any;
}

type MutationCallback = (result: MutationResult) => void;

interface Options {
complete?: MutationCallback;
failed?: MutationCallback;
}

const runMutation = async (
mutation: Mutation,
input: MutationInput,
options: Options = {}
) => {
try {
const result = await mutation.commit(input);

if (result.success) {
mutationSuccess(result, options.complete);
} else if (result.confirm) {
showConfirm(result.message, confirmMutation(mutation, input, options));
} else {
mutationFailed(result, options.failed);
}

} catch (error) {
mutationError(error, options.failed);
}
};

const confirmMutation = (
mutation: Mutation,
input: MutationInput,
options: Options = {}
) => {
return () => {
const confirmedInput = merge({}, {...input}, {input: {confirm: true}});
runMutation(mutation, confirmedInput, options);
};
};

const mutationSuccess = (result: MutationResult, complete?: MutationCallback) => {
showNotice(result.message);
if (complete) { complete(result); }
};

const mutationFailed = (result: MutationResult, failed?: MutationCallback) => {
/*
* Try and show page errors if possible
* otherwise fallback to notice.
*/
try {
showErrors(result.message);
} catch (error) {
showNotice(result.message);
}

if (failed) { failed(result); }
};

const mutationError = (error: Error, failed?: MutationCallback) => {
const message = error.message || "Something went wrong.";
const result = {success: false, message, userErrors: []};

showErrors(message);
if (failed) { failed(result); }
};

export default runMutation;
Loading

0 comments on commit 1c59f4c

Please sign in to comment.