feat: remove optional fields from register form (#528)

* feat: remove optional fields from register form

This is part of the larger ticket where we will move optional
fields to progressive profiling page.

VAN-837
This commit is contained in:
Zainab Amir
2022-02-09 15:27:18 +05:00
committed by GitHub
parent a04872d7bf
commit 0b21ca3f51
6 changed files with 2 additions and 248 deletions

1
.env
View File

@@ -16,7 +16,6 @@ SITE_NAME=null
USER_INFO_COOKIE_NAME=null
AUTHN_MINIMAL_HEADER=true
LOGIN_ISSUE_SUPPORT_LINK=''
REGISTRATION_OPTIONAL_FIELDS=''
USER_SURVEY_COOKIE_NAME=null
COOKIE_DOMAIN=null
WELCOME_PAGE_SUPPORT_LINK=null

View File

@@ -23,7 +23,6 @@ AUTHN_MINIMAL_HEADER=true
LOGIN_ISSUE_SUPPORT_LINK='/login-issue-support-url'
TOS_AND_HONOR_CODE='http://localhost:18000/honor'
PRIVACY_POLICY='http://localhost:18000/privacy'
REGISTRATION_OPTIONAL_FIELDS=''
USER_SURVEY_COOKIE_NAME='openedx-user-survey-type'
COOKIE_DOMAIN='localhost'
WELCOME_PAGE_SUPPORT_LINK='http://localhost:1999/welcome'

View File

@@ -31,7 +31,6 @@ initialize({
PASSWORD_RESET_SUPPORT_LINK: process.env.PASSWORD_RESET_SUPPORT_LINK || null,
TOS_AND_HONOR_CODE: process.env.TOS_AND_HONOR_CODE || null,
PRIVACY_POLICY: process.env.PRIVACY_POLICY || null,
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,

View File

@@ -1,110 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
import { Form, Icon } from '@edx/paragon';
import { ExpandMore } from '@edx/paragon/icons';
import { EDUCATION_LEVELS, GENDER_OPTIONS, YEAR_OF_BIRTH_OPTIONS } from './data/constants';
import messages from './messages';
const OptionalFields = (props) => {
const {
intl, optionalFields, onChangeHandler, values,
} = props;
if (getConfig().ENABLE_COPPA_COMPLIANCE && EDUCATION_LEVELS) {
const index = EDUCATION_LEVELS.indexOf('el');
EDUCATION_LEVELS.splice(index, 1);
}
const getOptions = () => ({
yearOfBirthOptions: YEAR_OF_BIRTH_OPTIONS.map(({ value, label }) => (
<option className="data-hj-suppress" key={value} value={value}>{label}</option>
)),
educationLevelOptions: EDUCATION_LEVELS.map(key => (
<option className="data-hj-suppress" key={key} value={key}>
{intl.formatMessage(messages[`registration.field.education.levels.${key || 'label'}`])}
</option>
)),
genderOptions: GENDER_OPTIONS.map(key => (
<option className="data-hj-suppress" key={key} value={key}>
{intl.formatMessage(messages[`registration.field.gender.options.${key || 'label'}`])}
</option>
)),
});
return (
<div className="mt-3">
{optionalFields.includes('gender') && (
<Form.Group controlId="gender">
<Form.Control
as="select"
name="gender"
value={values.gender}
onChange={(e) => onChangeHandler('gender', e.target.value)}
trailingElement={<Icon src={ExpandMore} />}
floatingLabel={intl.formatMessage(messages['registration.field.gender.options.label'])}
>
{getOptions().genderOptions}
</Form.Control>
</Form.Group>
)}
{optionalFields.includes('yearOfBirth') && (
<Form.Group controlId="yearOfBirth">
<Form.Control
as="select"
name="yearOfBirth"
value={values.yearOfBirth}
onChange={(e) => onChangeHandler('yearOfBirth', e.target.value)}
trailingElement={<Icon src={ExpandMore} />}
floatingLabel={intl.formatMessage(messages['registration.year.of.birth.label'])}
>
<option value="">{intl.formatMessage(messages['registration.year.of.birth.label'])}</option>
{getOptions().yearOfBirthOptions}
</Form.Control>
</Form.Group>
)}
{optionalFields.includes('levelOfEducation') && (
<Form.Group controlId="levelOfEducation">
<Form.Control
as="select"
name="levelOfEducation"
value={values.levelOfEducation}
onChange={(e) => onChangeHandler('levelOfEducation', e.target.value)}
trailingElement={<Icon src={ExpandMore} />}
floatingLabel={intl.formatMessage(messages['registration.field.education.levels.label'])}
>
{getOptions().educationLevelOptions}
</Form.Control>
</Form.Group>
)}
{optionalFields.includes('goals') && (
<Form.Group controlId="goals">
<Form.Control
as="textarea"
name="goals"
value={values.goals}
onChange={(e) => onChangeHandler('goals', e.target.value)}
floatingLabel={intl.formatMessage(messages['registration.goals.label'])}
/>
</Form.Group>
)}
</div>
);
};
OptionalFields.propTypes = {
intl: intlShape.isRequired,
optionalFields: PropTypes.arrayOf(PropTypes.string).isRequired,
onChangeHandler: PropTypes.func.isRequired,
values: PropTypes.shape({
gender: PropTypes.string,
goals: PropTypes.string,
levelOfEducation: PropTypes.string,
yearOfBirth: PropTypes.string,
}).isRequired,
};
export default injectIntl(OptionalFields);

View File

@@ -1,6 +1,5 @@
import React from 'react';
import snakeCase from 'lodash.snakecase';
import { connect } from 'react-redux';
import Skeleton from 'react-loading-skeleton';
import { Helmet } from 'react-helmet';
@@ -26,7 +25,6 @@ import {
registrationErrorSelector, registrationRequestSelector, validationsSelector, usernameSuggestionsSelector,
} from './data/selectors';
import messages from './messages';
import OptionalFields from './OptionalFields';
import RegistrationFailure from './RegistrationFailure';
import UsernameField from './UsernameField';
@@ -50,7 +48,6 @@ class RegistrationPage extends React.Component {
constructor(props, context) {
super(props, context);
sendPageEvent('login_and_registration', 'register');
const optionalFields = getConfig().REGISTRATION_OPTIONAL_FIELDS ? getConfig().REGISTRATION_OPTIONAL_FIELDS.split(',') : [];
this.handleOnClose = this.handleOnClose.bind(this);
this.queryParams = getAllPossibleQueryParam();
@@ -73,9 +70,6 @@ class RegistrationPage extends React.Component {
emailWarningSuggestion: null,
errorCode: null,
failureCount: 0,
optionalFields,
optionalFieldsState: {},
showOptionalField: false,
startTime: Date.now(),
totalRegistrationTime: 0,
optimizelyExperimentName: '', // eslint-disable-line react/no-unused-state
@@ -185,27 +179,11 @@ class RegistrationPage extends React.Component {
}
};
getOptionalFields() {
return (
<OptionalFields
optionalFields={this.state.optionalFields}
values={this.state.optionalFieldsState}
onChangeHandler={
(fieldName, value) => {
this.setState(prevState => ({
optionalFieldsState: { ...prevState.optionalFieldsState, [fieldName]: value },
}));
}
}
/>
);
}
handleSubmit = (e) => {
e.preventDefault();
const { startTime } = this.state;
const totalRegistrationTime = (Date.now() - startTime) / 1000;
let payload = {
const payload = {
name: this.state.name,
username: this.state.username,
email: this.state.email,
@@ -232,15 +210,6 @@ class RegistrationPage extends React.Component {
payload.marketing_emails_opt_in = this.state.marketingOptIn;
}
// Since optional fields and query params are not validated we can add it to payload after
// required fields have been validated.
payload = { ...payload, ...this.queryParams };
this.state.optionalFields.forEach((key) => {
if (this.state.optionalFieldsState[key]) {
payload[snakeCase(key)] = this.state.optionalFieldsState[key];
}
});
payload.totalRegistrationTime = totalRegistrationTime;
this.setState({
totalRegistrationTime,
@@ -269,12 +238,7 @@ class RegistrationPage extends React.Component {
}
handleOnChange = (e) => {
if (e.target.name === 'optionalFields') {
sendTrackEvent('edx.bi.user.register.optional_fields_selected', {});
this.setState({
showOptionalField: e.target.checked,
});
} else if (!(e.target.name === 'username' && e.target.value.length > 30)) {
if (!(e.target.name === 'username' && e.target.value.length > 30)) {
this.setState({
[e.target.name]: e.target.value,
});
@@ -692,20 +656,6 @@ class RegistrationPage extends React.Component {
}}
/>
</div>
{getConfig().REGISTRATION_OPTIONAL_FIELDS ? (
<Form.Group className="mb-0 mt-2 small">
<Form.Check
id="optional-field-checkbox"
type="checkbox"
name="optionalFields"
value={this.state.showOptionalField}
onClick={this.handleOnChange}
onChange={this.handleOnChange}
label={intl.formatMessage(messages['support.education.research'])}
/>
</Form.Group>
) : null}
{ this.state.showOptionalField ? this.getOptionalFields() : null }
<StatefulButton
type="submit"
variant="brand"

View File

@@ -34,7 +34,6 @@ const mockStore = configureStore();
describe('RegistrationPage', () => {
mergeConfig({
PRIVACY_POLICY: 'http://privacy-policy.com',
REGISTRATION_OPTIONAL_FIELDS: 'gender,goals,levelOfEducation,yearOfBirth',
TOS_AND_HONOR_CODE: 'http://tos-and-honot-code.com',
USER_SURVEY_COOKIE_NAME: process.env.USER_SURVEY_COOKIE_NAME,
REGISTER_CONVERSION_COOKIE_NAME: process.env.REGISTER_CONVERSION_COOKIE_NAME,
@@ -774,86 +773,4 @@ describe('RegistrationPage', () => {
});
});
});
describe('TestOptionalFields', () => {
it('should toggle optional fields state', () => {
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#optional-field-checkbox').simulate('click', { target: { name: 'optionalFields', checked: true } });
expect(registrationPage.find('RegistrationPage').state('showOptionalField')).toEqual(true);
// it should also works when change is made directly instead of click
registrationPage.find('input#optional-field-checkbox').simulate('change', { target: { name: 'optionalFields', checked: false } });
expect(registrationPage.find('RegistrationPage').state('showOptionalField')).toEqual(false);
});
it('should show optional fields section on optional check enabled', () => {
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#optional-field-checkbox').simulate('change', { target: { name: 'optionalFields', checked: true } });
registrationPage.update();
expect(registrationPage.find('textarea#goals').length).toEqual(1);
expect(registrationPage.find('select#levelOfEducation').length).toEqual(1);
expect(registrationPage.find('select#yearOfBirth').length).toEqual(1);
expect(registrationPage.find('select#gender').length).toEqual(1);
});
it('should show optional field check based on environment variable', () => {
mergeConfig({
REGISTRATION_OPTIONAL_FIELDS: '',
});
let registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('input#optional-field-checkbox').length).toEqual(0);
mergeConfig({
REGISTRATION_OPTIONAL_FIELDS: 'gender,goals,levelOfEducation,yearOfBirth',
});
registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('input#optional-field-checkbox').length).toEqual(1);
});
it('send tracking event on optional checkbox enabled', () => {
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#optional-field-checkbox').simulate('change', { target: { name: 'optionalFields', checked: true } });
expect(analytics.sendTrackEvent).toHaveBeenCalledWith('edx.bi.user.register.optional_fields_selected', {});
});
it('should submit form with optional fields', () => {
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
const payload = {
name: 'John Doe',
username: 'john_doe',
email: 'john.doe@example.com',
password: 'password1',
country: 'Pakistan',
gender: 'm',
year_of_birth: '1997',
level_of_education: 'other',
goals: 'edX goals',
honor_code: true,
totalRegistrationTime: 0,
is_authn_mfe: true,
};
store.dispatch = jest.fn(store.dispatch);
delete window.location;
window.location = { href: getConfig().BASE_URL };
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
populateRequiredFields(registerPage, payload);
// submit optional fields
registerPage.find('input#optional-field-checkbox').simulate('change', { target: { name: 'optionalFields', checked: true } });
registerPage.find('select#gender').simulate('change', { target: { value: 'm', name: 'gender' } });
registerPage.find('select#yearOfBirth').simulate('change', { target: { value: '1997', name: 'yearOfBirth' } });
registerPage.find('select#levelOfEducation').simulate('change', { target: { value: 'other', name: 'levelOfEducation' } });
registerPage.find('textarea#goals').simulate('change', { target: { value: 'edX goals', name: 'goals' } });
registerPage.find('button.btn-brand').simulate('click');
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload, country: 'PK' }));
});
});
});