make registration form static (#147)

- removed fetch registration call from register page
- removed unused state variables
- moved few hardcoded links to env variables

VAN-369
This commit is contained in:
Zainab Amir
2021-02-18 15:36:05 +05:00
committed by GitHub
parent f210c030d8
commit dea1f7d335
16 changed files with 4385 additions and 872 deletions

1
.env
View File

@@ -16,3 +16,4 @@ SITE_NAME=null
USER_INFO_COOKIE_NAME=null
AUTHN_MINIMAL_HEADER=true
LOGIN_ISSUE_SUPPORT_LINK=null
REGISTRATION_OPTIONAL_FIELDS=''

View File

@@ -21,3 +21,6 @@ SITE_NAME='edX'
USER_INFO_COOKIE_NAME='edx-user-info'
AUTHN_MINIMAL_HEADER=true
LOGIN_ISSUE_SUPPORT_LINK=''
TOS_AND_HONOR_CODE='http://localhost:18000/honor'
PRIVACY_POLICY='http://localhost:18000/privacy'
REGISTRATION_OPTIONAL_FIELDS='gender goals level_of_education year_of_birth'

View File

@@ -18,21 +18,7 @@ export const DEFAULT_STATE = 'default';
export const PENDING_STATE = 'pending';
export const COMPLETE_STATE = 'complete';
export const REGISTRATION_VALIDITY_MAP = {};
export const REGISTRATION_OPTIONAL_MAP = {};
export const REGISTRATION_EXTRA_FIELDS = [
'confirm_email',
'level_of_education',
'gender',
'year_of_birth',
'mailing_address',
'goals',
'honor_code',
'terms_of_service',
'city',
'country',
];
// Regex
export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+)*'
+ '|^"([\\001-\\010\\013\\014\\016-\\037!#-\\[\\]-\\177]|\\\\[\\001-\\011\\013\\014\\016-\\177])*"'
+ ')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+)(?:[A-Z0-9-]{2,63})'

View File

@@ -61,6 +61,9 @@ initialize({
LOGIN_ISSUE_SUPPORT_LINK: process.env.LOGIN_ISSUE_SUPPORT_LINK || null,
ACTIVATION_EMAIL_SUPPORT_LINK: process.env.ACTIVATION_EMAIL_SUPPORT_LINK || null,
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 || '',
});
},
},

View File

