Add welcome page (#302)

Add welcome page for A/B testing

VAN-514
This commit is contained in:
Mubbshar Anwar
2021-06-01 17:46:52 +05:00
committed by GitHub
parent ea02aba94a
commit a8eb5916eb
9 changed files with 309 additions and 1 deletions

1
.env
View File

@@ -19,3 +19,4 @@ LOGIN_ISSUE_SUPPORT_LINK=null
REGISTRATION_OPTIONAL_FIELDS=null
USER_SURVEY_COOKIE_NAME=null
COOKIE_DOMAIN=null
WELCOME_PAGE_SUPPORT_LINK=null

View File

@@ -26,3 +26,4 @@ PRIVACY_POLICY='http://localhost:18000/privacy'
REGISTRATION_OPTIONAL_FIELDS='gender,goals,level_of_education,year_of_birth'
USER_SURVEY_COOKIE_NAME='openedx-user-survey-type'
COOKIE_DOMAIN='localhost'
WELCOME_PAGE_SUPPORT_LINK='http://localhost:1999/welcome'

View File

@@ -19,3 +19,4 @@ SITE_NAME='edX'
USER_INFO_COOKIE_NAME='edx-user-info'
LOGIN_ISSUE_SUPPORT_LINK='https://login-issue-support-url.com'
USER_SURVEY_COOKIE_NAME='openedx-user-survey-type'
WELCOME_PAGE_SUPPORT_LINK='http://localhost:1999/welcome'

View File

@@ -14,6 +14,8 @@ function RedirectLogistration(props) {
if (finishAuthUrl && !redirectUrl.includes(finishAuthUrl)) {
window.location.href = getConfig().LMS_BASE_URL + finishAuthUrl;
} else {
// use this component to redirect WelcomePage after successful registration
// return <Redirect to={WELCOME_PAGE} />;
window.location.href = redirectUrl;
}
}

View File

@@ -2,6 +2,7 @@
export const LOGIN_PAGE = '/login';
export const REGISTER_PAGE = '/register';
export const RESET_PAGE = '/reset';
export const WELCOME_PAGE = '/welcome';
export const DEFAULT_REDIRECT_URL = '/dashboard';
export const PASSWORD_RESET_CONFIRM = '/password_reset_confirm/:token/';
export const PAGE_NOT_FOUND = '/notfound';

View File

@@ -15,13 +15,14 @@ import configureStore from './data/configureStore';
import { RegistrationPage } from './register';
import { LoginPage } from './login';
import {
LOGIN_PAGE, PAGE_NOT_FOUND, REGISTER_PAGE, RESET_PAGE, PASSWORD_RESET_CONFIRM,
LOGIN_PAGE, PAGE_NOT_FOUND, REGISTER_PAGE, RESET_PAGE, PASSWORD_RESET_CONFIRM, WELCOME_PAGE,
} from './data/constants';
import ForgotPasswordPage from './forgot-password';
import {
HeaderLayout, UnAuthOnlyRoute, registerIcons, NotFoundPage,
} from './common-components';
import ResetPasswordPage from './reset-password';
import WelcomePage from './welcome';
import appMessages from './i18n';
import './index.scss';
@@ -40,6 +41,7 @@ subscribe(APP_READY, () => {
<UnAuthOnlyRoute exact path={REGISTER_PAGE} component={RegistrationPage} />
<UnAuthOnlyRoute exact path={RESET_PAGE} component={ForgotPasswordPage} />
<Route exact path={PASSWORD_RESET_CONFIRM} component={ResetPasswordPage} />
<Route exact path={WELCOME_PAGE} component={WelcomePage} />
<Route path={PAGE_NOT_FOUND} component={NotFoundPage} />
<Route path="*">
<Redirect to={PAGE_NOT_FOUND} />
@@ -67,6 +69,7 @@ initialize({
REGISTRATION_OPTIONAL_FIELDS: process.env.REGISTRATION_OPTIONAL_FIELDS || '',
USER_SURVEY_COOKIE_NAME: process.env.USER_SURVEY_COOKIE_NAME || null,
COOKIE_DOMAIN: process.env.COOKIE_DOMAIN,
WELCOME_PAGE_SUPPORT_LINK: process.env.WELCOME_PAGE_SUPPORT_LINK || null,
});
},
},

188
src/welcome/WelcomePage.jsx Normal file
View File

@@ -0,0 +1,188 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Helmet } from 'react-helmet';
import { getConfig } from '@edx/frontend-platform';
import {
ensureAuthenticatedUser, hydrateAuthenticatedUser, getAuthenticatedUser,
} from '@edx/frontend-platform/auth';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import {
Form,
StatefulButton,
Hyperlink,
} from '@edx/paragon';
import messages from './messages';
import { EDUCATION_LEVELS, GENDER_OPTIONS, YEAR_OF_BIRTH_OPTIONS } from '../register/data/constants';
import { registrationRequestSelector } from '../register/data/selectors';
import { AuthnValidationFormGroup } from '../common-components';
import { DEFAULT_REDIRECT_URL } from '../data/constants';
const WelcomePage = (props) => {
const { intl, registrationResult } = props;
const [values, setValues] = useState({});
const [ready, setReady] = useState(false);
const DASHBOARD_URL = getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL);
useEffect(() => {
ensureAuthenticatedUser(DASHBOARD_URL).then(() => {
hydrateAuthenticatedUser().then(() => {
setReady(true);
});
});
}, []);
const authenticatedUser = getAuthenticatedUser();
if (!registrationResult.redirectUrl) {
global.location.assign(DASHBOARD_URL);
return null;
}
if (!ready) {
return null;
}
const getOptions = () => ({
yearOfBirthOptions: [{
value: '',
label: intl.formatMessage(messages['registration.year.of.birth.label']),
}].concat(YEAR_OF_BIRTH_OPTIONS),
educationLevelOptions: EDUCATION_LEVELS.map(key => ({
value: key,
label: intl.formatMessage(messages[`registration.field.education.levels.${key || 'label'}`]),
})),
genderOptions: GENDER_OPTIONS.map(key => ({
value: key,
label: intl.formatMessage(messages[`registration.field.gender.options.${key || 'label'}`]),
})),
});
const handleSubmit = (e) => {
e.preventDefault();
if (registrationResult.success) {
window.location.href = registrationResult.redirectUrl;
}
return null;
};
const handleSkip = (e) => {
e.preventDefault();
window.location.href = registrationResult.redirectUrl;
return null;
};
const onChangeHandler = (e) => {
setValues({ ...values, [e.target.name]: e.target.value });
};
return (
<>
<Helmet>
<title>{intl.formatMessage(messages['optional.fields.page.title'],
{ siteName: getConfig().SITE_NAME })}
</title>
</Helmet>
<div className="d-flex justify-content-center m-4">
<div className="d-flex flex-column">
<Form className="mw-500">
<p className="mb-4">
{ intl.formatMessage(messages['welcome.to.edx'], { username: authenticatedUser.username }) }
</p>
<hr className="mb-3 border-gray-200" />
<h1 className="mb-3 h3">{intl.formatMessage(messages['optional.fields.page.heading'])}</h1>
<AuthnValidationFormGroup
label={intl.formatMessage(messages['registration.field.education.levels.label'])}
for="levelOfEducation"
name="levelOfEducation"
type="select"
key="levelOfEducation"
className="mb-3 data-hj-suppress"
value={values.levelOfEducation}
onChange={(e) => onChangeHandler(e)}
selectOptions={getOptions().educationLevelOptions}
inputFieldStyle="border-gray-600 custom-select-size"
/>
<AuthnValidationFormGroup
label={intl.formatMessage(messages['registration.year.of.birth.label'])}
for="yearOfBirth"
name="yearOfBirth"
type="select"
key="yearOfBirth"
value={values.yearOfBirth}
className="mb-3 data-hj-suppress"
onChange={(e) => onChangeHandler(e)}
selectOptions={getOptions().yearOfBirthOptions}
inputFieldStyle="border-gray-600 custom-select-size"
/>
<AuthnValidationFormGroup
label={intl.formatMessage(messages['registration.field.gender.options.label'])}
for="gender"
name="gender"
type="select"
key="gender"
value={values.gender}
className="mb-3 data-hj-suppress"
onChange={(e) => onChangeHandler(e)}
selectOptions={getOptions().genderOptions}
inputFieldStyle="border-gray-600 custom-select-size"
/>
<p>
<Hyperlink
className="mt-1 text-dark"
destination={getConfig().WELCOME_PAGE_SUPPORT_LINK}
target="_blank"
>
{intl.formatMessage(messages['optional.fields.information.link'])}
</Hyperlink>
</p>
<div className="d-flex mt-3">
<StatefulButton
type="submit"
variant="brand"
labels={{
default: intl.formatMessage(messages['optional.fields.submit.button']),
}}
onClick={handleSubmit}
onMouseDown={(e) => e.preventDefault()}
/>
<StatefulButton
type="submit"
variant="link"
className="ml-1 text-dark"
labels={{
default: intl.formatMessage(messages['optional.fields.skip.button']),
}}
onClick={handleSkip}
onMouseDown={(e) => e.preventDefault()}
/>
</div>
</Form>
</div>
</div>
</>
);
};
WelcomePage.propTypes = {
intl: intlShape.isRequired,
registrationResult: PropTypes.shape({
redirectUrl: PropTypes.string,
success: PropTypes.bool,
}),
};
WelcomePage.defaultProps = {
registrationResult: {},
};
const mapStateToProps = state => {
const registrationResult = registrationRequestSelector(state);
return { registrationResult };
};
export default connect(
mapStateToProps,
)(injectIntl(WelcomePage));

