Skip to content

Commit

Permalink
refactor: refactor useMarketoForm to use a state machine
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller committed Sep 26, 2020
1 parent 5be934e commit 578659d
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 49 deletions.
7 changes: 4 additions & 3 deletions src/components/MarketoForm/MarketoForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div
css={css`
position: relative;
Expand All @@ -26,6 +26,7 @@ const MarketoForm = ({
border-radius: 5px;
border: 1px solid var(--border-color);
padding: 1.25rem;
display: ${state === 'formLoaded' ? 'block' : 'none'};
`}
>
<p
Expand All @@ -40,7 +41,7 @@ const MarketoForm = ({
<form id={`mktoForm_${id}`} />
</div>
</div>
) : null;
);
};

MarketoForm.propTypes = {
Expand Down
123 changes: 77 additions & 46 deletions src/hooks/useMarketoForm.js
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 578659d

Please sign in to comment.