Files
frontend-app-authn/src/register/ConfigurableRegistrationForm.jsx
Syed Sajjad Hussain Shah 84c563fda3 refactor: use paragon Autosuggest field for country field (#911)
VAN-1415

Co-authored-by: Syed Sajjad  Hussain Shah <syed.sajjad@H7FKF7K6XD.local>
2023-05-17 13:13:04 +05:00

226 lines
7.3 KiB
JavaScript

import React, { useEffect } from 'react';
import { getConfig } from '@edx/frontend-platform';
import { useIntl } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import { FIELDS } from './data/constants';
import { validateCountryField } from './data/utils';
import messages from './messages';
import { HonorCode, TermsOfService } from './registrationFields';
import CountryField from './registrationFields/CountryField';
import { FormFieldRenderer } from '../field-renderer';
/**
* Fields on registration page that are not the default required fields (name, email, username, password).
* These configurable required fields are defined on the backend using REGISTRATION_EXTRA_FIELDS setting.
*
* Country and Honor Code/Terms of Services (if enabled) will appear at the bottom of the form, even if they
* appear higher in order returned by backend. This is to make the user experience better.
*
* For edX only:
* Country and honor code fields are required by default, and we will continue to show them on
* frontend even if the API doesn't return it. The `SHOW_CONFIGURABLE_EDX_FIELDS` flag will enable
* it for edX.
* */
const ConfigurableRegistrationForm = (props) => {
const { formatMessage } = useIntl();
const {
countryList,
email,
fieldDescriptions,
fieldErrors,
formFields,
setFieldErrors,
setFocusedField,
setFormFields,
} = props;
let showTermsOfServiceAndHonorCode = false;
let showCountryField = false;
const formFieldDescriptions = [];
const honorCode = [];
const flags = {
showConfigurableRegistrationFields: getConfig().ENABLE_DYNAMIC_REGISTRATION_FIELDS,
showConfigurableEdxFields: getConfig().SHOW_CONFIGURABLE_EDX_FIELDS,
showMarketingEmailOptInCheckbox: getConfig().MARKETING_EMAILS_OPT_IN,
};
useEffect(() => {
if (!formFields.country) {
setFormFields(prevState => ({ ...prevState, country: { countryCode: '', displayValue: '' } }));
}
});
const handleOnChange = (event, countryValue = null) => {
const { name } = event.target;
let value;
if (countryValue) {
value = { ...countryValue };
} else {
value = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
if (event.target.type === 'checkbox') {
setFieldErrors(prevErrors => ({ ...prevErrors, [name]: '' }));
}
}
setFormFields(prevState => ({ ...prevState, [name]: value }));
};
const handleOnBlur = (event) => {
const { name, value } = event.target;
let error = '';
if (name === 'country') {
const countryValidation = validateCountryField(
value.trim(), countryList, formatMessage(messages['empty.country.field.error']),
);
const { countryCode, displayValue } = countryValidation;
error = countryValidation.error;
setFormFields(prevState => ({ ...prevState, country: { countryCode, displayValue } }));
} else if (!value || !value.trim()) {
error = fieldDescriptions[name].error_message;
} else if (name === 'confirm_email' && value !== email) {
error = formatMessage(messages['email.do.not.match']);
}
setFocusedField(null);
setFieldErrors(prevErrors => ({ ...prevErrors, [name]: error }));
};
const handleOnFocus = (event) => {
const { name } = event.target;
setFieldErrors(prevErrors => ({ ...prevErrors, [name]: '' }));
// Since we are removing the form errors from the focused field, we will
// need to rerun the validation for focused field on form submission.
setFocusedField(name);
};
if (flags.showConfigurableRegistrationFields) {
Object.keys(fieldDescriptions).forEach(fieldName => {
const fieldData = fieldDescriptions[fieldName];
switch (fieldData.name) {
case FIELDS.COUNTRY:
showCountryField = true;
break;
case FIELDS.HONOR_CODE:
if (fieldData.type === 'tos_and_honor_code') {
showTermsOfServiceAndHonorCode = true;
} else {
honorCode.push(
<span key={fieldData.name}>
<HonorCode
fieldType={fieldData.type}
value={formFields[fieldData.name]}
onChangeHandler={handleOnChange}
errorMessage={fieldErrors[fieldData.name]}
/>
</span>,
);
}
break;
case FIELDS.TERMS_OF_SERVICE:
honorCode.push(
<span key={fieldData.name}>
<TermsOfService
value={formFields[fieldData.name]}
onChangeHandler={handleOnChange}
errorMessage={fieldErrors[fieldData.name]}
/>
</span>,
);
break;
default:
formFieldDescriptions.push(
<span key={fieldData.name}>
<FormFieldRenderer
fieldData={fieldData}
value={formFields[fieldData.name]}
onChangeHandler={handleOnChange}
handleBlur={handleOnBlur}
handleFocus={handleOnFocus}
errorMessage={fieldErrors[fieldData.name]}
isRequired
/>
</span>,
);
}
});
}
if (flags.showConfigurableEdxFields || showCountryField) {
formFieldDescriptions.push(
<span key="country">
<CountryField
countryList={countryList}
selectedCountry={formFields.country}
errorMessage={fieldErrors.country || ''}
onChangeHandler={handleOnChange}
onBlurHandler={handleOnBlur}
onFocusHandler={handleOnFocus}
/>
</span>,
);
}
if (flags.showMarketingEmailOptInCheckbox) {
formFieldDescriptions.push(
<span key="marketing_email_opt_in">
<FormFieldRenderer
fieldData={{
type: 'checkbox',
label: formatMessage(messages['registration.opt.in.label'], { siteName: getConfig().SITE_NAME }),
name: 'marketingEmailsOptIn',
}}
value={formFields.marketingEmailsOptIn}
className="opt-checkbox"
onChangeHandler={handleOnChange}
handleBlur={handleOnBlur}
handleFocus={handleOnFocus}
/>
</span>,
);
}
if (flags.showConfigurableEdxFields || showTermsOfServiceAndHonorCode) {
formFieldDescriptions.push(
<span key="honor_code">
<HonorCode fieldType="tos_and_honor_code" onChangeHandler={handleOnChange} value={formFields.honor_code} />
</span>,
);
}
return (
<>
{formFieldDescriptions}
<div>
{honorCode}
</div>
</>
);
};
ConfigurableRegistrationForm.propTypes = {
countryList: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
email: PropTypes.string.isRequired,
fieldDescriptions: PropTypes.shape({}),
fieldErrors: PropTypes.shape({
country: PropTypes.string,
}).isRequired,
formFields: PropTypes.shape({
country: PropTypes.shape({
displayValue: PropTypes.string,
countryCode: PropTypes.string,
}),
honor_code: PropTypes.bool,
marketingEmailsOptIn: PropTypes.bool,
}).isRequired,
setFieldErrors: PropTypes.func.isRequired,
setFocusedField: PropTypes.func.isRequired,
setFormFields: PropTypes.func.isRequired,
};
ConfigurableRegistrationForm.defaultProps = {
fieldDescriptions: {},
};
export default ConfigurableRegistrationForm;