UNPKG

gatsby-plugin-gravity-forms

Version:

A component to take GraphQl Gravity Forms query data and return a usable form.

295 lines (266 loc) 8.23 kB
import classnames from "classnames"; import PropTypes from "prop-types"; import React, { useEffect, useState, useRef } from "react"; import { graphql, navigate } from "gatsby"; import { useMutation } from "@apollo/client"; import { useForm, FormProvider } from "react-hook-form"; import FormGeneralError from "./components/FormGeneralError"; import FieldBuilder from "./container/FieldBuilder"; import { handleGravityFormsValidationErrors, // manageMainFormError, } from "./utils/manageErrors"; import { submissionHasOneFieldEntry, cleanGroupedFields, } from "./utils/manageFormData"; import submitMutation from "./submitMutation"; import formatPayload from "./utils/formatPayload"; import { valueToLowerCase } from "./utils/helpers"; /** * Component to take Gravity Form graphQL data and turn into * a fully functional form. * @param {mixed} data Form dataset from graphQL */ const GravityFormForm = ({ data, presetValues, successCallback, errorCallback, }) => { const preOnSubmit = useRef(); // Split out data depending on how it is passed in. const form = data?.wpGfForm || data; // Deconstruct global settings (if provided). const settings = data?.wp?.gfSettings || {}; const { submitButton, confirmations, databaseId, description, descriptionPlacement, formFields, labelPlacement, subLabelPlacement, title, } = form; const [submitForm, { data: submittionData, loading }] = useMutation( submitMutation ); const hasBeenSubmitted = Boolean(submittionData?.submitGfForm); const haveFieldErrors = Boolean(submittionData?.submitGfForm?.errors?.length); const wasSuccessfullySubmitted = hasBeenSubmitted && !haveFieldErrors; // Pull in form functions const methods = useForm(); const { handleSubmit, setError, reset, getValues, formState: { errors }, } = methods; const [generalError, setGeneralError] = useState(""); const onSubmitCallback = async () => { // Make sure we are not already waiting for a response if (!loading) { // Clean error await preOnSubmit?.current?.recaptcha(); const values = getValues(); // Check that at least one field has been filled in if (submissionHasOneFieldEntry(values)) { setGeneralError(""); const formRes = formatPayload({ serverData: formFields?.nodes, clientData: values, }); submitForm({ variables: { databaseId, fieldValues: formRes, }, }) .then(({ data: { submitGfForm: errors } }) => { // Success if no errors returned. if (!Boolean(errors?.length)) { successCallback({ data: formRes, reset, }); } else { handleGravityFormsValidationErrors(errors, setError); errorCallback({ data: formRes, error: errors, reset, }); } }) .catch((error) => { setGeneralError("unknownError"); errorCallback({ data: formRes, error, reset }); }); } else { setGeneralError("leastOneField"); } } }; if (wasSuccessfullySubmitted) { const confirmation = confirmations?.find((el) => { // First check if there is a custom confirmation // that is not the default. if (el.isActive && !el.isDefault) { return true; } // If not, revert back to the default one. if (el.isDefault) { return true; } }); if (confirmation.type !== "PAGE") { // TODO: Somehow need to get the page URL. Query currently // returns the page ID for the page redirect. navigate(confirmation?.url); } if (confirmation.type !== "REDIRECT") { // TODO: Check that the redirect is internal. // If not, use window.location to direct to external URL. navigate(confirmation?.url); } if (confirmation.type == "MESSAGE") { return ( <div className="gform_confirmation_wrapper"> <div className="gform_confirmation_message" /* eslint-disable react/no-danger */ dangerouslySetInnerHTML={{ __html: confirmation?.message }} /> </div> ); } } return ( <div className="gform_wrapper" id={`gform_wrapper_${databaseId}`}> <div className="gform_anchor" id={`gf_${databaseId}`} /> {formFields && ( <FormProvider {...methods}> <form className={ loading ? `gravityform gravityform--loading gravityform--id-${databaseId}` : `gravityform gravityform--id-${databaseId}` } id={`gform_${databaseId}`} key={`gform_-${databaseId}`} onSubmit={handleSubmit(onSubmitCallback)} > {generalError && <FormGeneralError errorCode={generalError} />} <div className="gform_body"> <ul className={classnames( "gform_fields", { [`form_sublabel_${valueToLowerCase( subLabelPlacement )}`]: valueToLowerCase(subLabelPlacement), }, `description_${valueToLowerCase(descriptionPlacement)}`, `${valueToLowerCase(labelPlacement)}` )} id={`gform_fields_${databaseId}`} > <FieldBuilder databaseId={databaseId} formLoading={loading} formFields={formFields.nodes} labelPlacement={labelPlacement} preOnSubmit={preOnSubmit} presetValues={presetValues} settings={settings} /> </ul> </div> <div className={`gform_footer ${valueToLowerCase(labelPlacement)}`}> <button className="gravityform__button gform_button button" disabled={loading} id={`gform_submit_button_${databaseId}`} type="submit" > {loading ? ( <span className="gravityform__button__loading_span"> Loading </span> ) : ( submitButton?.text )} </button> </div> </form> </FormProvider> )} </div> ); }; GravityFormForm.propTypes = { errorCallback: PropTypes.func, data: PropTypes.object.isRequired, successCallback: PropTypes.func, presetValues: PropTypes.shape({}), }; GravityFormForm.defaultProps = { errorCallback: () => {}, successCallback: () => {}, presetValues: {}, }; export default GravityFormForm; export const GravityFormFields = graphql` fragment GravityFormFields on WpGfForm { databaseId description descriptionPlacement labelPlacement subLabelPlacement title submitButton { ...SubmitButton } confirmations { ...FormConfirmation } formFields { nodes { displayOnly id inputType layoutGridColumnSpan layoutSpacerGridColumnSpan pageNumber type visibility ...CaptchaField ...CheckboxField ...DateField ...EmailField ...HiddenField ...HtmlField ...MultiSelectField ...NumberField ...PhoneField ...RadioField ...SelectField ...TextAreaField ...TextField } } } `; export const GravityFormSettings = graphql` fragment GravityFormSettings on Wp { gfSettings { recaptcha { publicKey type } } } `;