From 578659d99d395887c99f8927b5c370a5ef5df4a9 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 25 Sep 2020 17:18:27 -0700 Subject: [PATCH] refactor: refactor useMarketoForm to use a state machine --- src/components/MarketoForm/MarketoForm.js | 7 +- src/hooks/useMarketoForm.js | 123 ++++++++++++++-------- 2 files changed, 81 insertions(+), 49 deletions(-) diff --git a/src/components/MarketoForm/MarketoForm.js b/src/components/MarketoForm/MarketoForm.js index a59f293c7..da90610f3 100644 --- a/src/components/MarketoForm/MarketoForm.js +++ b/src/components/MarketoForm/MarketoForm.js @@ -11,9 +11,9 @@ const MarketoForm = ({ publishableKey, redirectLink, }) => { - const loaded = useMarketoForm(munchkinId, id, publishableKey, redirectLink); + const [state] = useMarketoForm(munchkinId, id, publishableKey, redirectLink); - return loaded ? ( + return (

- ) : null; + ); }; MarketoForm.propTypes = { diff --git a/src/hooks/useMarketoForm.js b/src/hooks/useMarketoForm.js index b44cd0c19..ca6ec3f1c 100644 --- a/src/hooks/useMarketoForm.js +++ b/src/hooks/useMarketoForm.js @@ -1,57 +1,88 @@ -import { useEffect, useState } from 'react'; import { navigate } from 'gatsby'; +import { assign, Machine } from 'xstate'; +import { asEffect, useMachine } from '@xstate/react'; +import useScript from './useScript'; -const useMarketoForm = (munchkinId, id, publishableKey, redirectLink) => { - const [loaded, setLoaded] = useState(false); - - useEffect(() => { - if (!window.MktoForms2) { - return; - } - setLoaded(true); +const machine = Machine({ + id: 'marketo', + initial: 'loading', + context: { + form: null, + error: null, + }, + states: { + loading: { + on: { LOADED: 'scriptLoaded', LOAD_ERROR: 'error', BLOCKED: 'blocked' }, + }, + scriptLoaded: { + entry: ['loadForm'], + on: { + FORM_LOADED: { + target: 'formLoaded', + actions: assign({ form: (_context, event) => event.form }), + }, + BLOCKED: 'blocked', + }, + }, + formLoaded: { + type: 'final', + entry: ['defineFormActions'], + }, + blocked: { + type: 'final', + entry: assign({ + error: + 'Unable to load the script. Perhaps this was due to an ad blocker.', + }), + }, + error: { + type: 'final', + entry: assign({ error: 'Unable to load the script.' }), + }, + }, +}); - window.MktoForms2.loadForm( - '//app-abj.marketo.com', - munchkinId, - id, - (form) => { - // eslint-disable-next-line no-unused-vars - form.onSuccess(function (values, followUpUrl) { +const useMarketoForm = (munchkinId, id, publishableKey, redirectLink) => { + const [state, send] = useMachine(machine, { + actions: { + loadForm: asEffect(() => { + window.MktoForms2.loadForm( + '//app-abj.marketo.com', + munchkinId, + id, + (form) => send({ type: 'FORM_LOADED', form }) + ); + }), + defineFormActions: asEffect(({ form }) => { + form.onSuccess(() => { navigate(redirectLink); + + // prevent the default behavior of redirecting via marketo to another + // page. We want to control the navigation ourselves. + // https://developers.marketo.com/javascript-api/forms/api-reference/ + return false; }); - } - ); + }), + }, + }); - const pollForDefinition = (scope, varname, callback) => { - if (typeof scope[varname] !== 'undefined') { - return callback(); + useScript('https://marketo.clearbit.com/assets/v1/marketo/forms.js', { + attributes: { 'data-clearbit-publishable-key': publishableKey }, + onError: () => send('LOAD_ERROR'), + onLoad: () => { + if (window.MktoForms2) { + send('LOADED'); + } else { + // Some ad blockers block the marketo script from loading. In this case, + // we won't have the MktoForms2 variable available on window. We need + // to prevent the rest of the script from running to avoid triggering + // errors on the page that would cause the page to go blank. + send('BLOCKED'); } - const interval = setInterval(() => { - if (typeof scope[varname] !== 'undefined') { - clearInterval(interval); - callback(); - } - }, 250); - }; - const script = document.createElement('script'); - script.src = 'https://marketo.clearbit.com/assets/v1/marketo/forms.js'; - script.async = true; - script.setAttribute('data-clearbit-publishable-key', publishableKey); - script.onerror = () => { - // eslint-disable-next-line no-console - console.log('Clearbit Form JS unable to load'); - pollForDefinition(window, 'MktoForms2', () => { - window.MktoForms2.whenReady((form) => { - form.setValues({ - clearbitFormStatus: 'Clearbit Form JS unable to load', - }); - }); - }); - }; - document.body.append(script); - }, [munchkinId, id, publishableKey, redirectLink]); + }, + }); - return loaded; + return [state.value, state.context]; }; export default useMarketoForm;