1
src/welcome/index.js Normal file
View File

@@ -0,0 +1 @@
export { default } from './WelcomePage';

110
src/welcome/messages.jsx Normal file
View File

@@ -0,0 +1,110 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'optional.fields.page.title': {
id: 'optional.fields.page.title',
defaultMessage: 'Optional Fields | {siteName}',
description: 'optional fields page title',
},
'optional.fields.page.heading': {
id: 'optional.fields.page.heading',
defaultMessage: 'Support education research by providing additional information.',
description: 'The page heading for the optional fields page.',
},
'welcome.to.edx': {
id: 'welcome.to.edx',
defaultMessage: 'Welcome to edX, {username}!',
description: 'Welcome message on the optional fields page.',
},
'registration.field.gender.options.label': {
id: 'registration.field.gender.options.label',
defaultMessage: 'Gender (optional)',
description: 'Placeholder for the gender options dropdown',
},
'registration.field.gender.options.f': {
id: 'registration.field.gender.options.f',
defaultMessage: 'Female',
description: 'The label for the female gender option.',
},
'registration.field.gender.options.m': {
id: 'registration.field.gender.options.m',
defaultMessage: 'Male',
description: 'The label for the male gender option.',
},
'registration.field.gender.options.o': {
id: 'registration.field.gender.options.o',
defaultMessage: 'Other/Prefer not to say',
description: 'The label for catch-all gender option.',
},
'registration.field.education.levels.label': {
id: 'registration.field.education.levels.label',
defaultMessage: 'Highest level of education completed (optional)',
description: 'Placeholder for the education levels dropdown.',
},
'registration.field.education.levels.p': {
id: 'registration.field.education.levels.p',
defaultMessage: 'Doctorate',
description: 'Selected by the user if their highest level of education is a doctorate degree.',
},
'registration.field.education.levels.m': {
id: 'registration.field.education.levels.m',
defaultMessage: "Master's or professional degree",
description: "Selected by the user if their highest level of education is a master's or professional degree from a college or university.",
},
'registration.field.education.levels.b': {
id: 'registration.field.education.levels.b',
defaultMessage: "Bachelor's degree",
description: "Selected by the user if their highest level of education is a four year college or university bachelor's degree.",
},
'registration.field.education.levels.a': {
id: 'registration.field.education.levels.a',
defaultMessage: "Associate's degree",
description: "Selected by the user if their highest level of education is an associate's degree. 1-2 years of college or university.",
},
'registration.field.education.levels.hs': {
id: 'registration.field.education.levels.hs',
defaultMessage: 'Secondary/high school',
description: 'Selected by the user if their highest level of education is secondary or high school. 9-12 years of education.',
},
'registration.field.education.levels.jhs': {
id: 'registration.field.education.levels.jhs',
defaultMessage: 'Junior secondary/junior high/middle school',
description: 'Selected by the user if their highest level of education is junior or middle school. 6-8 years of education.',
},
'registration.field.education.levels.el': {
id: 'registration.field.education.levels.el',
defaultMessage: 'Elementary/primary school',
description: 'Selected by the user if their highest level of education is elementary or primary school. 1-5 years of education.',
},
'registration.field.education.levels.none': {
id: 'registration.field.education.levels.none',
defaultMessage: 'No formal education',
description: 'Selected by the user to describe their education.',
},
'registration.field.education.levels.other': {
id: 'registration.field.education.levels.other',
defaultMessage: 'Other education',
description: 'Selected by the user if they have a type of education not described by the other choices.',
},
'registration.year.of.birth.label': {
id: 'registration.year.of.birth.label',
defaultMessage: 'Year of birth (optional)',
description: 'Placeholder for the year of birth options dropdown',
},
'optional.fields.information.link': {
id: 'optional.fields.information.link',
defaultMessage: 'Learn more about how we use this information.',
description: 'Optional fields page information link',
},
'optional.fields.submit.button': {
id: 'optional.fields.submit.button',
defaultMessage: 'Submit',
description: 'Submit button text',
},
'optional.fields.skip.button': {
id: 'optional.fields.skip.button',
defaultMessage: 'Skip for now',
description: 'Skip button text',
},
});
export default messages;