Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement multi step registration experiment #1215

Merged
merged 2 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/common-components/SocialAuthProviders.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -60,6 +70,7 @@ const SocialAuthProviders = (props) => {
SocialAuthProviders.defaultProps = {
referrer: LOGIN_PAGE,
socialAuthProviders: [],
multiStepRegistrationExpVariation: '',
};

SocialAuthProviders.propTypes = {
Expand All @@ -73,6 +84,7 @@ SocialAuthProviders.propTypes = {
registerUrl: PropTypes.string,
skipRegistrationForm: PropTypes.bool,
})),
multiStepRegistrationExpVariation: PropTypes.string,
};

export default SocialAuthProviders;
4 changes: 4 additions & 0 deletions src/common-components/ThirdPartyAuth.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const ThirdPartyAuth = (props) => {
handleInstitutionLogin,
thirdPartyAuthApiStatus,
isLoginPage,
multiStepRegistrationExpVariation,
} = props;
const isInstitutionAuthActive = !!secondaryProviders.length && !currentProvider;
const isSocialAuthActive = !!providers.length && !currentProvider;
Expand Down Expand Up @@ -78,6 +79,7 @@ const ThirdPartyAuth = (props) => {
<SocialAuthProviders
socialAuthProviders={providers}
referrer={isLoginPage ? LOGIN_PAGE : REGISTER_PAGE}
multiStepRegistrationExpVariation={multiStepRegistrationExpVariation}
/>
</div>
)}
Expand All @@ -93,6 +95,7 @@ ThirdPartyAuth.defaultProps = {
secondaryProviders: [],
thirdPartyAuthApiStatus: PENDING_STATE,
isLoginPage: false,
multiStepRegistrationExpVariation: '',
};

ThirdPartyAuth.propTypes = {
Expand Down Expand Up @@ -120,6 +123,7 @@ ThirdPartyAuth.propTypes = {
),
thirdPartyAuthApiStatus: PropTypes.string,
isLoginPage: PropTypes.bool,
multiStepRegistrationExpVariation: PropTypes.string,
};

export default ThirdPartyAuth;
6 changes: 6 additions & 0 deletions src/common-components/messages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ 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;
2 changes: 2 additions & 0 deletions src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ 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;
55 changes: 46 additions & 9 deletions src/logistration/Logistration.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { connect, useDispatch, useSelector } from 'react-redux';

import { getConfig } from '@edx/frontend-platform';
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthService } from '@edx/frontend-platform/auth';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Icon,
IconButton,
Tab,
Tabs,
} from '@openedx/paragon';
import { ChevronLeft } from '@openedx/paragon/icons';
import { ArrowBackIos, ChevronLeft } from '@openedx/paragon/icons';
import PropTypes from 'prop-types';
import { Navigate, useNavigate } from 'react-router-dom';

Expand All @@ -27,7 +28,11 @@ import {
import { LoginPage } from '../login';
import { backupLoginForm } from '../login/data/actions';
import { RegistrationPage } from '../register';
import { backupRegistrationForm } from '../register/data/actions';
import { backupRegistrationForm, setMultiStepRegistrationExpData } from '../register/data/actions';
import {
FIRST_STEP,
getMultiStepRegistrationPreviousStep,
} from '../register/data/optimizelyExperiment/helper';

const Logistration = (props) => {
const { selectedPage, tpaProviders } = props;
Expand All @@ -42,6 +47,10 @@ 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) {
Expand Down Expand Up @@ -91,6 +100,39 @@ 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;
Expand Down Expand Up @@ -123,12 +165,7 @@ const Logistration = (props) => {
<Tab title={tabTitle} eventKey={selectedPage === LOGIN_PAGE ? LOGIN_PAGE : REGISTER_PAGE} />
</Tabs>
)
: (!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>
))}
: (!isValidTpaHint() && !hideRegistrationLink && getTabs())}
{ key && (
<Navigate to={updatePathWithQueryParams(key)} replace />
)}
Expand Down
7 changes: 7 additions & 0 deletions src/logistration/Logistration.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ 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);
Expand Down Expand Up @@ -63,6 +67,8 @@ describe('Logistration', () => {
registrationError: {},
usernameSuggestions: [],
validationApiRateLimited: false,
multiStepRegExpVariation: '',
multiStepRegistrationPageStep: FIRST_STEP,
},
commonComponents: {
thirdPartyAuthContext: {
Expand All @@ -83,6 +89,7 @@ describe('Logistration', () => {
username: 'test-user',
})),
}));
useMultiStepRegistrationExperimentVariation.mockReturnValue(NOT_INITIALIZED);

configure({
loggingService: { logError: jest.fn() },
Expand Down
Loading
Loading