From 90f650ce3eb0778e5328727184cecfc81b6a41d5 Mon Sep 17 00:00:00 2001 From: Syed Sajjad Hussain Shah <52817156+syedsajjadkazmii@users.noreply.github.com> Date: Thu, 18 Apr 2024 11:04:28 +0500 Subject: [PATCH] feat: add multi step registration eventing (#1226) * feat: implement multi step registration experiment * feat: add multi step registration eventing --- src/common-components/SocialAuthProviders.jsx | 14 ++++- src/common-components/ThirdPartyAuth.jsx | 4 ++ src/register/RegistrationPage.jsx | 35 +++++++++++- .../data/optimizelyExperiment/track.js | 56 +++++++++++++++++++ ...ltiStepRegistrationExperimentVariation.jsx | 2 + 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 src/register/data/optimizelyExperiment/track.js diff --git a/src/common-components/SocialAuthProviders.jsx b/src/common-components/SocialAuthProviders.jsx index abe06da7..5cdb04e0 100644 --- a/src/common-components/SocialAuthProviders.jsx +++ b/src/common-components/SocialAuthProviders.jsx @@ -9,14 +9,24 @@ import PropTypes from 'prop-types'; import messages from './messages'; import { LOGIN_PAGE, SUPPORTED_ICON_CLASSES } from '../data/constants'; +import { CONTROL, MULTI_STEP_REGISTRATION_EXP_VARIATION } from '../register/data/optimizelyExperiment/helper'; +import { trackMultiStepRegistrationSSOBtnClicked } from '../register/data/optimizelyExperiment/track'; const SocialAuthProviders = (props) => { const { formatMessage } = useIntl(); - const { referrer, socialAuthProviders } = props; + const { + referrer, + socialAuthProviders, + multiStepRegistrationExpVariation, + } = props; function handleSubmit(e) { e.preventDefault(); + if (multiStepRegistrationExpVariation === CONTROL + || multiStepRegistrationExpVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION) { + trackMultiStepRegistrationSSOBtnClicked(multiStepRegistrationExpVariation); + } const url = e.currentTarget.dataset.providerUrl; window.location.href = getConfig().LMS_BASE_URL + url; } @@ -60,6 +70,7 @@ const SocialAuthProviders = (props) => { SocialAuthProviders.defaultProps = { referrer: LOGIN_PAGE, socialAuthProviders: [], + multiStepRegistrationExpVariation: '', }; SocialAuthProviders.propTypes = { @@ -73,6 +84,7 @@ SocialAuthProviders.propTypes = { registerUrl: PropTypes.string, skipRegistrationForm: PropTypes.bool, })), + multiStepRegistrationExpVariation: PropTypes.string, }; export default SocialAuthProviders; diff --git a/src/common-components/ThirdPartyAuth.jsx b/src/common-components/ThirdPartyAuth.jsx index 3b782036..d64615e0 100644 --- a/src/common-components/ThirdPartyAuth.jsx +++ b/src/common-components/ThirdPartyAuth.jsx @@ -32,6 +32,7 @@ const ThirdPartyAuth = (props) => { handleInstitutionLogin, thirdPartyAuthApiStatus, isLoginPage, + multiStepRegistrationExpVariation, } = props; const isInstitutionAuthActive = !!secondaryProviders.length && !currentProvider; const isSocialAuthActive = !!providers.length && !currentProvider; @@ -78,6 +79,7 @@ const ThirdPartyAuth = (props) => { )} @@ -93,6 +95,7 @@ ThirdPartyAuth.defaultProps = { secondaryProviders: [], thirdPartyAuthApiStatus: PENDING_STATE, isLoginPage: false, + multiStepRegistrationExpVariation: '', }; ThirdPartyAuth.propTypes = { @@ -120,6 +123,7 @@ ThirdPartyAuth.propTypes = { ), thirdPartyAuthApiStatus: PropTypes.string, isLoginPage: PropTypes.bool, + multiStepRegistrationExpVariation: PropTypes.string, }; export default ThirdPartyAuth; diff --git a/src/register/RegistrationPage.jsx b/src/register/RegistrationPage.jsx index 70897a31..19b3d774 100644 --- a/src/register/RegistrationPage.jsx +++ b/src/register/RegistrationPage.jsx @@ -34,10 +34,17 @@ import { getRegisterButtonLabelInExperiment, getRegisterButtonSubmitStateInExperiment, MULTI_STEP_REGISTRATION_EXP_VARIATION, - NOT_INITIALIZED, SECOND_STEP, shouldDisplayFieldInExperiment, THIRD_STEP, } from './data/optimizelyExperiment/helper'; +import { + trackMultiStepRegistrationFormSubmitBtnClicked, + trackMultiStepRegistrationStep1SubmitBtnClicked, + trackMultiStepRegistrationStep2SubmitBtnClicked, + trackMultiStepRegistrationStep2Viewed, + trackMultiStepRegistrationStep3SubmitBtnClicked, + trackMultiStepRegistrationStep3Viewed, +} from './data/optimizelyExperiment/track'; import useMultiStepRegistrationExperimentVariation from './data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation'; import getBackendValidations from './data/selectors'; @@ -136,6 +143,17 @@ const RegistrationPage = (props) => { ) { setErrorCode({ type: '', count: 0 }); const nextStep = getMultiStepRegistrationNextStep(multiStepRegistrationPageStep); + if (nextStep === SECOND_STEP) { + trackMultiStepRegistrationStep2Viewed(multiStepRegistrationExpVariation); + if (multiStepRegistrationExpVariation === CONTROL) { + trackMultiStepRegistrationFormSubmitBtnClicked(multiStepRegistrationExpVariation); + } + } else if (nextStep === THIRD_STEP) { + trackMultiStepRegistrationStep3Viewed(); + if (multiStepRegistrationExpVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION) { + trackMultiStepRegistrationFormSubmitBtnClicked(multiStepRegistrationExpVariation); + } + } dispatch(setMultiStepRegistrationExpData(multiStepRegistrationExpVariation, nextStep)); } }, [ // eslint-disable-line react-hooks/exhaustive-deps @@ -215,7 +233,8 @@ const RegistrationPage = (props) => { if (registrationResult.success) { let registeredEventProps = {}; - if (multiStepRegistrationExpVariation !== NOT_INITIALIZED) { + if (multiStepRegistrationExpVariation === CONTROL + || multiStepRegistrationExpVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION) { registeredEventProps = { variation: multiStepRegistrationExpVariation, }; @@ -300,15 +319,25 @@ const RegistrationPage = (props) => { const handleSubmit = (e) => { e.preventDefault(); + if (multiStepRegistrationExpVariation === CONTROL + && multiStepRegistrationPageStep === SECOND_STEP) { + trackMultiStepRegistrationStep2SubmitBtnClicked(multiStepRegistrationExpVariation); + } + if (multiStepRegistrationExpVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION + && multiStepRegistrationPageStep === THIRD_STEP) { + trackMultiStepRegistrationStep3SubmitBtnClicked(); + } if (multiStepRegistrationExpVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION && multiStepRegistrationPageStep !== THIRD_STEP) { let formFieldsPayload = {}; if (multiStepRegistrationPageStep === FIRST_STEP) { + trackMultiStepRegistrationStep1SubmitBtnClicked(multiStepRegistrationExpVariation); // We only want to validate email in the first step of registration // Doing manual validations to avoid the case where user clicks CTA without focusing out of field. formFieldsPayload = { email: formFields.email }; } else if (multiStepRegistrationPageStep === SECOND_STEP) { + trackMultiStepRegistrationStep2SubmitBtnClicked(multiStepRegistrationExpVariation); // We only want to validate name and password field in the second step of registration // Doing manual validations to avoid the case where user clicks CTA without focusing out of field. formFieldsPayload = { name: formFields.name, password: formFields.password }; @@ -328,6 +357,7 @@ const RegistrationPage = (props) => { dispatch(fetchRealtimeValidations(formFieldsPayload, true)); } } else if (multiStepRegistrationExpVariation === CONTROL && multiStepRegistrationPageStep !== SECOND_STEP) { + trackMultiStepRegistrationStep1SubmitBtnClicked(multiStepRegistrationExpVariation); // We only want to validate name, email and password fields in the first step of CONTROL registration // Doing manual validations to avoid the case where user clicks CTA without focusing out of field. const formFieldsPayload = { name: formFields.name, email: formFields.email, password: formFields.password }; @@ -518,6 +548,7 @@ const RegistrationPage = (props) => { secondaryProviders={secondaryProviders} handleInstitutionLogin={handleInstitutionLogin} thirdPartyAuthApiStatus={thirdPartyAuthApiStatus} + multiStepRegistrationExpVariation={multiStepRegistrationExpVariation} /> )} diff --git a/src/register/data/optimizelyExperiment/track.js b/src/register/data/optimizelyExperiment/track.js new file mode 100644 index 00000000..8db71809 --- /dev/null +++ b/src/register/data/optimizelyExperiment/track.js @@ -0,0 +1,56 @@ +import { sendTrackEvent } from '@edx/frontend-platform/analytics'; + +export const eventNames = { + multiStepRegistrationStep1Viewed: 'edx.bi.user.multistepregistration.step1.viewed', + multiStepRegistrationStep2Viewed: 'edx.bi.user.multistepregistration.step2.viewed', + multiStepRegistrationStep3Viewed: 'edx.bi.user.multistepregistration.step3.viewed', + multiStepRegistrationStep1SubmitBtnClicked: 'edx.bi.user.registration.step1.submit.click', + multiStepRegistrationStep2SubmitBtnClicked: 'edx.bi.user.registration.step2.submit.click', + multiStepRegistrationStep3SubmitBtnClicked: 'edx.bi.user.registration.step3.submit.click', + multiStepRegistrationFormSubmitBtnClicked: 'edx.bi.user.registration.form.submit.click', + multiStepRegistrationSSOBtnClicked: 'edx.bi.user.registration.sso.btn.click', +}; + +export const trackMultiStepRegistrationStep1Viewed = (expVariation) => { + sendTrackEvent(eventNames.multiStepRegistrationStep1Viewed, { + variation: expVariation, + }); +}; + +export const trackMultiStepRegistrationStep2Viewed = (expVariation) => { + sendTrackEvent(eventNames.multiStepRegistrationStep2Viewed, { + variation: expVariation, + }); +}; + +export const trackMultiStepRegistrationStep3Viewed = () => { + sendTrackEvent(eventNames.multiStepRegistrationStep3Viewed, {}); +}; + +export const trackMultiStepRegistrationStep1SubmitBtnClicked = (expVariation) => { + sendTrackEvent(eventNames.multiStepRegistrationStep1SubmitBtnClicked, { + variation: expVariation, + }); +}; + +export const trackMultiStepRegistrationStep2SubmitBtnClicked = (expVariation) => { + sendTrackEvent(eventNames.multiStepRegistrationStep2SubmitBtnClicked, { + variation: expVariation, + }); +}; + +export const trackMultiStepRegistrationStep3SubmitBtnClicked = () => { + sendTrackEvent(eventNames.multiStepRegistrationStep3SubmitBtnClicked, {}); +}; + +export const trackMultiStepRegistrationFormSubmitBtnClicked = (expVariation) => { + sendTrackEvent(eventNames.multiStepRegistrationFormSubmitBtnClicked, { + variation: expVariation, + }); +}; + +export const trackMultiStepRegistrationSSOBtnClicked = (expVariation) => { + sendTrackEvent(eventNames.multiStepRegistrationSSOBtnClicked, { + variation: expVariation, + }); +}; diff --git a/src/register/data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation.jsx b/src/register/data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation.jsx index 692101b7..97d0a233 100644 --- a/src/register/data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation.jsx +++ b/src/register/data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation.jsx @@ -5,6 +5,7 @@ import { getMultiStepRegistrationExperimentVariation, NOT_INITIALIZED, } from './helper'; +import { trackMultiStepRegistrationStep1Viewed } from './track'; import { COMPLETE_STATE } from '../../../data/constants'; /** @@ -30,6 +31,7 @@ const useMultiStepRegistrationExperimentVariation = ( const expVariation = getMultiStepRegistrationExperimentVariation(); if (expVariation) { setVariation(expVariation); + trackMultiStepRegistrationStep1Viewed(expVariation); } else { // This is to handle the case when user dont get variation for some reason, the register page // shows unlimited spinner.