diff --git a/src/register/ConfigurableRegistrationForm.jsx b/src/register/ConfigurableRegistrationForm.jsx
index 844949f0..36bc66a9 100644
--- a/src/register/ConfigurableRegistrationForm.jsx
+++ b/src/register/ConfigurableRegistrationForm.jsx
@@ -54,13 +54,13 @@ const ConfigurableRegistrationForm = (props) => {
});
const handleOnChange = (event, countryValue = null) => {
- const { name, type } = event.target;
+ const { name } = event.target;
let value;
if (countryValue) {
value = { ...countryValue };
} else {
value = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
- if (type === 'checkbox') {
+ if (event.target.type === 'checkbox') {
setFieldErrors(prevErrors => ({ ...prevErrors, [name]: '' }));
}
}
diff --git a/src/register/data/constants.js b/src/register/data/constants.js
index 0c0f68fb..34d75e4b 100644
--- a/src/register/data/constants.js
+++ b/src/register/data/constants.js
@@ -173,6 +173,3 @@ export const DEFAULT_TOP_LEVEL_DOMAINS = [
export const COUNTRY_CODE_KEY = 'code';
export const COUNTRY_DISPLAY_KEY = 'name';
-
-export const EXPAND_MORE_ICON = 'expand-more';
-export const EXPAND_LESS_ICON = 'expand-less';
diff --git a/src/register/data/utils.js b/src/register/data/utils.js
index 99f3ba0c..f34a0aed 100644
--- a/src/register/data/utils.js
+++ b/src/register/data/utils.js
@@ -93,14 +93,10 @@ export function validateCountryField(value, countryList, errorMessage) {
if (value) {
const normalizedValue = value.toLowerCase();
- // Handling a case here where user enters a valid country code that needs to be
- // evaluated and set its value as a valid value.
const selectedCountry = countryList.find(
(country) => (
- // When translations apply extra space added in country value so we should
- // trim that.
+ // When translations are applied, extra space added in country value, so we should trim that.
country[COUNTRY_DISPLAY_KEY].toLowerCase().trim() === normalizedValue
- || country[COUNTRY_CODE_KEY].toLowerCase().trim() === normalizedValue
),
);
if (selectedCountry) {
diff --git a/src/register/registrationFields/CountryField.jsx b/src/register/registrationFields/CountryField.jsx
index cbe8440e..0465bfac 100644
--- a/src/register/registrationFields/CountryField.jsx
+++ b/src/register/registrationFields/CountryField.jsx
@@ -1,154 +1,62 @@
-import React, { useEffect, useRef, useState } from 'react';
+import React from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
-import { Icon, IconButton } from '@edx/paragon';
-import { ExpandLess, ExpandMore } from '@edx/paragon/icons';
+import { FormAutosuggest, FormAutosuggestOption, FormControlFeedback } from '@edx/paragon';
import PropTypes from 'prop-types';
-import { FormGroup } from '../../common-components';
-import {
- COUNTRY_CODE_KEY, COUNTRY_DISPLAY_KEY, EXPAND_LESS_ICON, EXPAND_MORE_ICON,
-} from '../data/constants';
+import { COUNTRY_CODE_KEY, COUNTRY_DISPLAY_KEY } from '../data/constants';
import messages from '../messages';
const CountryField = (props) => {
const { countryList, selectedCountry } = props;
-
- const dropdownRef = useRef(null);
const { formatMessage } = useIntl();
- const [errorMessage, setErrorMessage] = useState(props.errorMessage);
- const [dropDownItems, setDropDownItems] = useState([]);
- const [displayValue, setDisplayValue] = useState('');
- const [trailingIcon, setTrailingIcon] = useState(EXPAND_MORE_ICON);
- const onBlurHandler = (event, itemClicked = false, countryName = '') => {
- const { name } = event.target;
- const relatedName = event.relatedTarget ? event.relatedTarget.name : '';
- // For a better user experience, do not validate when focus out from 'country' field
- // and focus on 'countryItem' or 'countryExpand' button.
- if ((relatedName === 'countryItem' || relatedName === 'countryExpand') && name === 'country') {
- return;
- }
- const countryValue = itemClicked ? countryName : displayValue;
- if (props.onBlurHandler) {
- props.onBlurHandler({ target: { name: 'country', value: countryValue } });
- }
- setTrailingIcon(EXPAND_MORE_ICON);
- setDropDownItems([]);
- };
-
- const getDropdownItems = (countryToFind = null) => {
- let updatedCountryList = countryList;
- if (countryToFind) {
- updatedCountryList = countryList.filter(
- (option) => (option.name.toLowerCase().includes(countryToFind.toLowerCase())),
- );
- }
-
- return updatedCountryList.map((country) => {
- const countryName = country[COUNTRY_DISPLAY_KEY];
- return (
-
- );
- });
+ const handleSelected = (value) => {
+ if (props.onBlurHandler) { props.onBlurHandler({ target: { name: 'country', value } }); }
};
const onFocusHandler = (event) => {
- const { name, value } = event.target;
- setDropDownItems(getDropdownItems(name === 'country' ? value : displayValue));
- setTrailingIcon(EXPAND_LESS_ICON);
- setErrorMessage('');
if (props.onFocusHandler) { props.onFocusHandler(event); }
};
- const onChangeHandler = (event) => {
- const filteredItems = getDropdownItems(event.target.value);
- setDropDownItems(filteredItems);
- setDisplayValue(event.target.value);
- if (props.onChangeHandler) { props.onChangeHandler(event, { countryCode: '', displayValue: event.target.value }); }
- };
-
- const handleOnClickOutside = () => {
- setTrailingIcon(EXPAND_MORE_ICON);
- setDropDownItems([]);
- };
-
- const handleTrailingIconClick = () => {
- if (trailingIcon === EXPAND_MORE_ICON) {
- setDropDownItems(getDropdownItems());
- setTrailingIcon(EXPAND_LESS_ICON);
- } else {
- setDropDownItems([]);
- setTrailingIcon(EXPAND_MORE_ICON);
+ const onChangeHandler = (value) => {
+ if (props.onChangeHandler) {
+ props.onChangeHandler({ target: { name: 'country' } }, { countryCode: '', displayValue: value });
}
};
- useEffect(() => {
- const handleClickOutside = (event) => {
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
- handleOnClickOutside();
- }
- };
- document.addEventListener('click', handleClickOutside, true);
- return () => {
- document.removeEventListener('click', handleClickOutside, true);
- };
- }, []);
-
- useEffect(() => {
- if (selectedCountry.displayValue) {
- setDisplayValue(selectedCountry.displayValue);
- }
- }, [selectedCountry]);
-
- useEffect(() => {
- setErrorMessage(props.errorMessage);
- }, [props.errorMessage]);
+ const getCountryList = () => countryList.map((country) => (
+
+ {country[COUNTRY_DISPLAY_KEY]}
+
+ ));
return (
-
-
+ {}}
- onClick={handleTrailingIconClick}
- onFocus={() => {}}
- />
- )}
- value={displayValue}
- errorMessage={errorMessage}
- handleChange={onChangeHandler}
- handleBlur={onBlurHandler}
- handleFocus={onFocusHandler}
- />
-
- { dropDownItems?.length > 0 ? dropDownItems : null }
-
-
+ aria-label="form autosuggest"
+ name="country"
+ value={selectedCountry.displayValue || ''}
+ onSelected={(value) => handleSelected(value)}
+ onFocus={(e) => onFocusHandler(e)}
+ onBlur={(e) => handleSelected(e.target.value)}
+ onChange={(value) => onChangeHandler(value)}
+ >
+ {getCountryList()}
+
+ {props.errorMessage !== '' && (
+
+ {props.errorMessage}
+
+ )}
+ >
);
};
diff --git a/src/register/tests/RegistrationPage.test.jsx b/src/register/tests/RegistrationPage.test.jsx
index 2a580eb1..d4ebb0f2 100644
--- a/src/register/tests/RegistrationPage.test.jsx
+++ b/src/register/tests/RegistrationPage.test.jsx
@@ -121,8 +121,8 @@ describe('RegistrationPage', () => {
registrationPage.find('input#username').simulate('change', { target: { value: payload.username, name: 'username' } });
registrationPage.find('input#email').simulate('change', { target: { value: payload.email, name: 'email' } });
- registrationPage.find('input#country').simulate('change', { target: { value: payload.country, name: 'country' } });
- registrationPage.find('input#country').simulate('blur', { target: { value: payload.country, name: 'country' } });
+ registrationPage.find('input[name="country"]').simulate('change', { target: { value: payload.country, name: 'country' } });
+ registrationPage.find('input[name="country"]').simulate('blur', { target: { value: payload.country, name: 'country' } });
if (!isThirdPartyAuth) {
registrationPage.find('input#password').simulate('change', { target: { value: payload.password, name: 'password' } });
@@ -307,7 +307,7 @@ describe('RegistrationPage', () => {
registrationPage.find('input#password').simulate('blur', { target: { value: '', name: 'password' } });
expect(registrationPage.find('div[feedback-for="password"]').text()).toContain(emptyFieldValidation.password);
- registrationPage.find('input#country').simulate('blur', { target: { value: '', name: 'country' } });
+ registrationPage.find('input[name="country"]').simulate('blur', { target: { value: '', name: 'country' } });
expect(registrationPage.find('div[feedback-for="country"]').text()).toEqual(emptyFieldValidation.country);
});
@@ -332,7 +332,7 @@ describe('RegistrationPage', () => {
it('should run validations for focused field on form submission', () => {
const registrationPage = mount(reduxWrapper());
- registrationPage.find('input#country').simulate('focus');
+ registrationPage.find('input[name="country"]').simulate('focus');
registrationPage.find('button.btn-brand').simulate('click');
expect(registrationPage.find('div[feedback-for="country"]').text()).toEqual(emptyFieldValidation.country);
@@ -443,7 +443,7 @@ describe('RegistrationPage', () => {
expect(registrationPage.find('div[feedback-for="password"]').exists()).toBeFalsy();
expect(registrationPage.find('div[feedback-for="country"]').text()).toEqual(emptyFieldValidation.country);
- registrationPage.find('input#country').simulate('focus');
+ registrationPage.find('input[name="country"]').simulate('focus');
expect(registrationPage.find('div[feedback-for="country"]').exists()).toBeFalsy();
});
@@ -986,9 +986,11 @@ describe('RegistrationPage', () => {
backendCountryCode: 'PK',
},
});
+ const expectedPropValue = { countryCode: 'PK', displayValue: 'Pakistan' };
- const registrationPage = mount(reduxWrapper());
- expect(registrationPage.find('input#country').props().value).toEqual('Pakistan');
+ const registrationPage = mount(reduxWrapper()).find('RegistrationPage');
+ expect(registrationPage.find('CountryField').prop('selectedCountry')).toEqual(expectedPropValue);
+ expect(registrationPage.find('input[name="country"]').exists()).toBeTruthy();
});
it('should display error message based on the error code returned by API', () => {
@@ -1041,7 +1043,7 @@ describe('RegistrationPage', () => {
getLocale.mockImplementation(() => ('ar-ae'));
const registrationPage = mount(reduxWrapper());
- registrationPage.find('input#country').simulate('focus');
+ registrationPage.find('input[name="country"]').simulate('click');
registrationPage.find('button.dropdown-item').at(0).simulate('click', { target: { value: 'أفغانستان ', name: 'countryItem' } });
expect(registrationPage.find('div[feedback-for="country"]').exists()).toBeFalsy();
});
@@ -1064,18 +1066,6 @@ describe('RegistrationPage', () => {
registrationPage.find('input#email').simulate('change', { target: { value: 'a@gmail.com', name: 'email' } });
expect(registrationPage.find('div[feedback-for="email"]').exists()).toBeFalsy();
});
-
- it('should set country in component state when form is translated using browser translations', () => {
- getLocale.mockImplementation(() => ('en-us'));
-
- store.dispatch = jest.fn(store.dispatch);
-
- const registrationPage = mount(reduxWrapper());
- registrationPage.find('input#country').simulate('focus');
- registrationPage.find('button.dropdown-item').at(0).simulate('click', { target: { value: undefined, name: undefined, parentElement: { parentElement: { value: 'Afghanistan' } } } });
- expect(registrationPage.find('input#country').props().value).toEqual('Afghanistan');
- expect(registrationPage.find('div[feedback-for="country"]').exists()).toBeFalsy();
- });
});
describe('Test Configurable Fields', () => {
@@ -1104,6 +1094,7 @@ describe('RegistrationPage', () => {
});
it('should submit form with fields returned by backend in payload', () => {
+ getLocale.mockImplementation(() => ('en-us'));
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
store = mockStore({
...initialState,
@@ -1204,16 +1195,6 @@ describe('RegistrationPage', () => {
expect(registrationPage.find('#profession-error').last().text()).toEqual(professionError);
});
- it('should not remove errors from form fields when country is selected by clicking on expand button', () => {
- const registrationPage = mount(reduxWrapper());
- registrationPage.find('button.btn-brand').simulate('click');
- expect(registrationPage.find('div[feedback-for="name"]').exists()).toBeTruthy();
-
- registrationPage.find('button[name="countryExpand"]').simulate('click');
- registrationPage.find('button.dropdown-item').at(0).simulate('click', { target: { value: 'Pakistan', name: 'countryItem' } });
- expect(registrationPage.find('div[feedback-for="name"]').exists()).toBeTruthy();
- });
-
it('should check TOS and honor code fields if they exist when auto submitting register form', () => {
getLocale.mockImplementation(() => ('en-us'));
store = mockStore({
diff --git a/src/sass/_registration.scss b/src/sass/_registration.scss
index 5b4f93a0..63baf2c8 100644
--- a/src/sass/_registration.scss
+++ b/src/sass/_registration.scss
@@ -1,3 +1,7 @@
.register-stateful-button-width {
min-width: 14.4rem;
}
+
+.pgn__form-autosuggest__wrapper > .pgn__form-group {
+ margin-bottom: 0 !important;
+}