revert: multistep registration experiment
revert multistep registration experiment changes VAN-1930
This commit is contained in:
committed by
Mubbshar Anwar
parent
03d1666c2c
commit
d8947a4c0a
@@ -9,24 +9,14 @@ 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,
|
||||
multiStepRegistrationExpVariation,
|
||||
} = props;
|
||||
const { referrer, socialAuthProviders } = 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;
|
||||
}
|
||||
@@ -70,7 +60,6 @@ const SocialAuthProviders = (props) => {
|
||||
SocialAuthProviders.defaultProps = {
|
||||
referrer: LOGIN_PAGE,
|
||||
socialAuthProviders: [],
|
||||
multiStepRegistrationExpVariation: '',
|
||||
};
|
||||
|
||||
SocialAuthProviders.propTypes = {
|
||||
@@ -84,7 +73,6 @@ SocialAuthProviders.propTypes = {
|
||||
registerUrl: PropTypes.string,
|
||||
skipRegistrationForm: PropTypes.bool,
|
||||
})),
|
||||
multiStepRegistrationExpVariation: PropTypes.string,
|
||||
};
|
||||
|
||||
export default SocialAuthProviders;
|
||||
|
||||
@@ -32,7 +32,6 @@ const ThirdPartyAuth = (props) => {
|
||||
handleInstitutionLogin,
|
||||
thirdPartyAuthApiStatus,
|
||||
isLoginPage,
|
||||
multiStepRegistrationExpVariation,
|
||||
} = props;
|
||||
const isInstitutionAuthActive = !!secondaryProviders.length && !currentProvider;
|
||||
const isSocialAuthActive = !!providers.length && !currentProvider;
|
||||
@@ -79,7 +78,6 @@ const ThirdPartyAuth = (props) => {
|
||||
<SocialAuthProviders
|
||||
socialAuthProviders={providers}
|
||||
referrer={isLoginPage ? LOGIN_PAGE : REGISTER_PAGE}
|
||||
multiStepRegistrationExpVariation={multiStepRegistrationExpVariation}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -95,7 +93,6 @@ ThirdPartyAuth.defaultProps = {
|
||||
secondaryProviders: [],
|
||||
thirdPartyAuthApiStatus: PENDING_STATE,
|
||||
isLoginPage: false,
|
||||
multiStepRegistrationExpVariation: '',
|
||||
};
|
||||
|
||||
ThirdPartyAuth.propTypes = {
|
||||
@@ -123,7 +120,6 @@ ThirdPartyAuth.propTypes = {
|
||||
),
|
||||
thirdPartyAuthApiStatus: PropTypes.string,
|
||||
isLoginPage: PropTypes.bool,
|
||||
multiStepRegistrationExpVariation: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ThirdPartyAuth;
|
||||
|
||||
@@ -132,12 +132,6 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Company or school credentials',
|
||||
description: 'Company or school login link text.',
|
||||
},
|
||||
// multi step registration experiment messages
|
||||
'tab.back.btn.text': {
|
||||
id: 'tab.back.btn.text',
|
||||
defaultMessage: 'Back',
|
||||
description: 'Tab back button text',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
|
||||
@@ -34,8 +34,6 @@ const configuration = {
|
||||
ZENDESK_LOGO_URL: process.env.ZENDESK_LOGO_URL,
|
||||
ALGOLIA_APP_ID: process.env.ALGOLIA_APP_ID || '',
|
||||
ALGOLIA_SEARCH_API_KEY: process.env.ALGOLIA_SEARCH_API_KEY || '',
|
||||
// Multi Step Registration Experiment
|
||||
MULTI_STEP_REGISTRATION_EXPERIMENT_ID: process.env.MULTI_STEP_REGISTRATION_EXPERIMENT_ID || '',
|
||||
};
|
||||
|
||||
export default configuration;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { connect, useDispatch, useSelector } from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
@@ -7,11 +7,10 @@ import { getAuthService } from '@edx/frontend-platform/auth';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Icon,
|
||||
IconButton,
|
||||
Tab,
|
||||
Tabs,
|
||||
} from '@openedx/paragon';
|
||||
import { ArrowBackIos, ChevronLeft } from '@openedx/paragon/icons';
|
||||
import { ChevronLeft } from '@openedx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Navigate, useNavigate } from 'react-router-dom';
|
||||
|
||||
@@ -28,11 +27,7 @@ import {
|
||||
import { LoginPage } from '../login';
|
||||
import { backupLoginForm } from '../login/data/actions';
|
||||
import { RegistrationPage } from '../register';
|
||||
import { backupRegistrationForm, setMultiStepRegistrationExpData } from '../register/data/actions';
|
||||
import {
|
||||
FIRST_STEP,
|
||||
getMultiStepRegistrationPreviousStep,
|
||||
} from '../register/data/optimizelyExperiment/helper';
|
||||
import { backupRegistrationForm } from '../register/data/actions';
|
||||
|
||||
const Logistration = (props) => {
|
||||
const { selectedPage, tpaProviders } = props;
|
||||
@@ -47,10 +42,6 @@ const Logistration = (props) => {
|
||||
const disablePublicAccountCreation = getConfig().ALLOW_PUBLIC_ACCOUNT_CREATION === false;
|
||||
const hideRegistrationLink = getConfig().SHOW_REGISTRATION_LINKS === false;
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const multiStepRegExpVariation = useSelector(state => state.register.multiStepRegExpVariation);
|
||||
const multiStepRegistrationPageStep = useSelector(state => state.register.multiStepRegistrationPageStep);
|
||||
|
||||
useEffect(() => {
|
||||
const authService = getAuthService();
|
||||
if (authService) {
|
||||
@@ -100,39 +91,6 @@ const Logistration = (props) => {
|
||||
</div>
|
||||
);
|
||||
|
||||
/**
|
||||
* Temporary function created to resolve the complexity in tabs conditioning for multi-step
|
||||
* registration experiment
|
||||
*/
|
||||
const getTabs = () => {
|
||||
if (multiStepRegistrationPageStep !== FIRST_STEP) {
|
||||
const prevStep = getMultiStepRegistrationPreviousStep(multiStepRegistrationPageStep);
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
key="primary"
|
||||
src={ArrowBackIos}
|
||||
iconAs={Icon}
|
||||
alt="Back"
|
||||
onClick={() => {
|
||||
dispatch(setMultiStepRegistrationExpData(multiStepRegExpVariation, prevStep));
|
||||
}}
|
||||
variant="primary"
|
||||
size="inline"
|
||||
className="mr-1"
|
||||
/>
|
||||
{formatMessage(messages['tab.back.btn.text'])}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Tabs defaultActiveKey={selectedPage} id="controlled-tab" onSelect={(tabKey) => handleOnSelect(tabKey, selectedPage)}>
|
||||
<Tab title={formatMessage(messages['logistration.register'])} eventKey={REGISTER_PAGE} />
|
||||
<Tab title={formatMessage(messages['logistration.sign.in'])} eventKey={LOGIN_PAGE} />
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
const isValidTpaHint = () => {
|
||||
const { provider } = getTpaProvider(tpaHint, providers, secondaryProviders);
|
||||
return !!provider;
|
||||
@@ -165,7 +123,12 @@ const Logistration = (props) => {
|
||||
<Tab title={tabTitle} eventKey={selectedPage === LOGIN_PAGE ? LOGIN_PAGE : REGISTER_PAGE} />
|
||||
</Tabs>
|
||||
)
|
||||
: (!isValidTpaHint() && !hideRegistrationLink && getTabs())}
|
||||
: (!isValidTpaHint() && !hideRegistrationLink && (
|
||||
<Tabs defaultActiveKey={selectedPage} id="controlled-tab" onSelect={(tabKey) => handleOnSelect(tabKey, selectedPage)}>
|
||||
<Tab title={formatMessage(messages['logistration.register'])} eventKey={REGISTER_PAGE} />
|
||||
<Tab title={formatMessage(messages['logistration.sign.in'])} eventKey={LOGIN_PAGE} />
|
||||
</Tabs>
|
||||
))}
|
||||
{ key && (
|
||||
<Navigate to={updatePathWithQueryParams(key)} replace />
|
||||
)}
|
||||
|
||||
@@ -15,16 +15,12 @@ import {
|
||||
} from '../data/constants';
|
||||
import { backupLoginForm } from '../login/data/actions';
|
||||
import { backupRegistrationForm } from '../register/data/actions';
|
||||
import { FIRST_STEP, NOT_INITIALIZED } from '../register/data/optimizelyExperiment/helper';
|
||||
import useMultiStepRegistrationExperimentVariation
|
||||
from '../register/data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation';
|
||||
|
||||
jest.mock('@edx/frontend-platform/analytics', () => ({
|
||||
sendPageEvent: jest.fn(),
|
||||
sendTrackEvent: jest.fn(),
|
||||
}));
|
||||
jest.mock('@edx/frontend-platform/auth');
|
||||
jest.mock('../register/data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation', () => jest.fn());
|
||||
|
||||
const mockStore = configureStore();
|
||||
const IntlLogistration = injectIntl(Logistration);
|
||||
@@ -67,8 +63,6 @@ describe('Logistration', () => {
|
||||
registrationError: {},
|
||||
usernameSuggestions: [],
|
||||
validationApiRateLimited: false,
|
||||
multiStepRegExpVariation: '',
|
||||
multiStepRegistrationPageStep: FIRST_STEP,
|
||||
},
|
||||
commonComponents: {
|
||||
thirdPartyAuthContext: {
|
||||
@@ -89,7 +83,6 @@ describe('Logistration', () => {
|
||||
username: 'test-user',
|
||||
})),
|
||||
}));
|
||||
useMultiStepRegistrationExperimentVariation.mockReturnValue(NOT_INITIALIZED);
|
||||
|
||||
configure({
|
||||
loggingService: { logError: jest.fn() },
|
||||
|
||||
@@ -17,37 +17,14 @@ import RegistrationFailure from './components/RegistrationFailure';
|
||||
import {
|
||||
backupRegistrationFormBegin,
|
||||
clearRegistrationBackendError,
|
||||
fetchRealtimeValidations,
|
||||
registerNewUser,
|
||||
setEmailSuggestionInStore,
|
||||
setMultiStepRegistrationExpData,
|
||||
setUserPipelineDataLoaded,
|
||||
} from './data/actions';
|
||||
import {
|
||||
FORM_SUBMISSION_ERROR,
|
||||
TPA_AUTHENTICATION_FAILURE,
|
||||
} from './data/constants';
|
||||
import {
|
||||
CONTROL,
|
||||
FIRST_STEP,
|
||||
getMultiStepRegistrationNextStep,
|
||||
getRegisterButtonClassInExperiment,
|
||||
getRegisterButtonLabelInExperiment,
|
||||
getRegisterButtonSubmitStateInExperiment,
|
||||
MULTI_STEP_REGISTRATION_EXP_VARIATION,
|
||||
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';
|
||||
import {
|
||||
isFormValid, prepareRegistrationPayload,
|
||||
@@ -96,13 +73,6 @@ const RegistrationPage = (props) => {
|
||||
const shouldBackupState = useSelector(state => state.register.shouldBackupState);
|
||||
const userPipelineDataLoaded = useSelector(state => state.register.userPipelineDataLoaded);
|
||||
const submitState = useSelector(state => state.register.submitState);
|
||||
const backendValidations = useSelector(getBackendValidations);
|
||||
const multiStepRegExpVariation = useSelector(state => state.register.multiStepRegExpVariation);
|
||||
const multiStepRegistrationPageStep = useSelector(state => state.register.multiStepRegistrationPageStep);
|
||||
const isValidatingMultiStepRegistrationPage = useSelector(
|
||||
state => state.register.isValidatingMultiStepRegistrationPage,
|
||||
);
|
||||
const validationsSubmitState = useSelector(state => state.register.validationsSubmitState);
|
||||
|
||||
const fieldDescriptions = useSelector(state => state.commonComponents.fieldDescriptions);
|
||||
const optionalFields = useSelector(state => state.commonComponents.optionalFields);
|
||||
@@ -115,6 +85,7 @@ const RegistrationPage = (props) => {
|
||||
const secondaryProviders = useSelector(state => state.commonComponents.thirdPartyAuthContext.secondaryProviders);
|
||||
const pipelineUserDetails = useSelector(state => state.commonComponents.thirdPartyAuthContext.pipelineUserDetails);
|
||||
|
||||
const backendValidations = useSelector(getBackendValidations);
|
||||
const queryParams = useMemo(() => getAllPossibleQueryParams(), []);
|
||||
const tpaHint = useMemo(() => getTpaHint(), []);
|
||||
|
||||
@@ -131,38 +102,6 @@ const RegistrationPage = (props) => {
|
||||
? formatMessage(messages['create.account.cta.button'], { label: cta })
|
||||
: formatMessage(messages['create.account.for.free.button']);
|
||||
|
||||
/**
|
||||
* Multi-Step Registration Page Experiment
|
||||
*/
|
||||
const multiStepRegistrationExpVariation = useMultiStepRegistrationExperimentVariation(
|
||||
multiStepRegExpVariation, registrationEmbedded, tpaHint, currentProvider, thirdPartyAuthApiStatus,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isValidatingMultiStepRegistrationPage && backendValidations
|
||||
&& Object.values(backendValidations).every(value => value === '')
|
||||
) {
|
||||
setErrorCode({ type: '', count: 0 });
|
||||
const nextStep = getMultiStepRegistrationNextStep(multiStepRegistrationPageStep);
|
||||
if (nextStep === SECOND_STEP) {
|
||||
const isMarketingLead = formFields.email && configurableFormFields?.marketingEmailsOptIn;
|
||||
trackMultiStepRegistrationStep2Viewed(multiStepRegistrationExpVariation, isMarketingLead);
|
||||
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
|
||||
isValidatingMultiStepRegistrationPage,
|
||||
backendValidations,
|
||||
]);
|
||||
|
||||
/**
|
||||
* Set the userPipelineDetails data in formFields for only first time
|
||||
*/
|
||||
@@ -209,11 +148,8 @@ const RegistrationPage = (props) => {
|
||||
formFields: { ...formFields },
|
||||
errors: { ...errors },
|
||||
}));
|
||||
dispatch(setMultiStepRegistrationExpData(
|
||||
multiStepRegistrationExpVariation, multiStepRegistrationPageStep, false,
|
||||
));
|
||||
}
|
||||
}, [shouldBackupState]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}, [shouldBackupState, configurableFormFields, formFields, errors, dispatch, backedUpFormData]);
|
||||
|
||||
useEffect(() => {
|
||||
if (backendValidations) {
|
||||
@@ -233,22 +169,13 @@ const RegistrationPage = (props) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (registrationResult.success) {
|
||||
let registeredEventProps = {};
|
||||
|
||||
if (multiStepRegistrationExpVariation === CONTROL
|
||||
|| multiStepRegistrationExpVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION) {
|
||||
registeredEventProps = {
|
||||
variation: multiStepRegistrationExpVariation,
|
||||
};
|
||||
}
|
||||
|
||||
// This event is used by GTM
|
||||
sendTrackEvent('edx.bi.user.account.registered.client', registeredEventProps);
|
||||
sendTrackEvent('edx.bi.user.account.registered.client', {});
|
||||
|
||||
// This is used by the "User Retention Rate Event" on GTM
|
||||
setCookie(getConfig().USER_RETENTION_COOKIE_NAME, true);
|
||||
}
|
||||
}, [registrationResult]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}, [registrationResult]);
|
||||
|
||||
const handleOnChange = (event) => {
|
||||
const { name } = event.target;
|
||||
@@ -320,67 +247,7 @@ 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 };
|
||||
}
|
||||
|
||||
const { isValid, fieldErrors } = isFormValid(
|
||||
formFieldsPayload, errors, {}, {}, formatMessage,
|
||||
);
|
||||
setErrors(prevErrors => ({
|
||||
...prevErrors,
|
||||
...fieldErrors,
|
||||
}));
|
||||
// returning if not valid
|
||||
if (!isValid) {
|
||||
setErrorCode(prevState => ({ type: FORM_SUBMISSION_ERROR, count: prevState.count + 1 }));
|
||||
} else {
|
||||
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 };
|
||||
|
||||
const { isValid, fieldErrors } = isFormValid(
|
||||
formFieldsPayload, errors, {}, {}, formatMessage,
|
||||
);
|
||||
|
||||
setErrors(prevErrors => ({
|
||||
...prevErrors,
|
||||
...fieldErrors,
|
||||
}));
|
||||
// returning if not valid
|
||||
if (!isValid) {
|
||||
setErrorCode(prevState => ({ type: FORM_SUBMISSION_ERROR, count: prevState.count + 1 }));
|
||||
} else {
|
||||
dispatch(fetchRealtimeValidations(formFieldsPayload, true));
|
||||
}
|
||||
} else {
|
||||
registerUser();
|
||||
}
|
||||
registerUser();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -415,150 +282,104 @@ const RegistrationPage = (props) => {
|
||||
getConfig().ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN && !!Object.keys(optionalFields.fields).length
|
||||
}
|
||||
/>
|
||||
{(autoSubmitRegForm && !errorCode.type)
|
||||
|| (!multiStepRegistrationExpVariation && !(registrationEmbedded || !!tpaHint || !!currentProvider))
|
||||
? (
|
||||
<div className="mw-xs mt-5 text-center">
|
||||
<Spinner animation="border" variant="primary" id="tpa-spinner" />
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={classNames(
|
||||
'mw-xs mt-3',
|
||||
{ 'w-100 m-auto pt-4 main-content': registrationEmbedded },
|
||||
{autoSubmitRegForm && !errorCode.type ? (
|
||||
<div className="mw-xs mt-5 text-center">
|
||||
<Spinner animation="border" variant="primary" id="tpa-spinner" />
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={classNames(
|
||||
'mw-xs mt-3',
|
||||
{ 'w-100 m-auto pt-4 main-content': registrationEmbedded },
|
||||
)}
|
||||
>
|
||||
<ThirdPartyAuthAlert
|
||||
currentProvider={currentProvider}
|
||||
platformName={platformName}
|
||||
referrer={REGISTER_PAGE}
|
||||
/>
|
||||
<RegistrationFailure
|
||||
errorCode={errorCode.type}
|
||||
failureCount={errorCode.count}
|
||||
context={{ provider: currentProvider, errorMessage: thirdPartyAuthErrorMessage }}
|
||||
/>
|
||||
<Form id="registration-form" name="registration-form">
|
||||
<NameField
|
||||
name="name"
|
||||
value={formFields.name}
|
||||
shouldFetchUsernameSuggestions={!formFields.username.trim()}
|
||||
handleChange={handleOnChange}
|
||||
handleErrorChange={handleErrorChange}
|
||||
errorMessage={errors.name}
|
||||
helpText={[formatMessage(messages['help.text.name'])]}
|
||||
floatingLabel={formatMessage(messages['registration.fullname.label'])}
|
||||
/>
|
||||
<EmailField
|
||||
name="email"
|
||||
value={formFields.email}
|
||||
confirmEmailValue={configurableFormFields?.confirm_email}
|
||||
handleErrorChange={handleErrorChange}
|
||||
handleChange={handleOnChange}
|
||||
errorMessage={errors.email}
|
||||
helpText={[formatMessage(messages['help.text.email'])]}
|
||||
floatingLabel={formatMessage(messages['registration.email.label'])}
|
||||
/>
|
||||
<UsernameField
|
||||
name="username"
|
||||
spellCheck="false"
|
||||
value={formFields.username}
|
||||
handleChange={handleOnChange}
|
||||
handleErrorChange={handleErrorChange}
|
||||
errorMessage={errors.username}
|
||||
helpText={[formatMessage(messages['help.text.username.1']), formatMessage(messages['help.text.username.2'])]}
|
||||
floatingLabel={formatMessage(messages['registration.username.label'])}
|
||||
/>
|
||||
{!currentProvider && (
|
||||
<PasswordField
|
||||
name="password"
|
||||
value={formFields.password}
|
||||
handleChange={handleOnChange}
|
||||
handleErrorChange={handleErrorChange}
|
||||
errorMessage={errors.password}
|
||||
floatingLabel={formatMessage(messages['registration.password.label'])}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
<ThirdPartyAuthAlert
|
||||
currentProvider={currentProvider}
|
||||
platformName={platformName}
|
||||
referrer={REGISTER_PAGE}
|
||||
<ConfigurableRegistrationForm
|
||||
email={formFields.email}
|
||||
fieldErrors={errors}
|
||||
formFields={configurableFormFields}
|
||||
setFieldErrors={registrationEmbedded ? setTemporaryErrors : setErrors}
|
||||
setFormFields={setConfigurableFormFields}
|
||||
autoSubmitRegisterForm={autoSubmitRegForm}
|
||||
fieldDescriptions={fieldDescriptions}
|
||||
/>
|
||||
<RegistrationFailure
|
||||
errorCode={errorCode.type}
|
||||
failureCount={errorCode.count}
|
||||
context={{ provider: currentProvider, errorMessage: thirdPartyAuthErrorMessage }}
|
||||
multiStepRegistrationPageStep={multiStepRegistrationPageStep}
|
||||
<StatefulButton
|
||||
id="register-user"
|
||||
name="register-user"
|
||||
type="submit"
|
||||
variant="brand"
|
||||
className="register-button mt-4 mb-4"
|
||||
state={submitState}
|
||||
labels={{
|
||||
default: buttonLabel,
|
||||
pending: '',
|
||||
}}
|
||||
onClick={handleSubmit}
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
/>
|
||||
<Form id="registration-form" name="registration-form">
|
||||
{(multiStepRegistrationExpVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION
|
||||
&& multiStepRegistrationPageStep === SECOND_STEP) && (
|
||||
<p className="h3 mb-4">
|
||||
{formatMessage(messages['multistep.registration.username.second.step.guideline.content'])}
|
||||
</p>
|
||||
)}
|
||||
{((multiStepRegistrationExpVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION
|
||||
&& multiStepRegistrationPageStep === THIRD_STEP)
|
||||
|| (multiStepRegistrationExpVariation === CONTROL && multiStepRegistrationPageStep === SECOND_STEP))
|
||||
&& (
|
||||
<p className="small mb-4">
|
||||
{formatMessage(messages['multistep.registration.username.third.step.guideline.content'])}
|
||||
</p>
|
||||
)}
|
||||
{shouldDisplayFieldInExperiment(
|
||||
'name', multiStepRegistrationExpVariation, multiStepRegistrationPageStep,
|
||||
) && (
|
||||
<NameField
|
||||
name="name"
|
||||
value={formFields.name}
|
||||
shouldFetchUsernameSuggestions={!formFields.username.trim()}
|
||||
handleChange={handleOnChange}
|
||||
handleErrorChange={handleErrorChange}
|
||||
errorMessage={errors.name}
|
||||
helpText={[formatMessage(messages['help.text.name'])]}
|
||||
floatingLabel={formatMessage(messages['registration.fullname.label'])}
|
||||
/>
|
||||
)}
|
||||
{shouldDisplayFieldInExperiment(
|
||||
'email', multiStepRegistrationExpVariation, multiStepRegistrationPageStep,
|
||||
) && (
|
||||
<EmailField
|
||||
name="email"
|
||||
value={formFields.email}
|
||||
confirmEmailValue={configurableFormFields?.confirm_email}
|
||||
handleErrorChange={handleErrorChange}
|
||||
handleChange={handleOnChange}
|
||||
errorMessage={errors.email}
|
||||
helpText={[formatMessage(messages['help.text.email'])]}
|
||||
floatingLabel={formatMessage(messages['registration.email.label'])}
|
||||
/>
|
||||
)}
|
||||
{shouldDisplayFieldInExperiment(
|
||||
'username', multiStepRegistrationExpVariation, multiStepRegistrationPageStep,
|
||||
) && (
|
||||
<UsernameField
|
||||
name="username"
|
||||
spellCheck="false"
|
||||
value={formFields.username}
|
||||
handleChange={handleOnChange}
|
||||
handleErrorChange={handleErrorChange}
|
||||
errorMessage={errors.username}
|
||||
helpText={[formatMessage(messages['help.text.username.1']), formatMessage(messages['help.text.username.2'])]}
|
||||
floatingLabel={formatMessage(messages['registration.username.label'])}
|
||||
/>
|
||||
)}
|
||||
{!currentProvider && shouldDisplayFieldInExperiment(
|
||||
'password', multiStepRegistrationExpVariation, multiStepRegistrationPageStep,
|
||||
) && (
|
||||
<PasswordField
|
||||
name="password"
|
||||
value={formFields.password}
|
||||
handleChange={handleOnChange}
|
||||
handleErrorChange={handleErrorChange}
|
||||
errorMessage={errors.password}
|
||||
floatingLabel={formatMessage(messages['registration.password.label'])}
|
||||
/>
|
||||
)}
|
||||
<ConfigurableRegistrationForm
|
||||
email={formFields.email}
|
||||
fieldErrors={errors}
|
||||
formFields={configurableFormFields}
|
||||
setFieldErrors={registrationEmbedded ? setTemporaryErrors : setErrors}
|
||||
setFormFields={setConfigurableFormFields}
|
||||
autoSubmitRegisterForm={autoSubmitRegForm}
|
||||
fieldDescriptions={fieldDescriptions}
|
||||
multiStepRegistrationExpVariation={multiStepRegistrationExpVariation}
|
||||
multiStepRegistrationPageStep={multiStepRegistrationPageStep}
|
||||
{!registrationEmbedded && (
|
||||
<ThirdPartyAuth
|
||||
currentProvider={currentProvider}
|
||||
providers={providers}
|
||||
secondaryProviders={secondaryProviders}
|
||||
handleInstitutionLogin={handleInstitutionLogin}
|
||||
thirdPartyAuthApiStatus={thirdPartyAuthApiStatus}
|
||||
/>
|
||||
<StatefulButton
|
||||
id="register-user"
|
||||
name="register-user"
|
||||
type="submit"
|
||||
variant="brand"
|
||||
className={`
|
||||
mt-4 mb-4
|
||||
${getRegisterButtonClassInExperiment(multiStepRegistrationExpVariation, multiStepRegistrationPageStep)}
|
||||
`}
|
||||
state={getRegisterButtonSubmitStateInExperiment(
|
||||
submitState,
|
||||
validationsSubmitState,
|
||||
multiStepRegistrationExpVariation,
|
||||
multiStepRegistrationPageStep,
|
||||
)}
|
||||
labels={{
|
||||
default: getRegisterButtonLabelInExperiment(
|
||||
buttonLabel, multiStepRegistrationExpVariation, multiStepRegistrationPageStep, formatMessage,
|
||||
),
|
||||
pending: '',
|
||||
}}
|
||||
onClick={handleSubmit}
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
/>
|
||||
{(!registrationEmbedded && shouldDisplayFieldInExperiment(
|
||||
'ThirdPartyAuth', multiStepRegistrationExpVariation, multiStepRegistrationPageStep,
|
||||
))
|
||||
&& (
|
||||
<ThirdPartyAuth
|
||||
currentProvider={currentProvider}
|
||||
providers={providers}
|
||||
secondaryProviders={secondaryProviders}
|
||||
handleInstitutionLogin={handleInstitutionLogin}
|
||||
thirdPartyAuthApiStatus={thirdPartyAuthApiStatus}
|
||||
multiStepRegistrationExpVariation={multiStepRegistrationExpVariation}
|
||||
/>
|
||||
)}
|
||||
</Form>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</Form>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,9 +17,6 @@ import {
|
||||
setUserPipelineDataLoaded,
|
||||
} from './data/actions';
|
||||
import { INTERNAL_SERVER_ERROR } from './data/constants';
|
||||
import { NOT_INITIALIZED } from './data/optimizelyExperiment/helper';
|
||||
import useMultiStepRegistrationExperimentVariation
|
||||
from './data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation';
|
||||
import RegistrationPage from './RegistrationPage';
|
||||
import {
|
||||
AUTHN_PROGRESSIVE_PROFILING, COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
|
||||
@@ -33,7 +30,6 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
...jest.requireActual('@edx/frontend-platform/i18n'),
|
||||
getLocale: jest.fn(),
|
||||
}));
|
||||
jest.mock('./data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation', () => jest.fn());
|
||||
|
||||
const IntlRegistrationPage = injectIntl(RegistrationPage);
|
||||
const mockStore = configureStore();
|
||||
@@ -132,7 +128,6 @@ describe('RegistrationPage', () => {
|
||||
institutionLogin: false,
|
||||
};
|
||||
window.location = { search: '' };
|
||||
useMultiStepRegistrationExperimentVariation.mockReturnValue(NOT_INITIALIZED);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -6,7 +6,6 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import { FormFieldRenderer } from '../../field-renderer';
|
||||
import { FIELDS } from '../data/constants';
|
||||
import { FIRST_STEP, shouldDisplayFieldInExperiment } from '../data/optimizelyExperiment/helper';
|
||||
import messages from '../messages';
|
||||
import { CountryField, HonorCode, TermsOfService } from '../RegistrationFields';
|
||||
|
||||
@@ -32,8 +31,6 @@ const ConfigurableRegistrationForm = (props) => {
|
||||
setFieldErrors,
|
||||
setFormFields,
|
||||
autoSubmitRegistrationForm,
|
||||
multiStepRegistrationExpVariation,
|
||||
multiStepRegistrationPageStep,
|
||||
} = props;
|
||||
|
||||
const countryList = useMemo(() => getCountryList(getLocale()), []);
|
||||
@@ -108,9 +105,7 @@ const ConfigurableRegistrationForm = (props) => {
|
||||
setFieldErrors(prevErrors => ({ ...prevErrors, [name]: '' }));
|
||||
};
|
||||
|
||||
if (flags.showConfigurableRegistrationFields && shouldDisplayFieldInExperiment(
|
||||
'other_fields', multiStepRegistrationExpVariation, multiStepRegistrationPageStep,
|
||||
)) {
|
||||
if (flags.showConfigurableRegistrationFields) {
|
||||
Object.keys(fieldDescriptions).forEach(fieldName => {
|
||||
const fieldData = fieldDescriptions[fieldName];
|
||||
switch (fieldData.name) {
|
||||
@@ -162,9 +157,7 @@ const ConfigurableRegistrationForm = (props) => {
|
||||
});
|
||||
}
|
||||
|
||||
if ((flags.showConfigurableEdxFields || showCountryField) && shouldDisplayFieldInExperiment(
|
||||
'country', multiStepRegistrationExpVariation, multiStepRegistrationPageStep,
|
||||
)) {
|
||||
if (flags.showConfigurableEdxFields || showCountryField) {
|
||||
formFieldDescriptions.push(
|
||||
<span key="country">
|
||||
<CountryField
|
||||
@@ -180,9 +173,7 @@ const ConfigurableRegistrationForm = (props) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (flags.showMarketingEmailOptInCheckbox && shouldDisplayFieldInExperiment(
|
||||
'marketing_email_opt_in', multiStepRegistrationExpVariation, multiStepRegistrationPageStep,
|
||||
)) {
|
||||
if (flags.showMarketingEmailOptInCheckbox) {
|
||||
formFieldDescriptions.push(
|
||||
<span key="marketing_email_opt_in">
|
||||
<FormFieldRenderer
|
||||
@@ -201,10 +192,7 @@ const ConfigurableRegistrationForm = (props) => {
|
||||
);
|
||||
}
|
||||
|
||||
if ((flags.showConfigurableEdxFields || showTermsOfServiceAndHonorCode)
|
||||
&& shouldDisplayFieldInExperiment(
|
||||
'honor_code', multiStepRegistrationExpVariation, multiStepRegistrationPageStep,
|
||||
)) {
|
||||
if (flags.showConfigurableEdxFields || showTermsOfServiceAndHonorCode) {
|
||||
formFieldDescriptions.push(
|
||||
<span key="honor_code">
|
||||
<HonorCode fieldType="tos_and_honor_code" onChangeHandler={handleOnChange} value={formFields.honor_code} />
|
||||
@@ -239,15 +227,11 @@ ConfigurableRegistrationForm.propTypes = {
|
||||
setFieldErrors: PropTypes.func.isRequired,
|
||||
setFormFields: PropTypes.func.isRequired,
|
||||
autoSubmitRegistrationForm: PropTypes.bool,
|
||||
multiStepRegistrationExpVariation: PropTypes.string,
|
||||
multiStepRegistrationPageStep: PropTypes.string,
|
||||
};
|
||||
|
||||
ConfigurableRegistrationForm.defaultProps = {
|
||||
fieldDescriptions: {},
|
||||
autoSubmitRegistrationForm: false,
|
||||
multiStepRegistrationExpVariation: '',
|
||||
multiStepRegistrationPageStep: FIRST_STEP,
|
||||
};
|
||||
|
||||
export default ConfigurableRegistrationForm;
|
||||
|
||||
@@ -13,13 +13,12 @@ import {
|
||||
TPA_AUTHENTICATION_FAILURE,
|
||||
TPA_SESSION_EXPIRED,
|
||||
} from '../data/constants';
|
||||
import { FIRST_STEP } from '../data/optimizelyExperiment/helper';
|
||||
import messages from '../messages';
|
||||
|
||||
const RegistrationFailureMessage = (props) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const {
|
||||
context, errorCode, failureCount, multiStepRegistrationPageStep,
|
||||
context, errorCode, failureCount,
|
||||
} = props;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -50,11 +49,7 @@ const RegistrationFailureMessage = (props) => {
|
||||
errorMessage = formatMessage(messages['registration.tpa.session.expired'], { provider: context.provider });
|
||||
break;
|
||||
default:
|
||||
if (multiStepRegistrationPageStep !== FIRST_STEP) {
|
||||
errorMessage = formatMessage(messages['multistep.registration.form.submission.error']);
|
||||
} else {
|
||||
errorMessage = formatMessage(messages['registration.empty.form.submission.error']);
|
||||
}
|
||||
errorMessage = formatMessage(messages['registration.empty.form.submission.error']);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -70,7 +65,6 @@ RegistrationFailureMessage.defaultProps = {
|
||||
context: {
|
||||
errorMessage: null,
|
||||
},
|
||||
multiStepRegistrationPageStep: FIRST_STEP,
|
||||
};
|
||||
|
||||
RegistrationFailureMessage.propTypes = {
|
||||
@@ -80,7 +74,6 @@ RegistrationFailureMessage.propTypes = {
|
||||
}),
|
||||
errorCode: PropTypes.string.isRequired,
|
||||
failureCount: PropTypes.number.isRequired,
|
||||
multiStepRegistrationPageStep: PropTypes.string,
|
||||
};
|
||||
|
||||
export default RegistrationFailureMessage;
|
||||
|
||||
@@ -11,9 +11,6 @@ import configureStore from 'redux-mock-store';
|
||||
|
||||
import { registerNewUser } from '../../data/actions';
|
||||
import { FIELDS } from '../../data/constants';
|
||||
import { FIRST_STEP, NOT_INITIALIZED } from '../../data/optimizelyExperiment/helper';
|
||||
import useMultiStepRegistrationExperimentVariation
|
||||
from '../../data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation';
|
||||
import RegistrationPage from '../../RegistrationPage';
|
||||
import ConfigurableRegistrationForm from '../ConfigurableRegistrationForm';
|
||||
|
||||
@@ -25,7 +22,6 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
...jest.requireActual('@edx/frontend-platform/i18n'),
|
||||
getLocale: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation', () => jest.fn());
|
||||
|
||||
const IntlConfigurableRegistrationForm = injectIntl(ConfigurableRegistrationForm);
|
||||
const IntlRegistrationPage = injectIntl(RegistrationPage);
|
||||
@@ -97,9 +93,6 @@ describe('ConfigurableRegistrationForm', () => {
|
||||
registrationError: {},
|
||||
registrationFormData,
|
||||
usernameSuggestions: [],
|
||||
multiStepRegistrationPageStep: FIRST_STEP,
|
||||
multiStepRegExpVariation: '',
|
||||
isValidatingMultiStepRegistrationPage: false,
|
||||
},
|
||||
commonComponents: {
|
||||
thirdPartyAuthApiStatus: null,
|
||||
@@ -128,7 +121,6 @@ describe('ConfigurableRegistrationForm', () => {
|
||||
};
|
||||
window.location = { search: '' };
|
||||
getLocale.mockImplementationOnce(() => ('en-us'));
|
||||
useMultiStepRegistrationExperimentVariation.mockReturnValue(NOT_INITIALIZED);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -12,9 +12,6 @@ import configureStore from 'redux-mock-store';
|
||||
import {
|
||||
FORBIDDEN_REQUEST, INTERNAL_SERVER_ERROR, TPA_AUTHENTICATION_FAILURE, TPA_SESSION_EXPIRED,
|
||||
} from '../../data/constants';
|
||||
import { NOT_INITIALIZED } from '../../data/optimizelyExperiment/helper';
|
||||
import useMultiStepRegistrationExperimentVariation
|
||||
from '../../data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation';
|
||||
import RegistrationPage from '../../RegistrationPage';
|
||||
import RegistrationFailureMessage from '../RegistrationFailure';
|
||||
|
||||
@@ -26,7 +23,6 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
...jest.requireActual('@edx/frontend-platform/i18n'),
|
||||
getLocale: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation', () => jest.fn());
|
||||
|
||||
const IntlRegistrationPage = injectIntl(RegistrationPage);
|
||||
const IntlRegistrationFailure = injectIntl(RegistrationFailureMessage);
|
||||
@@ -125,7 +121,6 @@ describe('RegistrationFailure', () => {
|
||||
institutionLogin: false,
|
||||
};
|
||||
window.location = { search: '' };
|
||||
useMultiStepRegistrationExperimentVariation.mockReturnValue(NOT_INITIALIZED);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -12,9 +12,6 @@ import configureStore from 'redux-mock-store';
|
||||
import {
|
||||
COMPLETE_STATE, LOGIN_PAGE, PENDING_STATE, REGISTER_PAGE,
|
||||
} from '../../../data/constants';
|
||||
import { NOT_INITIALIZED } from '../../data/optimizelyExperiment/helper';
|
||||
import useMultiStepRegistrationExperimentVariation
|
||||
from '../../data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation';
|
||||
import RegistrationPage from '../../RegistrationPage';
|
||||
|
||||
jest.mock('@edx/frontend-platform/analytics', () => ({
|
||||
@@ -25,7 +22,6 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
...jest.requireActual('@edx/frontend-platform/i18n'),
|
||||
getLocale: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../data/optimizelyExperiment/useMultiStepRegistrationExperimentVariation', () => jest.fn());
|
||||
|
||||
const IntlRegistrationPage = injectIntl(RegistrationPage);
|
||||
const mockStore = configureStore();
|
||||
@@ -124,7 +120,6 @@ describe('ThirdPartyAuth', () => {
|
||||
institutionLogin: false,
|
||||
};
|
||||
window.location = { search: '' };
|
||||
useMultiStepRegistrationExperimentVariation.mockReturnValue(NOT_INITIALIZED);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -8,8 +8,6 @@ export const REGISTRATION_CLEAR_BACKEND_ERROR = 'REGISTRATION_CLEAR_BACKEND_ERRO
|
||||
export const REGISTER_SET_COUNTRY_CODE = 'REGISTER_SET_COUNTRY_CODE';
|
||||
export const REGISTER_SET_USER_PIPELINE_DATA_LOADED = 'REGISTER_SET_USER_PIPELINE_DATA_LOADED';
|
||||
export const REGISTER_SET_EMAIL_SUGGESTIONS = 'REGISTER_SET_EMAIL_SUGGESTIONS';
|
||||
export const REGISTER_SET_MULTI_STEP_REGISTRATION_EXP_DATA = 'REGISTER_SET_MULTI_STEP_REGISTRATION_EXP_DATA';
|
||||
|
||||
// Backup registration form
|
||||
export const backupRegistrationForm = () => ({
|
||||
type: BACKUP_REGISTRATION_DATA.BASE,
|
||||
@@ -21,19 +19,18 @@ export const backupRegistrationFormBegin = (data) => ({
|
||||
});
|
||||
|
||||
// Validate fields from the backend
|
||||
export const fetchRealtimeValidations = (formPayload, isValidatingMultiStepRegistrationPage) => ({
|
||||
export const fetchRealtimeValidations = (formPayload) => ({
|
||||
type: REGISTER_FORM_VALIDATIONS.BASE,
|
||||
payload: { formPayload, isValidatingMultiStepRegistrationPage },
|
||||
payload: { formPayload },
|
||||
});
|
||||
|
||||
export const fetchRealtimeValidationsBegin = (isValidatingMultiStepRegistrationPage) => ({
|
||||
export const fetchRealtimeValidationsBegin = () => ({
|
||||
type: REGISTER_FORM_VALIDATIONS.BEGIN,
|
||||
payload: { isValidatingMultiStepRegistrationPage },
|
||||
});
|
||||
|
||||
export const fetchRealtimeValidationsSuccess = (validations, isValidatingMultiStepRegistrationPage) => ({
|
||||
export const fetchRealtimeValidationsSuccess = (validations) => ({
|
||||
type: REGISTER_FORM_VALIDATIONS.SUCCESS,
|
||||
payload: { validations, isValidatingMultiStepRegistrationPage },
|
||||
payload: { validations },
|
||||
});
|
||||
|
||||
export const fetchRealtimeValidationsFailure = () => ({
|
||||
@@ -85,11 +82,3 @@ export const setUserPipelineDataLoaded = (value) => ({
|
||||
type: REGISTER_SET_USER_PIPELINE_DATA_LOADED,
|
||||
payload: { value },
|
||||
});
|
||||
|
||||
// Multi Step Registration Experiment Actions
|
||||
export const setMultiStepRegistrationExpData = (
|
||||
multiStepRegExpVariation, multiStepRegistrationPageStep, isValidatingMultiStepRegistrationPage,
|
||||
) => ({
|
||||
type: REGISTER_SET_MULTI_STEP_REGISTRATION_EXP_DATA,
|
||||
payload: { multiStepRegExpVariation, multiStepRegistrationPageStep, isValidatingMultiStepRegistrationPage },
|
||||
});
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
/**
|
||||
* This file contains data for Multi Step Registration Optimizely experiment
|
||||
*/
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
import messages from '../../messages';
|
||||
|
||||
export const NOT_INITIALIZED = 'experiment-not-initialized';
|
||||
export const CONTROL = 'control-registration-page';
|
||||
export const MULTI_STEP_REGISTRATION_EXP_VARIATION = 'multi-step-registration-page';
|
||||
|
||||
export const FIRST_STEP = 'first-step';
|
||||
export const SECOND_STEP = 'second-step';
|
||||
export const THIRD_STEP = 'third-step';
|
||||
|
||||
export const CONTROL_REGISTER_PAGE_FIRST_STEP_FIELDS = ['name', 'email', 'password', 'marketing_email_opt_in', 'ThirdPartyAuth'];
|
||||
export const CONTROL_REGISTER_PAGE_SECOND_STEP_FIELDS = ['username', 'country'];
|
||||
export const CONTROL_REGISTER_PAGE_COMMON_FIELDS = ['tos_and_honor_code', 'honor_code'];
|
||||
|
||||
export const MULTI_STEP_REGISTER_PAGE_FIRST_STEP_FIELDS = ['email', 'marketing_email_opt_in', 'ThirdPartyAuth'];
|
||||
export const MULTI_STEP_REGISTER_PAGE_SECOND_STEP_FIELDS = ['name', 'password'];
|
||||
export const MULTI_STEP_REGISTER_PAGE_THIRD_STEP_FIELDS = ['username', 'country'];
|
||||
export const MULTI_STEP_REGISTER_PAGE_COMMON_FIELDS = ['tos_and_honor_code', 'honor_code'];
|
||||
|
||||
const MULTI_STEP_REGISTRATION_EXP_PAGE = 'authn_register_page';
|
||||
|
||||
export function getMultiStepRegistrationExperimentVariation() {
|
||||
try {
|
||||
if (window.optimizely
|
||||
&& window.optimizely.get('data').experiments[getConfig().MULTI_STEP_REGISTRATION_EXPERIMENT_ID]) {
|
||||
const selectedVariant = window.optimizely.get('state').getVariationMap()[
|
||||
getConfig().MULTI_STEP_REGISTRATION_EXPERIMENT_ID
|
||||
];
|
||||
return selectedVariant?.name;
|
||||
}
|
||||
} catch (e) { /* empty */ }
|
||||
return '';
|
||||
}
|
||||
|
||||
export function activateMultiStepRegistrationExperiment() {
|
||||
window.optimizely = window.optimizely || [];
|
||||
window.optimizely.push({
|
||||
type: 'page',
|
||||
pageName: MULTI_STEP_REGISTRATION_EXP_PAGE,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to display username and honor_code fields in second page if user is in multi-step
|
||||
* registration page experiment
|
||||
*/
|
||||
export const shouldDisplayFieldInExperiment = (fieldName, expVariation, registerPageStep) => (
|
||||
!expVariation || expVariation === NOT_INITIALIZED
|
||||
|| (expVariation === CONTROL
|
||||
&& (
|
||||
CONTROL_REGISTER_PAGE_COMMON_FIELDS.includes(fieldName)
|
||||
|| (registerPageStep === FIRST_STEP && CONTROL_REGISTER_PAGE_FIRST_STEP_FIELDS.includes(fieldName))
|
||||
|| (registerPageStep === SECOND_STEP && CONTROL_REGISTER_PAGE_SECOND_STEP_FIELDS.includes(fieldName))
|
||||
))
|
||||
|| (expVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION
|
||||
&& (
|
||||
MULTI_STEP_REGISTER_PAGE_COMMON_FIELDS.includes(fieldName)
|
||||
|| (registerPageStep === FIRST_STEP && MULTI_STEP_REGISTER_PAGE_FIRST_STEP_FIELDS.includes(fieldName))
|
||||
|| (registerPageStep === SECOND_STEP && MULTI_STEP_REGISTER_PAGE_SECOND_STEP_FIELDS.includes(fieldName))
|
||||
|| (registerPageStep === THIRD_STEP && MULTI_STEP_REGISTER_PAGE_THIRD_STEP_FIELDS.includes(fieldName))
|
||||
))
|
||||
);
|
||||
|
||||
export const getRegisterButtonLabelInExperiment = (
|
||||
existingButtonLabel, expVariation, registerPageStep, formatMessage,
|
||||
) => {
|
||||
if (expVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION && registerPageStep === FIRST_STEP) {
|
||||
return formatMessage(messages['multistep.registration.exp.continue.button']);
|
||||
}
|
||||
return existingButtonLabel;
|
||||
};
|
||||
|
||||
export const getRegisterButtonClassInExperiment = (expVariation, registerPageStep) => {
|
||||
if (expVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION && registerPageStep === FIRST_STEP) {
|
||||
return 'continue-button';
|
||||
}
|
||||
return 'register-button';
|
||||
};
|
||||
|
||||
export const getRegisterButtonSubmitStateInExperiment = (
|
||||
registerSubmitState, validationsSubmitState, expVariation, registerPageStep,
|
||||
) => {
|
||||
if ((expVariation === MULTI_STEP_REGISTRATION_EXP_VARIATION && registerPageStep !== THIRD_STEP)
|
||||
|| (expVariation === CONTROL && registerPageStep !== SECOND_STEP)) {
|
||||
return validationsSubmitState;
|
||||
}
|
||||
return registerSubmitState;
|
||||
};
|
||||
|
||||
export const getMultiStepRegistrationPreviousStep = (currentStep) => {
|
||||
if (currentStep === THIRD_STEP) {
|
||||
return SECOND_STEP;
|
||||
}
|
||||
if (currentStep === SECOND_STEP) {
|
||||
return FIRST_STEP;
|
||||
}
|
||||
return currentStep;
|
||||
};
|
||||
|
||||
export const getMultiStepRegistrationNextStep = (currentStep) => {
|
||||
if (currentStep === FIRST_STEP) {
|
||||
return SECOND_STEP;
|
||||
}
|
||||
if (currentStep === SECOND_STEP) {
|
||||
return THIRD_STEP;
|
||||
}
|
||||
return currentStep;
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
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, isMarketingLead) => {
|
||||
sendTrackEvent(eventNames.multiStepRegistrationStep2Viewed, {
|
||||
variation: expVariation,
|
||||
is_marketing_lead: isMarketingLead,
|
||||
});
|
||||
};
|
||||
|
||||
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,
|
||||
});
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
activateMultiStepRegistrationExperiment,
|
||||
getMultiStepRegistrationExperimentVariation,
|
||||
NOT_INITIALIZED,
|
||||
} from './helper';
|
||||
import { trackMultiStepRegistrationStep1Viewed } from './track';
|
||||
import { COMPLETE_STATE } from '../../../data/constants';
|
||||
|
||||
/**
|
||||
* This hook returns activates multi step registration experiment and returns the experiment
|
||||
* variation for the user.
|
||||
*/
|
||||
const useMultiStepRegistrationExperimentVariation = (
|
||||
initExpVariation,
|
||||
registrationEmbedded,
|
||||
tpaHint,
|
||||
currentProvider,
|
||||
thirdPartyAuthApiStatus,
|
||||
) => {
|
||||
const [variation, setVariation] = useState(initExpVariation);
|
||||
|
||||
useEffect(() => {
|
||||
if (initExpVariation || registrationEmbedded || !!tpaHint || !!currentProvider
|
||||
|| thirdPartyAuthApiStatus !== COMPLETE_STATE) {
|
||||
return variation;
|
||||
}
|
||||
|
||||
const getVariation = () => {
|
||||
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.
|
||||
setVariation(NOT_INITIALIZED);
|
||||
}
|
||||
};
|
||||
|
||||
activateMultiStepRegistrationExperiment();
|
||||
|
||||
const timer = setTimeout(getVariation, 300);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
};
|
||||
}, [ // eslint-disable-line react-hooks/exhaustive-deps
|
||||
currentProvider, initExpVariation, registrationEmbedded, thirdPartyAuthApiStatus, tpaHint,
|
||||
]);
|
||||
|
||||
return variation;
|
||||
};
|
||||
|
||||
export default useMultiStepRegistrationExperimentVariation;
|
||||
@@ -5,11 +5,9 @@ import {
|
||||
REGISTER_NEW_USER,
|
||||
REGISTER_SET_COUNTRY_CODE,
|
||||
REGISTER_SET_EMAIL_SUGGESTIONS,
|
||||
REGISTER_SET_MULTI_STEP_REGISTRATION_EXP_DATA,
|
||||
REGISTER_SET_USER_PIPELINE_DATA_LOADED,
|
||||
REGISTRATION_CLEAR_BACKEND_ERROR,
|
||||
} from './actions';
|
||||
import { FIRST_STEP } from './optimizelyExperiment/helper';
|
||||
import {
|
||||
DEFAULT_STATE,
|
||||
PENDING_STATE,
|
||||
@@ -37,14 +35,10 @@ export const defaultState = {
|
||||
},
|
||||
validations: null,
|
||||
submitState: DEFAULT_STATE,
|
||||
validationsSubmitState: DEFAULT_STATE,
|
||||
userPipelineDataLoaded: false,
|
||||
usernameSuggestions: [],
|
||||
validationApiRateLimited: false,
|
||||
shouldBackupState: false,
|
||||
multiStepRegExpVariation: '',
|
||||
multiStepRegistrationPageStep: FIRST_STEP,
|
||||
isValidatingMultiStepRegistrationPage: false,
|
||||
};
|
||||
|
||||
const reducer = (state = defaultState, action = {}) => {
|
||||
@@ -91,22 +85,12 @@ const reducer = (state = defaultState, action = {}) => {
|
||||
registrationError: { ...registrationErrorTemp },
|
||||
};
|
||||
}
|
||||
case REGISTER_FORM_VALIDATIONS.BEGIN: {
|
||||
return {
|
||||
...state,
|
||||
validationsSubmitState: action.payload?.isValidatingMultiStepRegistrationPage
|
||||
? PENDING_STATE
|
||||
: state.validationsSubmitState,
|
||||
};
|
||||
}
|
||||
case REGISTER_FORM_VALIDATIONS.SUCCESS: {
|
||||
const { usernameSuggestions, ...validationWithoutUsernameSuggestions } = action.payload.validations;
|
||||
return {
|
||||
...state,
|
||||
validations: validationWithoutUsernameSuggestions,
|
||||
isValidatingMultiStepRegistrationPage: !!action.payload?.isValidatingMultiStepRegistrationPage,
|
||||
usernameSuggestions: usernameSuggestions || state.usernameSuggestions,
|
||||
validationsSubmitState: DEFAULT_STATE,
|
||||
};
|
||||
}
|
||||
case REGISTER_FORM_VALIDATIONS.FAILURE:
|
||||
@@ -114,7 +98,6 @@ const reducer = (state = defaultState, action = {}) => {
|
||||
...state,
|
||||
validationApiRateLimited: true,
|
||||
validations: null,
|
||||
validationsSubmitState: DEFAULT_STATE,
|
||||
};
|
||||
case REGISTER_CLEAR_USERNAME_SUGGESTIONS:
|
||||
return {
|
||||
@@ -146,14 +129,6 @@ const reducer = (state = defaultState, action = {}) => {
|
||||
emailSuggestion: action.payload.emailSuggestion,
|
||||
},
|
||||
};
|
||||
case REGISTER_SET_MULTI_STEP_REGISTRATION_EXP_DATA: {
|
||||
return {
|
||||
...state,
|
||||
multiStepRegExpVariation: action.payload.multiStepRegExpVariation,
|
||||
multiStepRegistrationPageStep: action.payload.multiStepRegistrationPageStep,
|
||||
isValidatingMultiStepRegistrationPage: !!action.payload?.isValidatingMultiStepRegistrationPage,
|
||||
};
|
||||
}
|
||||
default:
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -40,13 +40,10 @@ export function* handleNewUserRegistration(action) {
|
||||
|
||||
export function* fetchRealtimeValidations(action) {
|
||||
try {
|
||||
yield put(fetchRealtimeValidationsBegin(action.payload?.isValidatingMultiStepRegistrationPage));
|
||||
yield put(fetchRealtimeValidationsBegin());
|
||||
const { fieldValidations } = yield call(getFieldsValidations, action.payload.formPayload);
|
||||
|
||||
yield put(fetchRealtimeValidationsSuccess(
|
||||
camelCaseObject(fieldValidations),
|
||||
action.payload?.isValidatingMultiStepRegistrationPage,
|
||||
));
|
||||
yield put(fetchRealtimeValidationsSuccess(camelCaseObject(fieldValidations)));
|
||||
} catch (e) {
|
||||
if (e.response && e.response.status === 403) {
|
||||
yield put(fetchRealtimeValidationsFailure());
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
REGISTER_SET_USER_PIPELINE_DATA_LOADED,
|
||||
REGISTRATION_CLEAR_BACKEND_ERROR,
|
||||
} from '../actions';
|
||||
import { FIRST_STEP } from '../optimizelyExperiment/helper';
|
||||
import reducer from '../reducers';
|
||||
|
||||
describe('Registration Reducer Tests', () => {
|
||||
@@ -35,14 +34,10 @@ describe('Registration Reducer Tests', () => {
|
||||
},
|
||||
validations: null,
|
||||
submitState: DEFAULT_STATE,
|
||||
validationsSubmitState: DEFAULT_STATE,
|
||||
userPipelineDataLoaded: false,
|
||||
usernameSuggestions: [],
|
||||
validationApiRateLimited: false,
|
||||
shouldBackupState: false,
|
||||
multiStepRegExpVariation: '',
|
||||
multiStepRegistrationPageStep: FIRST_STEP,
|
||||
isValidatingMultiStepRegistrationPage: false,
|
||||
};
|
||||
|
||||
it('should return the initial state', () => {
|
||||
|
||||
@@ -43,39 +43,31 @@ export const isFormValid = (
|
||||
Object.keys(payload).forEach(key => {
|
||||
switch (key) {
|
||||
case 'name':
|
||||
if (!fieldErrors.name) {
|
||||
fieldErrors.name = validateName(payload.name, formatMessage);
|
||||
}
|
||||
fieldErrors.name = validateName(payload.name, formatMessage);
|
||||
if (fieldErrors.name) { isValid = false; }
|
||||
break;
|
||||
case 'email': {
|
||||
if (!fieldErrors.email) {
|
||||
const {
|
||||
fieldError, confirmEmailError, suggestion,
|
||||
} = validateEmail(payload.email, configurableFormFields?.confirm_email, formatMessage);
|
||||
if (fieldError) {
|
||||
fieldErrors.email = fieldError;
|
||||
isValid = false;
|
||||
}
|
||||
if (confirmEmailError) {
|
||||
fieldErrors.confirm_email = confirmEmailError;
|
||||
isValid = false;
|
||||
}
|
||||
emailSuggestion = suggestion;
|
||||
const {
|
||||
fieldError, confirmEmailError, suggestion,
|
||||
} = validateEmail(payload.email, configurableFormFields?.confirm_email, formatMessage);
|
||||
if (fieldError) {
|
||||
fieldErrors.email = fieldError;
|
||||
isValid = false;
|
||||
}
|
||||
if (confirmEmailError) {
|
||||
fieldErrors.confirm_email = confirmEmailError;
|
||||
isValid = false;
|
||||
}
|
||||
emailSuggestion = suggestion;
|
||||
if (fieldErrors.email) { isValid = false; }
|
||||
break;
|
||||
}
|
||||
case 'username':
|
||||
if (!fieldErrors.username) {
|
||||
fieldErrors.username = validateUsername(payload.username, formatMessage);
|
||||
}
|
||||
fieldErrors.username = validateUsername(payload.username, formatMessage);
|
||||
if (fieldErrors.username) { isValid = false; }
|
||||
break;
|
||||
case 'password':
|
||||
if (!fieldErrors.password) {
|
||||
fieldErrors.password = validatePasswordField(payload.password, formatMessage);
|
||||
}
|
||||
fieldErrors.password = validatePasswordField(payload.password, formatMessage);
|
||||
if (fieldErrors.password) { isValid = false; }
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -201,29 +201,6 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Did you mean',
|
||||
description: 'Did you mean alert suggestion',
|
||||
},
|
||||
// MultiStep Registration experiment
|
||||
'multistep.registration.exp.continue.button': {
|
||||
id: 'multistep.registration.exp.continue.button',
|
||||
defaultMessage: 'Continue',
|
||||
description: 'Label text for multistep registration page second step',
|
||||
},
|
||||
'multistep.registration.username.second.step.guideline.content': {
|
||||
id: 'multistep.registration.username.second.step.guideline.content',
|
||||
defaultMessage: 'Finish Registration',
|
||||
description: 'Guideline content for username field in multi-step registration experiment step 2',
|
||||
},
|
||||
'multistep.registration.username.third.step.guideline.content': {
|
||||
id: 'multistep.registration.username.third.step.guideline.content',
|
||||
defaultMessage: 'To finalize your registration, please confirm your country of residence '
|
||||
+ 'and create a public username that will identify you in your course communication forums. '
|
||||
+ 'The username cannot be changed.',
|
||||
description: 'Guideline content for username field in multi-step registration experiment step 2',
|
||||
},
|
||||
'multistep.registration.form.submission.error': {
|
||||
id: 'multistep.registration.form.submission.error',
|
||||
defaultMessage: 'Please check your responses for this and the previous step and try again.',
|
||||
description: 'Error message that appears on top of the form when invalid form is submitted',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
min-width: 14.4rem;
|
||||
}
|
||||
|
||||
.continue-button {
|
||||
min-width: 7rem;
|
||||
}
|
||||
|
||||
.pgn__form-autosuggest__wrapper > .pgn__form-group {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user