@@ -0,0 +1,89 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { EDUCATION_LEVELS, GENDER_OPTIONS, YEAR_OF_BIRTH_OPTIONS } from './data/constants';
import messages from './messages';
import { AuthnValidationFormGroup } from '../common-components';
const OptionalFields = (props) => {
const { intl, onChangeHandler, values } = props;
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'}`]),
})),
});
return (
<>
<AuthnValidationFormGroup
label={intl.formatMessage(messages['registration.field.gender.options.label'])}
for="gender"
name="gender"
type="select"
key="gender"
value={values.gender}
className="mb-20 opt-inline-field"
onChange={(e) => onChangeHandler('gender', e.target.value)}
selectOptions={getOptions().genderOptions}
/>
<AuthnValidationFormGroup
label={intl.formatMessage(messages['registration.year.of.birth.label'])}
for="yearOfBirth"
name="yearOfBirth"
type="select"
key="yearOfBirth"
value={values.yearOfBirth}
className="mb-20 opt-inline-field opt-year-field"
onChange={(e) => onChangeHandler('yearOfBirth', e.target.value)}
selectOptions={getOptions().yearOfBirthOptions}
/>
<AuthnValidationFormGroup
label={intl.formatMessage(messages['registration.field.education.levels.label'])}
for="levelOfEducation"
name="levelOfEducation"
type="select"
key="levelOfEducation"
value={values.levelOfEducation}
className="mb-20"
onChange={(e) => onChangeHandler('levelOfEducation', e.target.value)}
selectOptions={getOptions().educationLevelOptions}
/>
<AuthnValidationFormGroup
label={intl.formatMessage(messages['registration.goals.label'])}
for="goals"
name="goals"
type="textarea"
key="goals"
value={values.goals}
className="mb-20"
onChange={(e) => onChangeHandler('goals', e.target.value)}
/>
</>
);
};
OptionalFields.propTypes = {
intl: intlShape.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

@@ -44,7 +44,7 @@ const RegistrationFailureMessage = (props) => {
return (
!userErrors.length ? null : (
<Alert variant="danger">
<Alert id="validation-errors" variant="danger">
<Alert.Heading>
{props.intl.formatMessage(messages['registration.request.failure.header'])}
</Alert.Heading>

View File

@@ -1,49 +1,36 @@
import React from 'react';
import camelCase from 'lodash.camelcase';
import { connect } from 'react-redux';
import Skeleton from 'react-loading-skeleton';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
import {
Input,
StatefulButton,
Hyperlink,
ValidationFormGroup,
Form,
} from '@edx/paragon';
import {
injectIntl, intlShape,
injectIntl, intlShape, getCountryList, getLocale, FormattedMessage,
} from '@edx/frontend-platform/i18n';
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
import { Form, Hyperlink, StatefulButton } from '@edx/paragon';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import camelCase from 'lodash.camelcase';
import { getThirdPartyAuthContext } from '../common-components/data/actions';
import {
registerNewUser,
fetchRegistrationForm,
fetchRealtimeValidations,
} from './data/actions';
import { registerNewUser, fetchRealtimeValidations } from './data/actions';
import { registrationRequestSelector } from './data/selectors';
import { thirdPartyAuthContextSelector } from '../common-components/data/selectors';
import messages from './messages';
import OptionalFields from './OptionalFields';
import RegistrationFailure from './RegistrationFailure';
import {
RedirectLogistration, SocialAuthProviders, ThirdPartyAuthAlert, RenderInstitutionButton,
InstitutionLogistration, AuthnValidationFormGroup,
} from '../common-components';
import RegistrationFailure from './RegistrationFailure';
import { getThirdPartyAuthContext } from '../common-components/data/actions';
import { thirdPartyAuthContextSelector } from '../common-components/data/selectors';
import EnterpriseSSO from '../common-components/EnterpriseSSO';
import {
DEFAULT_REDIRECT_URL,
DEFAULT_STATE,
PENDING_STATE,
LOGIN_PAGE,
REGISTER_PAGE,
REGISTRATION_VALIDITY_MAP,
REGISTRATION_OPTIONAL_MAP,
REGISTRATION_EXTRA_FIELDS,
DEFAULT_REDIRECT_URL, DEFAULT_STATE, LOGIN_PAGE, PENDING_STATE, REGISTER_PAGE,
} from '../data/constants';
import messages from './messages';
import processLink, { getTpaProvider } from '../data/utils';
import { getTpaProvider } from '../data/utils';
class RegistrationPage extends React.Component {
constructor(props, context) {
@@ -58,17 +45,11 @@ class RegistrationPage extends React.Component {
username: '',
password: '',
country: '',
city: '',
gender: '',
yearOfBirth: '',
mailingAddress: '',
goals: '',
honorCode: true,
termsOfService: true,
levelOfEducation: '',
confirmEmail: '',
enableOptionalField: false,
validationFieldName: '',
validationErrorsAlertMessages: {
name: [{ user_message: '' }],
username: [{ user_message: '' }],
@@ -84,16 +65,7 @@ class RegistrationPage extends React.Component {
username: '',
password: '',
country: '',
honorCode: '',
termsOfService: '',
},
emailValid: false,
nameValid: false,
usernameValid: false,
passwordValid: false,
countryValid: false,
honorCodeValid: true,
termsOfServiceValid: false,
institutionLogin: false,
formValid: false,
assignRegistrationErrorsToField: true,
@@ -111,7 +83,6 @@ class RegistrationPage extends React.Component {
payload.tpa_hint = tpaHint;
}
this.props.getThirdPartyAuthContext(payload);
this.props.fetchRegistrationForm();
}
shouldComponentUpdate(nextProps) {
@@ -120,11 +91,9 @@ class RegistrationPage extends React.Component {
const { fieldName } = nextProps.validations.validation_decisions;
const errorMsg = nextProps.validations.validation_decisions[fieldName];
errors[fieldName] = errorMsg;
const stateValidKey = `${camelCase(fieldName)}Valid`;
const currentValidations = nextProps.validations.validation_decisions;
this.setState({
[stateValidKey]: !errorMsg,
errors,
currentValidations,
});
@@ -147,6 +116,29 @@ class RegistrationPage extends React.Component {
return true;
}
getCountryOptions = () => {
const { intl } = this.props;
return [{
value: '',
label: intl.formatMessage(messages['registration.country.label']),
}].concat(getCountryList(getLocale()).map(({ code, name }) => ({ value: code, label: name })));
}
getOptionalFields() {
const values = {};
const optionalFields = getConfig().REGISTRATION_OPTIONAL_FIELDS.split(' ');
optionalFields.forEach((key) => {
values[camelCase(key)] = this.state[camelCase(key)];
});
return (
<OptionalFields
values={values}
onChangeHandler={(fieldName, value) => { this.setState({ [fieldName]: value }); }}
/>
);
}
handleInstitutionLogin = () => {
this.setState(prevState => ({ institutionLogin: !prevState.institutionLogin }));
}
@@ -154,24 +146,18 @@ class RegistrationPage extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
const params = (new URL(document.location)).searchParams;
const payload = {};
const payloadMap = new Map();
payloadMap.set('name', this.state.name);
payloadMap.set('username', this.state.username);
payloadMap.set('email', this.state.email);
const payload = {
name: this.state.name,
username: this.state.username,
email: this.state.email,
country: this.state.country,
honor_code: true,
};
if (!this.props.thirdPartyAuthContext.currentProvider) {
payloadMap.set('password', this.state.password);
payload.password = this.state.password;
}
const fieldMap = { ...REGISTRATION_VALIDITY_MAP, ...REGISTRATION_OPTIONAL_MAP };
Object.entries(fieldMap).forEach(([key, value]) => {
if (value) {
payloadMap.set(key, this.state[camelCase(key)]);
}
});
payloadMap.forEach((value, key) => { payload[key] = value; });
const next = params.get('next');
const courseId = params.get('course_id');
if (next) {
@@ -181,16 +167,21 @@ class RegistrationPage extends React.Component {
payload.course_id = courseId;
}
let finalValidation = this.isFormValid();
if (!this.isFormValid()) {
// Special case where honor code and tos is a single field, true by default. We don't need
// to validate this field
payloadMap.forEach((value, key) => {
if (key !== 'honor_code' || 'terms_of_service' in REGISTRATION_VALIDITY_MAP) {
finalValidation = this.validateInput(key, value);
}
let finalValidation = this.state.formValid;
if (!this.state.formValid) {
Object.keys(payload).forEach(key => {
finalValidation = this.validateInput(key, payload[key]);
});
}
// Since optional fields are not validated we can add it to payload after required fields
// have been validated. This will save us unwanted calls to validateInput()
const optionalFields = getConfig().REGISTRATION_OPTIONAL_FIELDS.split(' ');
optionalFields.forEach((key) => {
const stateKey = camelCase(key);
if (this.state[stateKey]) {
payload[key] = this.state[stateKey];
}
});
if (finalValidation) {
this.props.registerNewUser(payload);
} else {
@@ -199,18 +190,13 @@ class RegistrationPage extends React.Component {
}
checkNoValidationsErrors(validations) {
let keyValidList = null;
keyValidList = Object.entries(validations).map(([key]) => {
const keyValidList = Object.entries(validations).map(([key]) => {
const validation = validations[key][0];
return !validation.user_message;
});
return keyValidList.every((current) => current === true);
}
isFormValid() {
return this.state.formValid;
}
handleOnBlur(e) {
const { name, value } = e.target;
if (this.props.statusCode === 403) {
@@ -227,24 +213,16 @@ class RegistrationPage extends React.Component {
username: this.state.username,
password: this.state.password,
name: this.state.name,
honor_code: this.state.honorCode,
honor_code: true,
country: this.state.country,
};
this.setState({
validationFieldName: e.target.name,
assignRegistrationErrorsToField: false,
});
this.props.fetchRealtimeValidations(payload);
}
handleOnChange(e) {
const targetValue = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
this.setState({
[camelCase(e.target.name)]: targetValue,
});
}
handleOnOptional(e) {
const optionalEnable = this.state.enableOptionalField;
const targetValue = e.target.id === 'additionalFields' ? !optionalEnable : e.target.checked;
@@ -254,19 +232,6 @@ class RegistrationPage extends React.Component {
sendTrackEvent('edx.bi.user.register.optional_fields_selected', {});
}
handleOnClick(e) {
if (this.state.currentValidations && this.props.statusCode !== 403) {
const { errors } = this.state;
const fieldName = e.target.name;
errors[fieldName] = this.state.currentValidations[fieldName];
const stateValidKey = `${camelCase(fieldName)}Valid`;
this.setState(prevState => ({
[stateValidKey]: !prevState.currentValidations[fieldName],
errors,
}));
}
}
handleLoginLinkClickEvent() {
sendTrackEvent('edx.bi.login_form.toggled', { category: 'user-engagement' });
}
@@ -277,12 +242,7 @@ class RegistrationPage extends React.Component {
validationErrorsAlertMessages,
} = this.state;
let {
honorCodeValid,
termsOfServiceValid,
formValid,
assignRegistrationErrorsToField,
} = this.state;
let { formValid, assignRegistrationErrorsToField } = this.state;
const validations = this.state.currentValidations;
switch (inputName) {
case 'email':
@@ -385,14 +345,6 @@ class RegistrationPage extends React.Component {
errors.country = emptyError[0].user_message;
}
break;
case 'honor_code':
honorCodeValid = value !== false;
errors.honorCode = honorCodeValid ? '' : null;
break;
case 'terms_of_service':
termsOfServiceValid = value !== false;
errors.termsOfService = termsOfServiceValid ? '' : null;
break;
default:
break;
}
@@ -404,179 +356,12 @@ class RegistrationPage extends React.Component {
this.setState({
formValid,
validationErrorsAlertMessages,
honorCodeValid,
termsOfServiceValid,
assignRegistrationErrorsToField,
errors,
});
return formValid;
}
addExtraRequiredFields() {
const fields = this.props.formData.fields.map((field) => {
let options = null;
if (REGISTRATION_EXTRA_FIELDS.includes(field.name)) {
if (field.required) {
const stateVar = camelCase(field.name);
let beforeLink;
let link;
let linkText;
let afterLink;
const props = {
id: field.name,
name: field.name,
type: field.type,
value: this.state[stateVar],
required: true,
onChange: e => this.handleOnChange(e),
};
REGISTRATION_VALIDITY_MAP[field.name] = true;
if (field.type === 'plaintext' && field.name === 'honor_code') { // special case where honor code and tos are combined
afterLink = field.label;
props.type = 'hidden';
const nodes = [];
do {
const matches = processLink(afterLink);
[beforeLink, link, linkText, afterLink] = matches;
nodes.push(
<React.Fragment key={link}>
{beforeLink}
<Hyperlink destination={link}>{linkText}</Hyperlink>
</React.Fragment>,
);
} while (afterLink.includes('a href'));
nodes.push(<React.Fragment key={afterLink}>{afterLink}</React.Fragment>);
return (
<React.Fragment key={field.type}>
<input {...props} />
<ValidationFormGroup
for={field.name}
key={field.name}
className="pt-10 small mb-0"
>
{ nodes }
</ValidationFormGroup>
</React.Fragment>
);
}
if (field.type === 'checkbox') {
const matches = processLink(field.label);
[beforeLink, link, linkText, afterLink] = matches;
props.checked = this.state[stateVar];
return (
<ValidationFormGroup
for={field.name}
key={field.name}
invalid={this.state.errors[stateVar] !== ''}
invalidMessage={field.errorMessages.required}
className="custom-control small"
>
<Input {...props} />
{beforeLink}
<Hyperlink destination={link}>{linkText}</Hyperlink>
{afterLink}
</ValidationFormGroup>
);
}
if (field.type === 'select') {
options = field.options.map((item) => {
const option = {};
option.value = item.value;
option.label = item.name;
if (item.name === '--') {
option.label = `${field.label} (required)`;
option.disabled = true;
}
return option;
});
props.options = options;
}
return (
<AuthnValidationFormGroup
label={`${field.label} (required)`}
for={field.name}
name={field.name}
type={field.type}
key={field.name}
invalid={this.state.errors[stateVar] !== ''}
invalidMessage={field.errorMessages.required}
className="mb-0"
value={props.value}
onClick={(e) => this.handleOnClick(e)}
onBlur={(e) => this.handleOnBlur(e)}
onChange={(e) => this.handleOnChange(e)}
selectOptions={props.options}
/>
);
}
}
return null;
});
return fields;
}
addExtraOptionalFields() {
const fields = this.props.formData.fields.map((field) => {
let options = null;
let cssClass = 'mb-20';
if (REGISTRATION_EXTRA_FIELDS.includes(field.name)) {
if (!field.required && field.name !== 'honor_code' && field.name !== 'country') {
REGISTRATION_OPTIONAL_MAP[field.name] = true;
const stateVar = camelCase(field.name);
const props = {
id: field.name,
name: field.name,
type: field.type,
onChange: e => this.handleOnChange(e),
value: this.state[stateVar],
};
if (field.type === 'select') {
options = field.options.map((item) => {
const option = {};
option.value = item.value;
option.label = item.name;
if (item.name === '--') {
option.label = `${field.label} (optional)`;
option.disabled = true;
}
return option;
});
props.options = options;
}
if (field.name === 'gender') {
cssClass += ' opt-inline-field';
}
if (field.name === 'year_of_birth') {
cssClass += ' opt-inline-field opt-year-field';
}
return (
<AuthnValidationFormGroup
label={`${field.label} (optional)`}
for={field.name}
name={field.name}
type={field.type}
key={field.name}
value={props.value}
className={cssClass}
onClick={(e) => this.handleOnClick(e)}
onChange={(e) => this.handleOnChange(e)}
selectOptions={props.options}
/>
);
}
}
return null;
});
return fields;
}
generateUserMessage(isFieldInValid, messageID) {
return [{ user_message: isFieldInValid ? this.intl.formatMessage(messages[messageID]) : '' }];
}
@@ -701,9 +486,8 @@ class RegistrationPage extends React.Component {
invalid={this.state.errors.name !== ''}
invalidMessage={this.state.errors.name}
value={this.state.name}
onClick={(e) => this.handleOnClick(e)}
onBlur={(e) => this.handleOnBlur(e)}
onChange={(e) => this.handleOnChange(e)}
onChange={(e) => this.setState({ name: e.target.value })}
helpText={intl.formatMessage(messages['helptext.name'])}
/>
<AuthnValidationFormGroup
@@ -714,9 +498,8 @@ class RegistrationPage extends React.Component {
invalid={this.state.errors.username !== ''}
invalidMessage={this.state.errors.username}
value={this.state.username}
onClick={(e) => this.handleOnClick(e)}
onBlur={(e) => this.handleOnBlur(e)}
onChange={(e) => this.handleOnChange(e)}
onChange={(e) => this.setState({ username: e.target.value })}
helpText={intl.formatMessage(messages['helptext.username'])}
/>
<AuthnValidationFormGroup
@@ -727,9 +510,8 @@ class RegistrationPage extends React.Component {
invalid={this.state.errors.email !== ''}
invalidMessage={this.state.errors.email}
value={this.state.email}
onClick={(e) => this.handleOnClick(e)}
onBlur={(e) => this.handleOnBlur(e)}
onChange={(e) => this.handleOnChange(e)}
onChange={(e) => this.setState({ email: e.target.value })}
helpText={intl.formatMessage(messages['helptext.email'])}
/>
{!currentProvider && (
@@ -741,19 +523,51 @@ class RegistrationPage extends React.Component {
invalid={this.state.errors.password !== ''}
invalidMessage={this.state.errors.password}
value={this.state.password}
onClick={(e) => this.handleOnClick(e)}
onBlur={(e) => this.handleOnBlur(e)}
onChange={(e) => this.handleOnChange(e)}
onChange={(e) => this.setState({ password: e.target.value })}
helpText={intl.formatMessage(messages['helptext.password'])}
/>
)}
{ this.addExtraRequiredFields() }
<AuthnValidationFormGroup
label={intl.formatMessage(messages['registration.country.label'])}
for="country"
name="country"
type="select"
key="country"
invalid={this.state.errors.country !== ''}
invalidMessage={intl.formatMessage(messages['country.validation.message'])}
className="mb-0"
value={this.state.country}
onBlur={(e) => this.handleOnBlur(e)}
onChange={(e) => this.setState({ country: e.target.value })}
selectOptions={this.getCountryOptions()}
/>
<div id="honor-code" className="pt-10 small">
<FormattedMessage
id="register.page.terms.of.service.and.honor.code"
defaultMessage="By creating an account, you agree to the {tosAndHonorCode} and you acknowledge that {platformName} and each
Member process your personal data in accordance with the {privacyPolicy}."
description="Text that appears on registration form stating honor code and privacy policy"
values={{
platformName: this.state.platformName,
tosAndHonorCode: (
<Hyperlink destination={getConfig().TOS_AND_HONOR_CODE} rel="noopener" target="_blank">
{intl.formatMessage(messages['terms.of.service.and.honor.code'])}
</Hyperlink>
),
privacyPolicy: (
<Hyperlink destination={getConfig().PRIVACY_POLICY} rel="noopener" target="_blank">
{intl.formatMessage(messages['privacy.policy'])}
</Hyperlink>
),
}}
/>
</div>
<AuthnValidationFormGroup
label=""
for="optional"
name="optional"
type="checkbox"
invalidMessage=""
value={this.state.enableOptionalField}
onClick={(e) => this.handleOnOptional(e)}
onBlur={null}
@@ -762,7 +576,7 @@ class RegistrationPage extends React.Component {
isChecked={this.state.enableOptionalField}
checkboxMessage={intl.formatMessage(messages['support.education.research'])}
/>
{ this.state.enableOptionalField ? this.addExtraOptionalFields() : null}
{ this.state.enableOptionalField ? this.getOptionalFields() : null}
<StatefulButton
type="submit"
variant="brand"
@@ -779,7 +593,7 @@ class RegistrationPage extends React.Component {
&& !currentProvider ? (
<div className="d-block mb-4 mt-4">
<hr className="mt-0 border-gray-200" />
<span className="d-blockmb-4 text-left">
<span className="d-block mb-4 text-left">
{intl.formatMessage(messages['create.an.account.using'])}
</span>
</div>
@@ -803,10 +617,6 @@ class RegistrationPage extends React.Component {
currentProvider, finishAuthUrl, providers, secondaryProviders,
} = this.props.thirdPartyAuthContext;
if (!this.props.formData) {
return <div />;
}
const params = (new URL(window.location.href)).searchParams;
const tpaHint = params.get('tpa_hint');
@@ -816,21 +626,25 @@ class RegistrationPage extends React.Component {
}
const provider = getTpaProvider(tpaHint, providers, secondaryProviders);
return provider ? (<EnterpriseSSO provider={provider} intl={intl} />)
: this.renderForm(currentProvider,
: this.renderForm(
currentProvider,
providers,
secondaryProviders,
thirdPartyAuthApiStatus,
finishAuthUrl,
submitState,
intl);
intl,
);
}
return this.renderForm(currentProvider,
return this.renderForm(
currentProvider,
providers,
secondaryProviders,
thirdPartyAuthApiStatus,
finishAuthUrl,
submitState,
intl);
intl,
);
}
}
@@ -847,7 +661,6 @@ RegistrationPage.defaultProps = {
secondaryProviders: [],
pipelineUserDetails: null,
},
formData: null,
validations: null,
statusCode: null,
};
@@ -883,11 +696,6 @@ RegistrationPage.propTypes = {
username: PropTypes.string,
}),
}),
fetchRegistrationForm: PropTypes.func.isRequired,
formData: PropTypes.shape({
fields: PropTypes.array,
}),
fetchRealtimeValidations: PropTypes.func.isRequired,
validations: PropTypes.shape({
validation_decisions: PropTypes.shape({
@@ -911,7 +719,6 @@ const mapStateToProps = state => {
thirdPartyAuthApiStatus: state.commonComponents.thirdPartyAuthApiStatus,
registrationResult,
thirdPartyAuthContext,
formData: state.register.formData,
validations: state.register.validations,
statusCode: state.register.statusCode,
};
@@ -921,7 +728,6 @@ export default connect(
mapStateToProps,
{
getThirdPartyAuthContext,
fetchRegistrationForm,
fetchRealtimeValidations,
registerNewUser,
},

View File

@@ -26,24 +26,6 @@ export const registerNewUserFailure = (error) => ({
payload: { error },
});
// Registration Form Fields
export const fetchRegistrationForm = () => ({
type: REGISTER_FORM.BASE,
});
export const fetchRegistrationFormBegin = () => ({
type: REGISTER_FORM.BEGIN,
});
export const fetchRegistrationFormSuccess = (formData) => ({
type: REGISTER_FORM.SUCCESS,
payload: { formData },
});
export const fetchRegistrationFormFailure = () => ({
type: REGISTER_FORM.FAILURE,
});
// Realtime Field validations
export const fetchRealtimeValidations = (formPayload) => ({
type: REGISTER_FORM_VALIDATIONS.BASE,

View File

@@ -0,0 +1,26 @@
export const YEAR_OF_BIRTH_OPTIONS = (() => {
const currentYear = new Date().getFullYear();
const years = [];
let startYear = currentYear - 120;
while (startYear < currentYear) {
startYear += 1;
years.push({ value: startYear.toString(), label: startYear });
}
return years.reverse();
})();
export const EDUCATION_LEVELS = [
'',
'p',
'm',
'b',
'a',
'hs',
'jhs',
'el',
'none',
'o',
];
export const GENDER_OPTIONS = ['', 'f', 'm', 'o'];

View File

@@ -1,8 +1,4 @@
import {
REGISTER_NEW_USER,
REGISTER_FORM,
REGISTER_FORM_VALIDATIONS,
} from './actions';
import { REGISTER_NEW_USER, REGISTER_FORM_VALIDATIONS } from './actions';
import { DEFAULT_STATE, PENDING_STATE } from '../../data/constants';
@@ -32,19 +28,6 @@ const reducer = (state = defaultState, action) => {
registrationError: action.payload.error,
submitState: DEFAULT_STATE,
};
case REGISTER_FORM.BEGIN:
return {
...state,
};
case REGISTER_FORM.SUCCESS:
return {
...state,
formData: action.payload.formData,
};
case REGISTER_FORM.FAILURE:
return {
...state,
};
case REGISTER_FORM_VALIDATIONS.BEGIN:
return {
...state,

View File

@@ -12,18 +12,10 @@ import {
fetchRealtimeValidationsBegin,
fetchRealtimeValidationsSuccess,
fetchRealtimeValidationsFailure,
REGISTER_FORM,
fetchRegistrationFormBegin,
fetchRegistrationFormSuccess,
fetchRegistrationFormFailure,
} from './actions';
// Services
import {
getFieldsValidations,
getRegistrationForm,
registerRequest,
} from './service';
import { getFieldsValidations, registerRequest } from './service';
import { INTERNAL_SERVER_ERROR } from '../../login/data/constants';
export function* handleNewUserRegistration(action) {
@@ -47,20 +39,6 @@ export function* handleNewUserRegistration(action) {
}
}
export function* fetchRegistrationForm() {
try {
yield put(fetchRegistrationFormBegin());
const { registrationForm } = yield call(getRegistrationForm);
yield put(fetchRegistrationFormSuccess(
registrationForm,
));
} catch (e) {
yield put(fetchRegistrationFormFailure());
logError(e);
}
}
export function* fetchRealtimeValidations(action) {
try {
yield put(fetchRealtimeValidationsBegin());
@@ -80,6 +58,5 @@ export function* fetchRealtimeValidations(action) {
export default function* saga() {
yield takeEvery(REGISTER_NEW_USER.BASE, handleNewUserRegistration);
yield takeEvery(REGISTER_FORM.BASE, fetchRegistrationForm);
yield takeEvery(REGISTER_FORM_VALIDATIONS.BASE, fetchRealtimeValidations);
}

View File

@@ -24,26 +24,6 @@ export async function registerRequest(registrationInformation) {
};
}
export async function getRegistrationForm() {
const requestConfig = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
isPublic: true,
};
const { data } = await getAuthenticatedHttpClient()
.get(
`${getConfig().LMS_BASE_URL}/user_api/v2/account/registration/`,
requestConfig,
)
.catch((e) => {
throw (e);
});
return {
registrationForm: data,
};
}
export async function getFieldsValidations(formPayload) {
const requestConfig = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },

View File

@@ -4,7 +4,6 @@ import { camelCaseObject } from '@edx/frontend-platform';
import * as actions from '../actions';
import {
fetchRealtimeValidations,
fetchRegistrationForm,
handleNewUserRegistration,
} from '../sagas';
import * as api from '../service';
@@ -12,70 +11,6 @@ import initializeMockLogging from '../../../setupTest';
const { loggingService } = initializeMockLogging();
describe('fetchRegistrationForm', () => {
const data = {
fields: [{
label: 'City',
name: 'city',
type: 'text',
errorMessages: {
required: 'invalid city',
},
required: true,
},
{
label: 'I agree to the Your Platform Name Here <a href="/honor" rel="noopener" target="_blank">Honor Code</a>',
name: 'honor_code',
type: 'checkbox',
errorMessages: {
required: 'invalid honor code',
},
required: true,
}],
};
beforeEach(() => {
loggingService.logError.mockReset();
});
it('should call service and dispatch success action', async () => {
const getRegistrationForm = jest.spyOn(api, 'getRegistrationForm')
.mockImplementation(() => Promise.resolve({ registrationForm: data }));
const dispatched = [];
await runSaga(
{ dispatch: (action) => dispatched.push(action) },
fetchRegistrationForm,
);
expect(getRegistrationForm).toHaveBeenCalledTimes(1);
expect(dispatched).toEqual([
actions.fetchRegistrationFormBegin(),
actions.fetchRegistrationFormSuccess(data),
]);
getRegistrationForm.mockClear();
});
it('should call service and dispatch error action', async () => {
const getRegistrationForm = jest.spyOn(api, 'getRegistrationForm')
.mockImplementation(() => Promise.reject(new Error('something went wrong')));
const dispatched = [];
await runSaga(
{ dispatch: (action) => dispatched.push(action) },
fetchRegistrationForm,
);
expect(getRegistrationForm).toHaveBeenCalledTimes(1);
expect(loggingService.logError).toHaveBeenCalled();
expect(dispatched).toEqual([
actions.fetchRegistrationFormBegin(),
actions.fetchRegistrationFormFailure(),
]);
getRegistrationForm.mockClear();
});
});
describe('fetchRealtimeValidations', () => {
const params = {
payload: {

View File

@@ -161,6 +161,103 @@ const messages = defineMessages({
defaultMessage: 'This is what you will use to login.',
description: '',
},
// Terms of Service and Honor Code
'terms.of.service.and.honor.code': {
id: 'terms.of.service.and.honor.code',
defaultMessage: 'Terms of Service and Honor Code',
description: 'Text for the hyperlink that redirects user to terms of service and honor code',
},
'privacy.policy': {
id: 'privacy.policy',
defaultMessage: 'Privacy Policy',
description: 'Text for the hyperlink that redirects user to privacy policy',
},
// Registration Fields
'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',
},
'registration.country.label': {
id: 'registration.country.label',
defaultMessage: 'Country or Region of Residence (required)',
description: 'Placeholder for the country options dropdown.',
},
'registration.field.gender.options.label': {
id: 'registration.field.gender.options.label',
defaultMessage: 'Gender (optional)',
description: 'Placeholder for the gender options dropdown',
},
'registration.goals.label': {
id: 'registration.goals.label',
defaultMessage: 'Tell us why you\'re interested in edX (optional)',
description: 'Placeholder for the goals 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.o': {
id: 'registration.field.education.levels.o',
defaultMessage: 'Other education',
description: 'Selected by the user if they have a type of education not described by the other choices.',
},
});
export default messages;

View File

@@ -3,7 +3,7 @@ import { Provider } from 'react-redux';
import renderer from 'react-test-renderer';
import { mount } from 'enzyme';
import configureStore from 'redux-mock-store';
import { getConfig } from '@edx/frontend-platform';
import { getConfig, mergeConfig } from '@edx/frontend-platform';
import { IntlProvider, injectIntl, configure } from '@edx/frontend-platform/i18n';
import * as analytics from '@edx/frontend-platform/analytics';
import CookiePolicyBanner from '@edx/frontend-component-cookie-policy-banner';
@@ -13,7 +13,7 @@ import { RenderInstitutionButton } from '../../common-components';
import RegistrationFailureMessage from '../RegistrationFailure';
import { COMPLETE_STATE, PENDING_STATE } from '../../data/constants';
import { INTERNAL_SERVER_ERROR } from '../../login/data/constants';
import { fetchRegistrationForm, fetchRealtimeValidations, registerNewUser } from '../data/actions';
import { fetchRealtimeValidations, registerNewUser } from '../data/actions';
jest.mock('@edx/frontend-platform/analytics');
@@ -24,22 +24,17 @@ const IntlRegistrationPage = injectIntl(RegistrationPage);
const IntlRegistrationFailure = injectIntl(RegistrationFailureMessage);
const mockStore = configureStore();
describe('./RegistrationPage.js', () => {
describe('RegistrationPageTests', () => {
mergeConfig({
PRIVACY_POLICY: 'http://privacy-policy.com',
REGISTRATION_OPTIONAL_FIELDS: 'gender goals level_of_education year_of_birth',
TOS_AND_HONOR_CODE: 'http://tos-and-honot-code.com',
});
const initialState = {
register: {
registrationResult: { success: false, redirectUrl: '' },
registrationError: null,
formData: {
fields: [{
label: 'I agree to the Your Platform Name Here <a href="/honor" rel="noopener" target="_blank">Honor Code</a>',
name: 'honor_code',
type: 'checkbox',
errorMessages: {
required: 'You must agree to the Your Platform Name Here Honor Code',
},
required: true,
}],
},
},
commonComponents: {
thirdPartyAuthApiStatus: null,
@@ -71,6 +66,14 @@ describe('./RegistrationPage.js', () => {
registerUrl: '/dummy_auth',
};
const emptyFieldValidation = {
name: 'Please enter your Full Name.',
username: 'Please enter your Public Username.',
email: 'Please enter your Email.',
password: 'Please enter your Password.',
country: 'Select your country or region of residence.',
};
const reduxWrapper = children => (
<IntlProvider locale="en">
<Provider store={store}>{children}</Provider>
@@ -85,11 +88,7 @@ describe('./RegistrationPage.js', () => {
ENVIRONMENT: 'production',
LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum',
},
messages: {
'es-419': {},
de: {},
'en-us': {},
},
messages: { 'es-419': {}, de: {}, 'en-us': {} },
});
props = {
registrationResult: jest.fn(),
@@ -100,43 +99,6 @@ describe('./RegistrationPage.js', () => {
jest.clearAllMocks();
});
it('should show error messages on invalid extra fields', () => {
const validationMessage = {
honorCode: 'You must agree to the Your Platform Name Here Honor Code',
country: 'Select your country or region of residence.',
};
store = mockStore({
...initialState,
register: {
...initialState.register,
formData: {
fields: [
...initialState.register.formData.fields,
{
label: 'The country or region where you live.',
name: 'country',
type: 'select',
options: [{ value: '', name: '--' }, { value: 'AF', name: 'Afghanistan' }],
errorMessages: {
required: validationMessage.country,
},
required: true,
},
],
},
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#honor_code').simulate('change', { target: { checked: false, name: 'honor_code', type: 'checkbox' } });
registrationPage.update();
expect(registrationPage.find('#honor_code-invalid-feedback').text()).toEqual(validationMessage.honorCode);
registrationPage.find('select#country').simulate('change', { target: { checked: false, name: 'country', type: 'checkbox' } });
registrationPage.update();
expect(registrationPage.find('#country-invalid-feedback').text()).toEqual(validationMessage.country);
});
it('should toggle optional fields state on checkbox click', () => {
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
@@ -173,58 +135,14 @@ describe('./RegistrationPage.js', () => {
});
it('should show optional fields section on optional check enabled', () => {
store = mockStore({
...initialState,
register: {
...initialState.register,
formData: {
fields: [
{
label: 'Tell us why you\'re interested in edX',
name: 'goals',
type: 'textarea',
required: false,
},
{
label: 'Highest level of Education completed.',
name: 'level_of_education',
type: 'select',
options: [{ value: '', name: '--' }, { value: 'p', name: 'Doctorate' }],
required: false,
},
{
label: 'Year of birth.',
name: 'year_of_birth',
type: 'select',
options: [{ value: '', name: '--' }, { value: '2021', name: '2021' }],
required: false,
},
{
label: 'Gender.',
name: 'gender',
type: 'select',
options: [{ value: '', name: '--' }, { value: 'f', name: 'Female' }],
required: false,
},
],
},
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#optional').simulate('change', { target: { checked: true } });
registrationPage.update();
expect(registrationPage.find('textarea#goals').length).toEqual(1);
expect(registrationPage.find('select#level_of_education').length).toEqual(1);
expect(registrationPage.find('select#year_of_birth').length).toEqual(1);
expect(registrationPage.find('select#gender').length).toEqual(1);
});
it('should dispatch fetchRegistrationForm on ComponentDidMount', () => {
store.dispatch = jest.fn(store.dispatch);
mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(store.dispatch).toHaveBeenCalledWith(fetchRegistrationForm());
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 dispatch fetchRealtimeValidations on Blur', () => {
@@ -255,9 +173,13 @@ describe('./RegistrationPage.js', () => {
registrationPage.find('input#password').simulate('blur', { target: { value: '', name: 'password' } });
formPayload.fieldName = 'password';
expect(store.dispatch).toHaveBeenCalledWith(fetchRealtimeValidations(formPayload));
registrationPage.find('select#country').simulate('blur', { target: { value: '', name: 'country' } });
formPayload.fieldName = 'country';
expect(store.dispatch).toHaveBeenCalledWith(fetchRealtimeValidations(formPayload));
});
it('should call Validations function on Blur in case of 403', () => {
it('should call validations function on Blur in case of 403', () => {
store = mockStore({
...initialState,
register: {
@@ -265,25 +187,17 @@ describe('./RegistrationPage.js', () => {
statusCode: 403,
},
});
const errors = {
email: 'Please enter your Email.',
name: 'Please enter your Full Name.',
username: 'Please enter your Public Username.',
password: 'Please enter your Password.',
country: '',
honorCode: '',
termsOfService: '',
};
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#username').simulate('blur', { target: { value: '', name: 'username' } });
registrationPage.find('input#name').simulate('blur', { target: { value: '', name: 'name' } });
registrationPage.find('input#email').simulate('blur', { target: { value: '', name: 'email' } });
registrationPage.find('input#password').simulate('blur', { target: { value: '', name: 'password' } });
expect(registrationPage.find('RegistrationPage').state('errors')).toEqual(errors);
registrationPage.find('select#country').simulate('blur', { target: { value: '', name: 'country' } });
expect(registrationPage.find('RegistrationPage').state('errors')).toEqual(emptyFieldValidation);
});
it('validate passwrod validations incsae of 403', () => {
it('validate password validations in case of 403', () => {
store = mockStore({
...initialState,
register: {
@@ -297,8 +211,6 @@ describe('./RegistrationPage.js', () => {
username: '',
password: 'Your password must contain at least 8 characters',
country: '',
honorCode: '',
termsOfService: '',
};
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
@@ -341,32 +253,7 @@ describe('./RegistrationPage.js', () => {
expect(shouldUpdate).toBe(false);
});
it('tests onClick should change errors state via realtime validation', () => {
const nextProps = {
validations: {
validation_decisions: {
username: 'Username must be between 2 and 30 characters long.',
},
},
};
const errors = {
email: '',
name: '',
username: 'Username must be between 2 and 30 characters long.',
password: '',
country: '',
honorCode: '',
termsOfService: '',
};
const root = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
root.find('RegistrationPage').instance().shouldComponentUpdate(nextProps);
root.find('input#username').simulate('click', { target: { value: '', name: 'username' } });
expect(root.find('RegistrationPage').state('errors')).toEqual(errors);
});
it('should not dispatch registerNewUser on Submit', () => {
it('should not dispatch registerNewUser on empty form Submission', () => {
const formPayload = {
email: '',
username: '',
@@ -382,6 +269,76 @@ describe('./RegistrationPage.js', () => {
expect(store.dispatch).not.toHaveBeenCalledWith(registerNewUser(formPayload));
});
it('should show error messages for required fields on empty form submission', () => {
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('button.btn-brand').simulate('click');
expect(registrationPage.find('#name-invalid-feedback').text()).toEqual(emptyFieldValidation.name);
expect(registrationPage.find('#username-invalid-feedback').text()).toEqual(emptyFieldValidation.username);
expect(registrationPage.find('#email-invalid-feedback').text()).toEqual(emptyFieldValidation.email);
expect(registrationPage.find('#password-invalid-feedback').text()).toEqual(emptyFieldValidation.password);
expect(registrationPage.find('#country-invalid-feedback').text()).toEqual(emptyFieldValidation.country);
let alertBanner = 'We couldn\'t create your account.';
Object.keys(emptyFieldValidation).forEach(key => {
alertBanner += emptyFieldValidation[key];
});
expect(registrationPage.find('#validation-errors').first().text()).toEqual(alertBanner);
});
it('should show error message on 409 on alert and below the fields', () => {
const errors = {
email: 'It looks like test@gmail.com belongs to an existing account. Try again with a different email address.',
username: 'It looks like test belongs to an existing account. Try again with a different username.',
};
store = mockStore({
...initialState,
register: {
...initialState.register,
isSubmitted: true,
registrationError: {
email: [{ user_message: errors.email }],
username: [{ user_message: errors.username }],
},
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('#email-invalid-feedback').text()).toEqual(errors.email);
expect(registrationPage.find('#username-invalid-feedback').text()).toEqual(errors.username);
expect(registrationPage.find('#validation-errors').first().text()).toEqual(
'We couldn\'t create your account.'.concat(errors.email + errors.username),
);
});
it('should submit form for valid input', () => {
const formPayload = {
name: 'John Doe',
username: 'john_doe',
email: 'john.doe@example.com',
password: 'password',
country: 'Pakistan',
gender: 'm',
};
store.dispatch = jest.fn(store.dispatch);
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registerPage.find('input#name').simulate('change', { target: { value: formPayload.name, name: 'name' } });
registerPage.find('input#username').simulate('change', { target: { value: formPayload.username, name: 'username' } });
registerPage.find('input#email').simulate('change', { target: { value: formPayload.email, name: 'email' } });
registerPage.find('input#password').simulate('change', { target: { value: formPayload.password, name: 'password' } });
registerPage.find('select#country').simulate('change', { target: { value: formPayload.country, name: 'country' } });
// Send optional field
registerPage.find('input#optional').simulate('change', { target: { checked: true } });
registerPage.find('select#gender').simulate('change', { target: { value: formPayload.gender, name: 'gender' } });
registerPage.find('button.btn-brand').simulate('click');
expect(store.dispatch).not.toHaveBeenCalledWith(registerNewUser(formPayload));
});
it('should match default section snapshot', () => {
const tree = renderer.create(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(tree.toJSON()).toMatchSnapshot();
@@ -441,8 +398,8 @@ describe('./RegistrationPage.js', () => {
},
});
const tree = renderer.create(reduxWrapper(<IntlRegistrationPage {...props} />)).toJSON();
expect(tree).toMatchSnapshot();
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('input#password').length).toEqual(0);
});
it('tests shouldComponentUpdate with pipeline user data', () => {
@@ -557,19 +514,6 @@ describe('./RegistrationPage.js', () => {
}],
},
},
register: {
...initialState.register,
formData: {
fields: [{
label: 'I agree to the Your Platform Name Here <a href="/honor" rel="noopener" target="_blank">Honor Code</a>',
name: 'honor_code',
type: 'checkbox',
errorMessages: {
required: 'You must agree to the Your Platform Name Here Honor Code',
},
}],
},
},
});
delete window.location;
@@ -593,8 +537,6 @@ describe('./RegistrationPage.js', () => {
},
});
delete window.location;
window.location = { href: getConfig().BASE_URL };
const expectedMessage = 'You\'ve successfully signed into Apple. We just need a little more information before '
+ 'you start learning with openedX.';
@@ -603,8 +545,6 @@ describe('./RegistrationPage.js', () => {
});
it('check cookie rendered', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL };
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registerPage.find(<CookiePolicyBanner />)).toBeTruthy();
});

View File

@@ -1,186 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`./RegistrationPage.js should display no password field when current provider is present 1`] = `
<div
className="d-flex justify-content-center m-4"
>
<div
className="d-flex flex-column"
>
<div
className="mw-500"
>
<div
className="fade alert-success mt-n2 alert show"
id="tpa-alert"
role="alert"
>
<span>
You've successfully signed into Google. We just need a little more information before you start learning with openedX.
</span>
</div>
<p>
Already have an edX account?
<a
className="ml-1"
href="/login"
onClick={[Function]}
target="_self"
>
Sign in.
</a>
</p>
<hr
className="mb-3 border-gray-200"
/>
<h3
className="mb-3"
>
Create a new account
</h3>
<form
className="form-group"
>
<div
className="form-group"
>
<span />
<input
aria-describedby=""
className="form-control"
id="name"
name="name"
onBlur={[Function]}
onChange={[Function]}
onClick={[Function]}
onFocus={[Function]}
placeholder="Full Name (required)"
required={true}
type="text"
value=""
/>
<span />
</div>
<div
className="form-group"
>
<span />
<input
aria-describedby=""
className="form-control"
id="username"
name="username"
onBlur={[Function]}
onChange={[Function]}
onClick={[Function]}
onFocus={[Function]}
placeholder="Public Username (required)"
required={true}
type="text"
value=""
/>
<span />
</div>
<div
className="form-group"
>
<span />
<input
aria-describedby=""
className="form-control"
id="email"
name="email"
onBlur={[Function]}
onChange={[Function]}
onClick={[Function]}
onFocus={[Function]}
placeholder="Email (required)"
required={true}
type="text"
value=""
/>
<span />
</div>
<div
className="form-group custom-control small"
>
<input
aria-describedby=""
checked={true}
className="form-check-input"
id="honor_code"
name="honor_code"
onChange={[Function]}
required={true}
type="checkbox"
value={true}
/>
I agree to the Your Platform Name Here
<a
href="/honor"
onClick={[Function]}
target="_self"
>
Honor Code
</a>
<strong
className="invalid-feedback"
id="honor_code-invalid-feedback"
>
You must agree to the Your Platform Name Here Honor Code
</strong>
</div>
<div
className="form-group custom-control pt-10 mb-0"
>
<span />
<input
aria-describedby=""
checked={false}
className="form-check-input"
id="optional"
name="optional"
onBlur={[Function]}
onChange={[Function]}
onClick={[Function]}
onFocus={[Function]}
placeholder=""
required={true}
type="checkbox"
value={false}
/>
<p
className="mb-1 small"
id="additionalFields"
onClick={[Function]}
role="presentation"
>
Support education research by providing additional information. (Optional)
</p>
</div>
<button
aria-disabled={false}
aria-live="assertive"
className="pgn__stateful-btn pgn__stateful-btn-state-default mt-3 btn btn-brand"
disabled={false}
onClick={[Function]}
onMouseDown={[Function]}
type="submit"
>
<span
className="d-flex align-items-center justify-content-center"
>
Create Account
</span>
</button>
</form>
</div>
</div>
</div>
`;
exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
exports[`RegistrationPageTests should match TPA provider snapshot 1`] = `
<div
className="d-flex justify-content-center m-4"
>
@@ -293,35 +113,1330 @@ exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
<span />
</div>
<div
className="form-group custom-control small"
className="form-group mb-0"
>
<input
<span />
<select
aria-describedby=""
checked={true}
className="form-check-input"
id="honor_code"
name="honor_code"
className="form-control"
id="country"
name="country"
onBlur={[Function]}
onChange={[Function]}
required={true}
type="checkbox"
value={true}
/>
I agree to the Your Platform Name Here
<a
href="/honor"
onClick={[Function]}
target="_self"
onFocus={[Function]}
placeholder="Country or Region of Residence (required)"
required={true}
value=""
>
Honor Code
</a>
<option
value=""
>
Country or Region of Residence (required)
</option>
<option
value="AF"
>
Afghanistan
</option>
<option
value="AL"
>
Albania
</option>
<option
value="DZ"
>
Algeria
</option>
<option
value="AS"
>
American Samoa
</option>
<option
value="AD"
>
Andorra
</option>
<option
value="AO"
>
Angola
</option>
<option
value="AI"
>
Anguilla
</option>
<option
value="AQ"
>
Antarctica
</option>
<option
value="AG"
>
Antigua and Barbuda
</option>
<option
value="AR"
>
Argentina
</option>
<option
value="AM"
>
Armenia
</option>
<option
value="AW"
>
Aruba
</option>
<option
value="AU"
>
Australia
</option>
<option
value="AT"
>
Austria
</option>
<option
value="AZ"
>
Azerbaijan
</option>
<option
value="BS"
>
Bahamas
</option>
<option
value="BH"
>
Bahrain
</option>
<option
value="BD"
>
Bangladesh
</option>
<option
value="BB"
>
Barbados
</option>
<option
value="BY"
>
Belarus
</option>
<option
value="BE"
>
Belgium
</option>
<option
value="BZ"
>
Belize
</option>
<option
value="BJ"
>
Benin
</option>
<option
value="BM"
>
Bermuda
</option>
<option
value="BT"
>
Bhutan
</option>
<option
value="BO"
>
Bolivia
</option>
<option
value="BA"
>
Bosnia and Herzegovina
</option>
<option
value="BW"
>
Botswana
</option>
<option
value="BV"
>
Bouvet Island
</option>
<option
value="BR"
>
Brazil
</option>
<option
value="IO"
>
British Indian Ocean Territory
</option>
<option
value="BN"
>
Brunei Darussalam
</option>
<option
value="BG"
>
Bulgaria
</option>
<option
value="BF"
>
Burkina Faso
</option>
<option
value="BI"
>
Burundi
</option>
<option
value="KH"
>
Cambodia
</option>
<option
value="CM"
>
Cameroon
</option>
<option
value="CA"
>
Canada
</option>
<option
value="CV"
>
Cape Verde
</option>
<option
value="KY"
>
Cayman Islands
</option>
<option
value="CF"
>
Central African Republic
</option>
<option
value="TD"
>
Chad
</option>
<option
value="CL"
>
Chile
</option>
<option
value="CN"
>
China
</option>
<option
value="CX"
>
Christmas Island
</option>
<option
value="CC"
>
Cocos (Keeling) Islands
</option>
<option
value="CO"
>
Colombia
</option>
<option
value="KM"
>
Comoros
</option>
<option
value="CG"
>
Congo
</option>
<option
value="CD"
>
Congo, the Democratic Republic of the
</option>
<option
value="CK"
>
Cook Islands
</option>
<option
value="CR"
>
Costa Rica
</option>
<option
value="CI"
>
Cote D'Ivoire
</option>
<option
value="HR"
>
Croatia
</option>
<option
value="CU"
>
Cuba
</option>
<option
value="CY"
>
Cyprus
</option>
<option
value="CZ"
>
Czech Republic
</option>
<option
value="DK"
>
Denmark
</option>
<option
value="DJ"
>
Djibouti
</option>
<option
value="DM"
>
Dominica
</option>
<option
value="DO"
>
Dominican Republic
</option>
<option
value="EC"
>
Ecuador
</option>
<option
value="EG"
>
Egypt
</option>
<option
value="SV"
>
El Salvador
</option>
<option
value="GQ"
>
Equatorial Guinea
</option>
<option
value="ER"
>
Eritrea
</option>
<option
value="EE"
>
Estonia
</option>
<option
value="ET"
>
Ethiopia
</option>
<option
value="FK"
>
Falkland Islands (Malvinas)
</option>
<option
value="FO"
>
Faroe Islands
</option>
<option
value="FJ"
>
Fiji
</option>
<option
value="FI"
>
Finland
</option>
<option
value="FR"
>
France
</option>
<option
value="GF"
>
French Guiana
</option>
<option
value="PF"
>
French Polynesia
</option>
<option
value="TF"
>
French Southern Territories
</option>
<option
value="GA"
>
Gabon
</option>
<option
value="GM"
>
Gambia
</option>
<option
value="GE"
>
Georgia
</option>
<option
value="DE"
>
Germany
</option>
<option
value="GH"
>
Ghana
</option>
<option
value="GI"
>
Gibraltar
</option>
<option
value="GR"
>
Greece
</option>
<option
value="GL"
>
Greenland
</option>
<option
value="GD"
>
Grenada
</option>
<option
value="GP"
>
Guadeloupe
</option>
<option
value="GU"
>
Guam
</option>
<option
value="GT"
>
Guatemala
</option>
<option
value="GN"
>
Guinea
</option>
<option
value="GW"
>
Guinea-Bissau
</option>
<option
value="GY"
>
Guyana
</option>
<option
value="HT"
>
Haiti
</option>
<option
value="HM"
>
Heard Island and Mcdonald Islands
</option>
<option
value="VA"
>
Holy See (Vatican City State)
</option>
<option
value="HN"
>
Honduras
</option>
<option
value="HK"
>
Hong Kong
</option>
<option
value="HU"
>
Hungary
</option>
<option
value="IS"
>
Iceland
</option>
<option
value="IN"
>
India
</option>
<option
value="ID"
>
Indonesia
</option>
<option
value="IR"
>
Iran, Islamic Republic of
</option>
<option
value="IQ"
>
Iraq
</option>
<option
value="IE"
>
Ireland
</option>
<option
value="IL"
>
Israel
</option>
<option
value="IT"
>
Italy
</option>
<option
value="JM"
>
Jamaica
</option>
<option
value="JP"
>
Japan
</option>
<option
value="JO"
>
Jordan
</option>
<option
value="KZ"
>
Kazakhstan
</option>
<option
value="KE"
>
Kenya
</option>
<option
value="KI"
>
Kiribati
</option>
<option
value="KP"
>
North Korea
</option>
<option
value="KR"
>
South Korea
</option>
<option
value="KW"
>
Kuwait
</option>
<option
value="KG"
>
Kyrgyzstan
</option>
<option
value="LA"
>
Lao People's Democratic Republic
</option>
<option
value="LV"
>
Latvia
</option>
<option
value="LB"
>
Lebanon
</option>
<option
value="LS"
>
Lesotho
</option>
<option
value="LR"
>
Liberia
</option>
<option
value="LY"
>
Libya
</option>
<option
value="LI"
>
Liechtenstein
</option>
<option
value="LT"
>
Lithuania
</option>
<option
value="LU"
>
Luxembourg
</option>
<option
value="MO"
>
Macao
</option>
<option
value="MG"
>
Madagascar
</option>
<option
value="MW"
>
Malawi
</option>
<option
value="MY"
>
Malaysia
</option>
<option
value="MV"
>
Maldives
</option>
<option
value="ML"
>
Mali
</option>
<option
value="MT"
>
Malta
</option>
<option
value="MH"
>
Marshall Islands
</option>
<option
value="MQ"
>
Martinique
</option>
<option
value="MR"
>
Mauritania
</option>
<option
value="MU"
>
Mauritius
</option>
<option
value="YT"
>
Mayotte
</option>
<option
value="MX"
>
Mexico
</option>
<option
value="FM"
>
Micronesia, Federated States of
</option>
<option
value="MD"
>
Moldova, Republic of
</option>
<option
value="MC"
>
Monaco
</option>
<option
value="MN"
>
Mongolia
</option>
<option
value="MS"
>
Montserrat
</option>
<option
value="MA"
>
Morocco
</option>
<option
value="MZ"
>
Mozambique
</option>
<option
value="MM"
>
Myanmar
</option>
<option
value="NA"
>
Namibia
</option>
<option
value="NR"
>
Nauru
</option>
<option
value="NP"
>
Nepal
</option>
<option
value="NL"
>
Netherlands
</option>
<option
value="NC"
>
New Caledonia
</option>
<option
value="NZ"
>
New Zealand
</option>
<option
value="NI"
>
Nicaragua
</option>
<option
value="NE"
>
Niger
</option>
<option
value="NG"
>
Nigeria
</option>
<option
value="NU"
>
Niue
</option>
<option
value="NF"
>
Norfolk Island
</option>
<option
value="MK"
>
North Macedonia, Republic of
</option>
<option
value="MP"
>
Northern Mariana Islands
</option>
<option
value="NO"
>
Norway
</option>
<option
value="OM"
>
Oman
</option>
<option
value="PK"
>
Pakistan
</option>
<option
value="PW"
>
Palau
</option>
<option
value="PS"
>
Palestinian Territory, Occupied
</option>
<option
value="PA"
>
Panama
</option>
<option
value="PG"
>
Papua New Guinea
</option>
<option
value="PY"
>
Paraguay
</option>
<option
value="PE"
>
Peru
</option>
<option
value="PH"
>
Philippines
</option>
<option
value="PN"
>
Pitcairn
</option>
<option
value="PL"
>
Poland
</option>
<option
value="PT"
>
Portugal
</option>
<option
value="PR"
>
Puerto Rico
</option>
<option
value="QA"
>
Qatar
</option>
<option
value="RE"
>
Reunion
</option>
<option
value="RO"
>
Romania
</option>
<option
value="RU"
>
Russian Federation
</option>
<option
value="RW"
>
Rwanda
</option>
<option
value="SH"
>
Saint Helena
</option>
<option
value="KN"
>
Saint Kitts and Nevis
</option>
<option
value="LC"
>
Saint Lucia
</option>
<option
value="PM"
>
Saint Pierre and Miquelon
</option>
<option
value="VC"
>
Saint Vincent and the Grenadines
</option>
<option
value="WS"
>
Samoa
</option>
<option
value="SM"
>
San Marino
</option>
<option
value="ST"
>
Sao Tome and Principe
</option>
<option
value="SA"
>
Saudi Arabia
</option>
<option
value="SN"
>
Senegal
</option>
<option
value="SC"
>
Seychelles
</option>
<option
value="SL"
>
Sierra Leone
</option>
<option
value="SG"
>
Singapore
</option>
<option
value="SK"
>
Slovakia
</option>
<option
value="SI"
>
Slovenia
</option>
<option
value="SB"
>
Solomon Islands
</option>
<option
value="SO"
>
Somalia
</option>
<option
value="ZA"
>
South Africa
</option>
<option
value="GS"
>
South Georgia and the South Sandwich Islands
</option>
<option
value="ES"
>
Spain
</option>
<option
value="LK"
>
Sri Lanka
</option>
<option
value="SD"
>
Sudan
</option>
<option
value="SR"
>
Suriname
</option>
<option
value="SJ"
>
Svalbard and Jan Mayen
</option>
<option
value="SZ"
>
Swaziland
</option>
<option
value="SE"
>
Sweden
</option>
<option
value="CH"
>
Switzerland
</option>
<option
value="SY"
>
Syrian Arab Republic
</option>
<option
value="TW"
>
Taiwan
</option>
<option
value="TJ"
>
Tajikistan
</option>
<option
value="TZ"
>
Tanzania, United Republic of
</option>
<option
value="TH"
>
Thailand
</option>
<option
value="TL"
>
Timor-Leste
</option>
<option
value="TG"
>
Togo
</option>
<option
value="TK"
>
Tokelau
</option>
<option
value="TO"
>
Tonga
</option>
<option
value="TT"
>
Trinidad and Tobago
</option>
<option
value="TN"
>
Tunisia
</option>
<option
value="TR"
>
Turkey
</option>
<option
value="TM"
>
Turkmenistan
</option>
<option
value="TC"
>
Turks and Caicos Islands
</option>
<option
value="TV"
>
Tuvalu
</option>
<option
value="UG"
>
Uganda
</option>
<option
value="UA"
>
Ukraine
</option>
<option
value="AE"
>
United Arab Emirates
</option>
<option
value="GB"
>
United Kingdom
</option>
<option
value="US"
>
United States of America
</option>
<option
value="UM"
>
United States Minor Outlying Islands
</option>
<option
value="UY"
>
Uruguay
</option>
<option
value="UZ"
>
Uzbekistan
</option>
<option
value="VU"
>
Vanuatu
</option>
<option
value="VE"
>
Venezuela
</option>
<option
value="VN"
>
Viet Nam
</option>
<option
value="VG"
>
Virgin Islands, British
</option>
<option
value="VI"
>
Virgin Islands, U.S.
</option>
<option
value="WF"
>
Wallis and Futuna
</option>
<option
value="EH"
>
Western Sahara
</option>
<option
value="YE"
>
Yemen
</option>
<option
value="ZM"
>
Zambia
</option>
<option
value="ZW"
>
Zimbabwe
</option>
<option
value="AX"
>
Åland Islands
</option>
<option
value="BQ"
>
Bonaire, Sint Eustatius and Saba
</option>
<option
value="CW"
>
Curaçao
</option>
<option
value="GG"
>
Guernsey
</option>
<option
value="IM"
>
Isle of Man
</option>
<option
value="JE"
>
Jersey
</option>
<option
value="ME"
>
Montenegro
</option>
<option
value="BL"
>
Saint Barthélemy
</option>
<option
value="MF"
>
Saint Martin (French part)
</option>
<option
value="RS"
>
Serbia
</option>
<option
value="SX"
>
Sint Maarten (Dutch part)
</option>
<option
value="SS"
>
South Sudan
</option>
<option
value="XK"
>
Kosovo
</option>
</select>
<span />
<strong
className="invalid-feedback"
id="honor_code-invalid-feedback"
id="country-invalid-feedback"
>
You must agree to the Your Platform Name Here Honor Code
Select your country or region of residence.
</strong>
</div>
<div
className="pt-10 small"
id="honor-code"
>
<span>
By creating an account, you agree to the
<a
href="http://tos-and-honot-code.com"
onClick={[Function]}
rel="noopener noopener"
target="_blank"
>
Terms of Service and Honor Code
<span>
<span
aria-hidden={false}
aria-label="Opens in a new window"
className="fa fa-external-link"
title="Opens in a new window"
/>
</span>
</a>
and you acknowledge that and each Member process your personal data in accordance with the
<a
href="http://privacy-policy.com"
onClick={[Function]}
rel="noopener noopener"
target="_blank"
>
Privacy Policy
<span>
<span
aria-hidden={false}
aria-label="Opens in a new window"
className="fa fa-external-link"
title="Opens in a new window"
/>
</span>
</a>
.
</span>
</div>
<div
className="form-group custom-control pt-10 mb-0"
>
@@ -372,7 +1487,7 @@ exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
className="mt-0 border-gray-200"
/>
<span
className="d-blockmb-4 text-left"
className="d-block mb-4 text-left"
>
or create an account using
</span>
@@ -410,7 +1525,7 @@ exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
</div>
`;
exports[`./RegistrationPage.js should match default section snapshot 1`] = `
exports[`RegistrationPageTests should match default section snapshot 1`] = `
<div
className="d-flex justify-content-center m-4"
>
@@ -523,35 +1638,1330 @@ exports[`./RegistrationPage.js should match default section snapshot 1`] = `
<span />
</div>
<div
className="form-group custom-control small"
className="form-group mb-0"
>
<input
<span />
<select
aria-describedby=""
checked={true}
className="form-check-input"
id="honor_code"
name="honor_code"
className="form-control"
id="country"
name="country"
onBlur={[Function]}
onChange={[Function]}
required={true}
type="checkbox"
value={true}
/>
I agree to the Your Platform Name Here
<a
href="/honor"
onClick={[Function]}
target="_self"
onFocus={[Function]}
placeholder="Country or Region of Residence (required)"
required={true}
value=""
>
Honor Code
</a>
<option
value=""
>
Country or Region of Residence (required)
</option>
<option
value="AF"
>
Afghanistan
</option>
<option
value="AL"
>
Albania
</option>
<option
value="DZ"
>
Algeria
</option>
<option
value="AS"
>
American Samoa
</option>
<option
value="AD"
>
Andorra
</option>
<option
value="AO"
>
Angola
</option>
<option
value="AI"
>
Anguilla
</option>
<option
value="AQ"
>
Antarctica
</option>
<option
value="AG"
>
Antigua and Barbuda
</option>
<option
value="AR"
>
Argentina
</option>
<option
value="AM"
>
Armenia
</option>
<option
value="AW"
>
Aruba
</option>
<option
value="AU"
>
Australia
</option>
<option
value="AT"
>
Austria
</option>
<option
value="AZ"
>
Azerbaijan
</option>
<option
value="BS"
>
Bahamas
</option>
<option
value="BH"
>
Bahrain
</option>
<option
value="BD"
>
Bangladesh
</option>
<option
value="BB"
>
Barbados
</option>
<option
value="BY"
>
Belarus
</option>
<option
value="BE"
>
Belgium
</option>
<option
value="BZ"
>
Belize
</option>
<option
value="BJ"
>
Benin
</option>
<option
value="BM"
>
Bermuda
</option>
<option
value="BT"
>
Bhutan
</option>
<option
value="BO"
>
Bolivia
</option>
<option
value="BA"
>
Bosnia and Herzegovina
</option>
<option
value="BW"
>
Botswana
</option>
<option
value="BV"
>
Bouvet Island
</option>
<option
value="BR"
>
Brazil
</option>
<option
value="IO"
>
British Indian Ocean Territory
</option>
<option
value="BN"
>
Brunei Darussalam
</option>
<option
value="BG"
>
Bulgaria
</option>
<option
value="BF"
>
Burkina Faso
</option>
<option
value="BI"
>
Burundi
</option>
<option
value="KH"
>
Cambodia
</option>
<option
value="CM"
>
Cameroon
</option>
<option
value="CA"
>
Canada
</option>
<option
value="CV"
>
Cape Verde
</option>
<option
value="KY"
>
Cayman Islands
</option>
<option
value="CF"
>
Central African Republic
</option>
<option
value="TD"
>
Chad
</option>
<option
value="CL"
>
Chile
</option>
<option
value="CN"
>
China
</option>
<option
value="CX"
>
Christmas Island
</option>
<option
value="CC"
>
Cocos (Keeling) Islands
</option>
<option
value="CO"
>
Colombia
</option>
<option
value="KM"
>
Comoros
</option>
<option
value="CG"
>
Congo
</option>
<option
value="CD"
>
Congo, the Democratic Republic of the
</option>
<option
value="CK"
>
Cook Islands
</option>
<option
value="CR"
>
Costa Rica
</option>
<option
value="CI"
>
Cote D'Ivoire
</option>
<option
value="HR"
>
Croatia
</option>
<option
value="CU"
>
Cuba
</option>
<option
value="CY"
>
Cyprus
</option>
<option
value="CZ"
>
Czech Republic
</option>
<option
value="DK"
>
Denmark
</option>
<option
value="DJ"
>
Djibouti
</option>
<option
value="DM"
>
Dominica
</option>
<option
value="DO"
>
Dominican Republic
</option>
<option
value="EC"
>
Ecuador
</option>
<option
value="EG"
>
Egypt
</option>
<option
value="SV"
>
El Salvador
</option>
<option
value="GQ"
>
Equatorial Guinea
</option>
<option
value="ER"
>
Eritrea
</option>
<option
value="EE"
>
Estonia
</option>
<option
value="ET"
>
Ethiopia
</option>
<option
value="FK"
>
Falkland Islands (Malvinas)
</option>
<option
value="FO"
>
Faroe Islands
</option>
<option
value="FJ"
>
Fiji
</option>
<option
value="FI"
>
Finland
</option>
<option
value="FR"
>
France
</option>
<option
value="GF"
>
French Guiana
</option>
<option
value="PF"
>
French Polynesia
</option>
<option
value="TF"
>
French Southern Territories
</option>
<option
value="GA"
>
Gabon
</option>
<option
value="GM"
>
Gambia
</option>
<option
value="GE"
>
Georgia
</option>
<option
value="DE"
>
Germany
</option>
<option
value="GH"
>
Ghana
</option>
<option
value="GI"
>
Gibraltar
</option>
<option
value="GR"
>
Greece
</option>
<option
value="GL"
>
Greenland
</option>
<option
value="GD"
>
Grenada
</option>
<option
value="GP"
>
Guadeloupe
</option>
<option
value="GU"
>
Guam
</option>
<option
value="GT"
>
Guatemala
</option>
<option
value="GN"
>
Guinea
</option>
<option
value="GW"
>
Guinea-Bissau
</option>
<option
value="GY"
>
Guyana
</option>
<option
value="HT"
>
Haiti
</option>
<option
value="HM"
>
Heard Island and Mcdonald Islands
</option>
<option
value="VA"
>
Holy See (Vatican City State)
</option>
<option
value="HN"
>
Honduras
</option>
<option
value="HK"
>
Hong Kong
</option>
<option
value="HU"
>
Hungary
</option>
<option
value="IS"
>
Iceland
</option>
<option
value="IN"
>
India
</option>
<option
value="ID"
>
Indonesia
</option>
<option
value="IR"
>
Iran, Islamic Republic of
</option>
<option
value="IQ"
>
Iraq
</option>
<option
value="IE"
>
Ireland
</option>
<option
value="IL"
>
Israel
</option>
<option
value="IT"
>
Italy
</option>
<option
value="JM"
>
Jamaica
</option>
<option
value="JP"
>
Japan
</option>
<option
value="JO"
>
Jordan
</option>
<option
value="KZ"
>
Kazakhstan
</option>
<option
value="KE"
>
Kenya
</option>
<option
value="KI"
>
Kiribati
</option>
<option
value="KP"
>
North Korea
</option>
<option
value="KR"
>
South Korea
</option>
<option
value="KW"
>
Kuwait
</option>
<option
value="KG"
>
Kyrgyzstan
</option>
<option
value="LA"
>
Lao People's Democratic Republic
</option>
<option
value="LV"
>
Latvia
</option>
<option
value="LB"
>
Lebanon
</option>
<option
value="LS"
>
Lesotho
</option>
<option
value="LR"
>
Liberia
</option>
<option
value="LY"
>
Libya
</option>
<option
value="LI"
>
Liechtenstein
</option>
<option
value="LT"
>
Lithuania
</option>
<option
value="LU"
>
Luxembourg
</option>
<option
value="MO"
>
Macao
</option>
<option
value="MG"
>
Madagascar
</option>
<option
value="MW"
>
Malawi
</option>
<option
value="MY"
>
Malaysia
</option>
<option
value="MV"
>
Maldives
</option>
<option
value="ML"
>
Mali
</option>
<option
value="MT"
>
Malta
</option>
<option
value="MH"
>
Marshall Islands
</option>
<option
value="MQ"
>
Martinique
</option>
<option
value="MR"
>
Mauritania
</option>
<option
value="MU"
>
Mauritius
</option>
<option
value="YT"
>
Mayotte
</option>
<option
value="MX"
>
Mexico
</option>
<option
value="FM"
>
Micronesia, Federated States of
</option>
<option
value="MD"
>
Moldova, Republic of
</option>
<option
value="MC"
>
Monaco
</option>
<option
value="MN"
>
Mongolia
</option>
<option
value="MS"
>
Montserrat
</option>
<option
value="MA"
>
Morocco
</option>
<option
value="MZ"
>
Mozambique
</option>
<option
value="MM"
>
Myanmar
</option>
<option
value="NA"
>
Namibia
</option>
<option
value="NR"
>
Nauru
</option>
<option
value="NP"
>
Nepal
</option>
<option
value="NL"
>
Netherlands
</option>
<option
value="NC"
>
New Caledonia
</option>
<option
value="NZ"
>
New Zealand
</option>
<option
value="NI"
>
Nicaragua
</option>
<option
value="NE"
>
Niger
</option>
<option
value="NG"
>
Nigeria
</option>
<option
value="NU"
>
Niue
</option>
<option
value="NF"
>
Norfolk Island
</option>
<option
value="MK"
>
North Macedonia, Republic of
</option>
<option
value="MP"
>
Northern Mariana Islands
</option>
<option
value="NO"
>
Norway
</option>
<option
value="OM"
>
Oman
</option>
<option
value="PK"
>
Pakistan
</option>
<option
value="PW"
>
Palau
</option>
<option
value="PS"
>
Palestinian Territory, Occupied
</option>
<option
value="PA"
>
Panama
</option>
<option
value="PG"
>
Papua New Guinea
</option>
<option
value="PY"
>
Paraguay
</option>
<option
value="PE"
>
Peru
</option>
<option
value="PH"
>
Philippines
</option>
<option
value="PN"
>
Pitcairn
</option>
<option
value="PL"
>
Poland
</option>
<option
value="PT"
>
Portugal
</option>
<option
value="PR"
>
Puerto Rico
</option>
<option
value="QA"
>
Qatar
</option>
<option
value="RE"
>
Reunion
</option>
<option
value="RO"
>
Romania
</option>
<option
value="RU"
>
Russian Federation
</option>
<option
value="RW"
>
Rwanda
</option>
<option
value="SH"
>
Saint Helena
</option>
<option
value="KN"
>
Saint Kitts and Nevis
</option>
<option
value="LC"
>
Saint Lucia
</option>
<option
value="PM"
>
Saint Pierre and Miquelon
</option>
<option
value="VC"
>
Saint Vincent and the Grenadines
</option>
<option
value="WS"
>
Samoa
</option>
<option
value="SM"
>
San Marino
</option>
<option
value="ST"
>
Sao Tome and Principe
</option>
<option
value="SA"
>
Saudi Arabia
</option>
<option
value="SN"
>
Senegal
</option>
<option
value="SC"
>
Seychelles
</option>
<option
value="SL"
>
Sierra Leone
</option>
<option
value="SG"
>
Singapore
</option>
<option
value="SK"
>
Slovakia
</option>
<option
value="SI"
>
Slovenia
</option>
<option
value="SB"
>
Solomon Islands
</option>
<option
value="SO"
>
Somalia
</option>
<option
value="ZA"
>
South Africa
</option>
<option
value="GS"
>
South Georgia and the South Sandwich Islands
</option>
<option
value="ES"
>
Spain
</option>
<option
value="LK"
>
Sri Lanka
</option>
<option
value="SD"
>
Sudan
</option>
<option
value="SR"
>
Suriname
</option>
<option
value="SJ"
>
Svalbard and Jan Mayen
</option>
<option
value="SZ"
>
Swaziland
</option>
<option
value="SE"
>
Sweden
</option>
<option
value="CH"
>
Switzerland
</option>
<option
value="SY"
>
Syrian Arab Republic
</option>
<option
value="TW"
>
Taiwan
</option>
<option
value="TJ"
>
Tajikistan
</option>
<option
value="TZ"
>
Tanzania, United Republic of
</option>
<option
value="TH"
>
Thailand
</option>
<option
value="TL"
>
Timor-Leste
</option>
<option
value="TG"
>
Togo
</option>
<option
value="TK"
>
Tokelau
</option>
<option
value="TO"
>
Tonga
</option>
<option
value="TT"
>
Trinidad and Tobago
</option>
<option
value="TN"
>
Tunisia
</option>
<option
value="TR"
>
Turkey
</option>
<option
value="TM"
>
Turkmenistan
</option>
<option
value="TC"
>
Turks and Caicos Islands
</option>
<option
value="TV"
>
Tuvalu
</option>
<option
value="UG"
>
Uganda
</option>
<option
value="UA"
>
Ukraine
</option>
<option
value="AE"
>
United Arab Emirates
</option>
<option
value="GB"
>
United Kingdom
</option>
<option
value="US"
>
United States of America
</option>
<option
value="UM"
>
United States Minor Outlying Islands
</option>
<option
value="UY"
>
Uruguay
</option>
<option
value="UZ"
>
Uzbekistan
</option>
<option
value="VU"
>
Vanuatu
</option>
<option
value="VE"
>
Venezuela
</option>
<option
value="VN"
>
Viet Nam
</option>
<option
value="VG"
>
Virgin Islands, British
</option>
<option
value="VI"
>
Virgin Islands, U.S.
</option>
<option
value="WF"
>
Wallis and Futuna
</option>
<option
value="EH"
>
Western Sahara
</option>
<option
value="YE"
>
Yemen
</option>
<option
value="ZM"
>
Zambia
</option>
<option
value="ZW"
>
Zimbabwe
</option>
<option
value="AX"
>
Åland Islands
</option>
<option
value="BQ"
>
Bonaire, Sint Eustatius and Saba
</option>
<option
value="CW"
>
Curaçao
</option>
<option
value="GG"
>
Guernsey
</option>
<option
value="IM"
>
Isle of Man
</option>
<option
value="JE"
>
Jersey
</option>
<option
value="ME"
>
Montenegro
</option>
<option
value="BL"
>
Saint Barthélemy
</option>
<option
value="MF"
>
Saint Martin (French part)
</option>
<option
value="RS"
>
Serbia
</option>
<option
value="SX"
>
Sint Maarten (Dutch part)
</option>
<option
value="SS"
>
South Sudan
</option>
<option
value="XK"
>
Kosovo
</option>
</select>
<span />
<strong
className="invalid-feedback"
id="honor_code-invalid-feedback"
id="country-invalid-feedback"
>
You must agree to the Your Platform Name Here Honor Code
Select your country or region of residence.
</strong>
</div>
<div
className="pt-10 small"
id="honor-code"
>
<span>
By creating an account, you agree to the
<a
href="http://tos-and-honot-code.com"
onClick={[Function]}
rel="noopener noopener"
target="_blank"
>
Terms of Service and Honor Code
<span>
<span
aria-hidden={false}
aria-label="Opens in a new window"
className="fa fa-external-link"
title="Opens in a new window"
/>
</span>
</a>
and you acknowledge that and each Member process your personal data in accordance with the
<a
href="http://privacy-policy.com"
onClick={[Function]}
rel="noopener noopener"
target="_blank"
>
Privacy Policy
<span>
<span
aria-hidden={false}
aria-label="Opens in a new window"
className="fa fa-external-link"
title="Opens in a new window"
/>
</span>
</a>
.
</span>
</div>
<div
className="form-group custom-control pt-10 mb-0"
>
@@ -601,7 +3011,7 @@ exports[`./RegistrationPage.js should match default section snapshot 1`] = `
</div>
`;
exports[`./RegistrationPage.js should match pending button state snapshot 1`] = `
exports[`RegistrationPageTests should match pending button state snapshot 1`] = `
<div
className="d-flex justify-content-center m-4"
>
@@ -714,35 +3124,1330 @@ exports[`./RegistrationPage.js should match pending button state snapshot 1`] =
<span />
</div>
<div
className="form-group custom-control small"
className="form-group mb-0"
>
<input
<span />
<select
aria-describedby=""
checked={true}
className="form-check-input"
id="honor_code"
name="honor_code"
className="form-control"
id="country"
name="country"
onBlur={[Function]}
onChange={[Function]}
required={true}
type="checkbox"
value={true}
/>
I agree to the Your Platform Name Here
<a
href="/honor"
onClick={[Function]}
target="_self"
onFocus={[Function]}
placeholder="Country or Region of Residence (required)"
required={true}
value=""
>
Honor Code
</a>
<option
value=""
>
Country or Region of Residence (required)
</option>
<option
value="AF"
>
Afghanistan
</option>
<option
value="AL"
>
Albania
</option>
<option
value="DZ"
>
Algeria
</option>
<option
value="AS"
>
American Samoa
</option>
<option
value="AD"
>
Andorra
</option>
<option
value="AO"
>
Angola
</option>
<option
value="AI"
>
Anguilla
</option>
<option
value="AQ"
>
Antarctica
</option>
<option
value="AG"
>
Antigua and Barbuda
</option>
<option
value="AR"
>
Argentina
</option>
<option
value="AM"
>
Armenia
</option>
<option
value="AW"
>
Aruba
</option>
<option
value="AU"
>
Australia
</option>
<option
value="AT"
>
Austria
</option>
<option
value="AZ"
>
Azerbaijan
</option>
<option
value="BS"
>
Bahamas
</option>
<option
value="BH"
>
Bahrain
</option>
<option
value="BD"
>
Bangladesh
</option>
<option
value="BB"
>
Barbados
</option>
<option
value="BY"
>
Belarus
</option>
<option
value="BE"
>
Belgium
</option>
<option
value="BZ"
>
Belize
</option>
<option
value="BJ"
>
Benin
</option>
<option
value="BM"
>
Bermuda
</option>
<option
value="BT"
>
Bhutan
</option>
<option
value="BO"
>
Bolivia
</option>
<option
value="BA"
>
Bosnia and Herzegovina
</option>
<option
value="BW"
>
Botswana
</option>
<option
value="BV"
>
Bouvet Island
</option>
<option
value="BR"
>
Brazil
</option>
<option
value="IO"
>
British Indian Ocean Territory
</option>
<option
value="BN"
>
Brunei Darussalam
</option>
<option
value="BG"
>
Bulgaria
</option>
<option
value="BF"
>
Burkina Faso
</option>
<option
value="BI"
>
Burundi
</option>
<option
value="KH"
>
Cambodia
</option>
<option
value="CM"
>
Cameroon
</option>
<option
value="CA"
>
Canada
</option>
<option
value="CV"
>
Cape Verde
</option>
<option
value="KY"
>
Cayman Islands
</option>
<option
value="CF"
>
Central African Republic
</option>
<option
value="TD"
>
Chad
</option>
<option
value="CL"
>
Chile
</option>
<option
value="CN"
>
China
</option>
<option
value="CX"
>
Christmas Island
</option>
<option
value="CC"
>
Cocos (Keeling) Islands
</option>
<option
value="CO"
>
Colombia
</option>
<option
value="KM"
>
Comoros
</option>
<option
value="CG"
>
Congo
</option>
<option
value="CD"
>
Congo, the Democratic Republic of the
</option>
<option
value="CK"
>
Cook Islands
</option>
<option
value="CR"
>
Costa Rica
</option>
<option
value="CI"
>
Cote D'Ivoire
</option>
<option
value="HR"
>
Croatia
</option>
<option
value="CU"
>
Cuba
</option>
<option
value="CY"
>
Cyprus
</option>
<option
value="CZ"
>
Czech Republic
</option>
<option
value="DK"
>
Denmark
</option>
<option
value="DJ"
>
Djibouti
</option>
<option
value="DM"
>
Dominica
</option>
<option
value="DO"
>
Dominican Republic
</option>
<option
value="EC"
>
Ecuador
</option>
<option
value="EG"
>
Egypt
</option>
<option
value="SV"
>
El Salvador
</option>
<option
value="GQ"
>
Equatorial Guinea
</option>
<option
value="ER"
>
Eritrea
</option>
<option
value="EE"
>
Estonia
</option>
<option
value="ET"
>
Ethiopia
</option>
<option
value="FK"
>
Falkland Islands (Malvinas)
</option>
<option
value="FO"
>
Faroe Islands
</option>
<option
value="FJ"
>
Fiji
</option>
<option
value="FI"
>
Finland
</option>
<option
value="FR"
>
France
</option>
<option
value="GF"
>
French Guiana
</option>
<option
value="PF"
>
French Polynesia
</option>
<option
value="TF"
>
French Southern Territories
</option>
<option
value="GA"
>
Gabon
</option>
<option
value="GM"
>
Gambia
</option>
<option
value="GE"
>
Georgia
</option>
<option
value="DE"
>
Germany
</option>
<option
value="GH"
>
Ghana
</option>
<option
value="GI"
>
Gibraltar
</option>
<option
value="GR"
>
Greece
</option>
<option
value="GL"
>
Greenland
</option>
<option
value="GD"
>
Grenada
</option>
<option
value="GP"
>
Guadeloupe
</option>
<option
value="GU"
>
Guam
</option>
<option
value="GT"
>
Guatemala
</option>
<option
value="GN"
>
Guinea
</option>
<option
value="GW"
>
Guinea-Bissau
</option>
<option
value="GY"
>
Guyana
</option>
<option
value="HT"
>
Haiti
</option>
<option
value="HM"
>
Heard Island and Mcdonald Islands
</option>
<option
value="VA"
>
Holy See (Vatican City State)
</option>
<option
value="HN"
>
Honduras
</option>
<option
value="HK"
>
Hong Kong
</option>
<option
value="HU"
>
Hungary
</option>
<option
value="IS"
>
Iceland
</option>
<option
value="IN"
>
India
</option>
<option
value="ID"
>
Indonesia
</option>
<option
value="IR"
>
Iran, Islamic Republic of
</option>
<option
value="IQ"
>
Iraq
</option>
<option
value="IE"
>
Ireland
</option>
<option
value="IL"
>
Israel
</option>
<option
value="IT"
>
Italy
</option>
<option
value="JM"
>
Jamaica
</option>
<option
value="JP"
>
Japan
</option>
<option
value="JO"
>
Jordan
</option>
<option
value="KZ"
>
Kazakhstan
</option>
<option
value="KE"
>
Kenya
</option>
<option
value="KI"
>
Kiribati
</option>
<option
value="KP"
>
North Korea
</option>
<option
value="KR"
>
South Korea
</option>
<option
value="KW"
>
Kuwait
</option>
<option
value="KG"
>
Kyrgyzstan
</option>
<option
value="LA"
>
Lao People's Democratic Republic
</option>
<option
value="LV"
>
Latvia
</option>
<option
value="LB"
>
Lebanon
</option>
<option
value="LS"
>
Lesotho
</option>
<option
value="LR"
>
Liberia
</option>
<option
value="LY"
>
Libya
</option>
<option
value="LI"
>
Liechtenstein
</option>
<option
value="LT"
>
Lithuania
</option>
<option
value="LU"
>
Luxembourg
</option>
<option
value="MO"
>
Macao
</option>
<option
value="MG"
>
Madagascar
</option>
<option
value="MW"
>
Malawi
</option>
<option
value="MY"
>
Malaysia
</option>
<option
value="MV"
>
Maldives
</option>
<option
value="ML"
>
Mali
</option>
<option
value="MT"
>
Malta
</option>
<option
value="MH"
>
Marshall Islands
</option>
<option
value="MQ"
>
Martinique
</option>
<option
value="MR"
>
Mauritania
</option>
<option
value="MU"
>
Mauritius
</option>
<option
value="YT"
>
Mayotte
</option>
<option
value="MX"
>
Mexico
</option>
<option
value="FM"
>
Micronesia, Federated States of
</option>
<option
value="MD"
>
Moldova, Republic of
</option>
<option
value="MC"
>
Monaco
</option>
<option
value="MN"
>
Mongolia
</option>
<option
value="MS"
>
Montserrat
</option>
<option
value="MA"
>
Morocco
</option>
<option
value="MZ"
>
Mozambique
</option>
<option
value="MM"
>
Myanmar
</option>
<option
value="NA"
>
Namibia
</option>
<option
value="NR"
>
Nauru
</option>
<option
value="NP"
>
Nepal
</option>
<option
value="NL"
>
Netherlands
</option>
<option
value="NC"
>
New Caledonia
</option>
<option
value="NZ"
>
New Zealand
</option>
<option
value="NI"
>
Nicaragua
</option>
<option
value="NE"
>
Niger
</option>
<option
value="NG"
>
Nigeria
</option>
<option
value="NU"
>
Niue
</option>
<option
value="NF"
>
Norfolk Island
</option>
<option
value="MK"
>
North Macedonia, Republic of
</option>
<option
value="MP"
>
Northern Mariana Islands
</option>
<option
value="NO"
>
Norway
</option>
<option
value="OM"
>
Oman
</option>
<option
value="PK"
>
Pakistan
</option>
<option
value="PW"
>
Palau
</option>
<option
value="PS"
>
Palestinian Territory, Occupied
</option>
<option
value="PA"
>
Panama
</option>
<option
value="PG"
>
Papua New Guinea
</option>
<option
value="PY"
>
Paraguay
</option>
<option
value="PE"
>
Peru
</option>
<option
value="PH"
>
Philippines
</option>
<option
value="PN"
>
Pitcairn
</option>
<option
value="PL"
>
Poland
</option>
<option
value="PT"
>
Portugal
</option>
<option
value="PR"
>
Puerto Rico
</option>
<option
value="QA"
>
Qatar
</option>
<option
value="RE"
>
Reunion
</option>
<option
value="RO"
>
Romania
</option>
<option
value="RU"
>
Russian Federation
</option>
<option
value="RW"
>
Rwanda
</option>
<option
value="SH"
>
Saint Helena
</option>
<option
value="KN"
>
Saint Kitts and Nevis
</option>
<option
value="LC"
>
Saint Lucia
</option>
<option
value="PM"
>
Saint Pierre and Miquelon
</option>
<option
value="VC"
>
Saint Vincent and the Grenadines
</option>
<option
value="WS"
>
Samoa
</option>
<option
value="SM"
>
San Marino
</option>
<option
value="ST"
>
Sao Tome and Principe
</option>
<option
value="SA"
>
Saudi Arabia
</option>
<option
value="SN"
>
Senegal
</option>
<option
value="SC"
>
Seychelles
</option>
<option
value="SL"
>
Sierra Leone
</option>
<option
value="SG"
>
Singapore
</option>
<option
value="SK"
>
Slovakia
</option>
<option
value="SI"
>
Slovenia
</option>
<option
value="SB"
>
Solomon Islands
</option>
<option
value="SO"
>
Somalia
</option>
<option
value="ZA"
>
South Africa
</option>
<option
value="GS"
>
South Georgia and the South Sandwich Islands
</option>
<option
value="ES"
>
Spain
</option>
<option
value="LK"
>
Sri Lanka
</option>
<option
value="SD"
>
Sudan
</option>
<option
value="SR"
>
Suriname
</option>
<option
value="SJ"
>
Svalbard and Jan Mayen
</option>
<option
value="SZ"
>
Swaziland
</option>
<option
value="SE"
>
Sweden
</option>
<option
value="CH"
>
Switzerland
</option>
<option
value="SY"
>
Syrian Arab Republic
</option>
<option
value="TW"
>
Taiwan
</option>
<option
value="TJ"
>
Tajikistan
</option>
<option
value="TZ"
>
Tanzania, United Republic of
</option>
<option
value="TH"
>
Thailand
</option>
<option
value="TL"
>
Timor-Leste
</option>
<option
value="TG"
>
Togo
</option>
<option
value="TK"
>
Tokelau
</option>
<option
value="TO"
>
Tonga
</option>
<option
value="TT"
>
Trinidad and Tobago
</option>
<option
value="TN"
>
Tunisia
</option>
<option
value="TR"
>
Turkey
</option>
<option
value="TM"
>
Turkmenistan
</option>
<option
value="TC"
>
Turks and Caicos Islands
</option>
<option
value="TV"
>
Tuvalu
</option>
<option
value="UG"
>
Uganda
</option>
<option
value="UA"
>
Ukraine
</option>
<option
value="AE"
>
United Arab Emirates
</option>
<option
value="GB"
>
United Kingdom
</option>
<option
value="US"
>
United States of America
</option>
<option
value="UM"
>
United States Minor Outlying Islands
</option>
<option
value="UY"
>
Uruguay
</option>
<option
value="UZ"
>
Uzbekistan
</option>
<option
value="VU"
>
Vanuatu
</option>
<option
value="VE"
>
Venezuela
</option>
<option
value="VN"
>
Viet Nam
</option>
<option
value="VG"
>
Virgin Islands, British
</option>
<option
value="VI"
>
Virgin Islands, U.S.
</option>
<option
value="WF"
>
Wallis and Futuna
</option>
<option
value="EH"
>
Western Sahara
</option>
<option
value="YE"
>
Yemen
</option>
<option
value="ZM"
>
Zambia
</option>
<option
value="ZW"
>
Zimbabwe
</option>
<option
value="AX"
>
Åland Islands
</option>
<option
value="BQ"
>
Bonaire, Sint Eustatius and Saba
</option>
<option
value="CW"
>
Curaçao
</option>
<option
value="GG"
>
Guernsey
</option>
<option
value="IM"
>
Isle of Man
</option>
<option
value="JE"
>
Jersey
</option>
<option
value="ME"
>
Montenegro
</option>
<option
value="BL"
>
Saint Barthélemy
</option>
<option
value="MF"
>
Saint Martin (French part)
</option>
<option
value="RS"
>
Serbia
</option>
<option
value="SX"
>
Sint Maarten (Dutch part)
</option>
<option
value="SS"
>
South Sudan
</option>
<option
value="XK"
>
Kosovo
</option>
</select>
<span />
<strong
className="invalid-feedback"
id="honor_code-invalid-feedback"
id="country-invalid-feedback"
>
You must agree to the Your Platform Name Here Honor Code
Select your country or region of residence.
</strong>
</div>
<div
className="pt-10 small"
id="honor-code"
>
<span>
By creating an account, you agree to the
<a
href="http://tos-and-honot-code.com"
onClick={[Function]}
rel="noopener noopener"
target="_blank"
>
Terms of Service and Honor Code
<span>
<span
aria-hidden={false}
aria-label="Opens in a new window"
className="fa fa-external-link"
title="Opens in a new window"
/>
</span>
</a>
and you acknowledge that and each Member process your personal data in accordance with the
<a
href="http://privacy-policy.com"
onClick={[Function]}
rel="noopener noopener"
target="_blank"
>
Privacy Policy
<span>
<span
aria-hidden={false}
aria-label="Opens in a new window"
className="fa fa-external-link"
title="Opens in a new window"
/>
</span>
</a>
.
</span>
</div>
<div
className="form-group custom-control pt-10 mb-0"
>