diff --git a/src/common-components/data/actions.js b/src/common-components/data/actions.js index f86ddd08..96871445 100644 --- a/src/common-components/data/actions.js +++ b/src/common-components/data/actions.js @@ -13,9 +13,15 @@ export const getThirdPartyAuthContextBegin = () => ({ type: THIRD_PARTY_AUTH_CONTEXT.BEGIN, }); -export const getThirdPartyAuthContextSuccess = (fieldDescriptions, optionalFields, thirdPartyAuthContext) => ({ +export const getThirdPartyAuthContextSuccess = ( + fieldDescriptions, + optionalFields, + thirdPartyAuthContext, + countriesCodesList) => ({ type: THIRD_PARTY_AUTH_CONTEXT.SUCCESS, - payload: { fieldDescriptions, optionalFields, thirdPartyAuthContext }, + payload: { + fieldDescriptions, optionalFields, thirdPartyAuthContext, countriesCodesList, + }, }); export const getThirdPartyAuthContextFailure = () => ({ diff --git a/src/common-components/data/constants.js b/src/common-components/data/constants.js index 4f9ec72c..d071dd19 100644 --- a/src/common-components/data/constants.js +++ b/src/common-components/data/constants.js @@ -77,3 +77,7 @@ export const progressiveProfilingFields = { }, }, }; + +export const FIELD_LABELS = { + COUNTRY: 'country', +}; diff --git a/src/common-components/data/reducers.js b/src/common-components/data/reducers.js index c2150cda..b51f989f 100644 --- a/src/common-components/data/reducers.js +++ b/src/common-components/data/reducers.js @@ -35,6 +35,7 @@ const reducer = (state = defaultState, action = {}) => { optionalFields: action.payload.optionalFields, thirdPartyAuthContext: action.payload.thirdPartyAuthContext, thirdPartyAuthApiStatus: COMPLETE_STATE, + countriesCodesList: action.payload.countriesCodesList, }; } case THIRD_PARTY_AUTH_CONTEXT.FAILURE: diff --git a/src/common-components/data/sagas.js b/src/common-components/data/sagas.js index 65105866..62de3eab 100644 --- a/src/common-components/data/sagas.js +++ b/src/common-components/data/sagas.js @@ -10,6 +10,7 @@ import { } from './actions'; import { progressiveProfilingFields, registerFields } from './constants'; import { + getCountryList, getThirdPartyAuthContext, } from './service'; import { setCountryFromThirdPartyAuthContext } from '../../register/data/actions'; @@ -20,6 +21,7 @@ export function* fetchThirdPartyAuthContext(action) { const { fieldDescriptions, optionalFields, thirdPartyAuthContext, } = yield call(getThirdPartyAuthContext, action.payload.urlParams); + const countriesCodesList = (yield call(getCountryList)) || []; yield put(setCountryFromThirdPartyAuthContext(thirdPartyAuthContext.countryCode)); // hard code country field, level of education and gender fields @@ -28,9 +30,15 @@ export function* fetchThirdPartyAuthContext(action) { registerFields, progressiveProfilingFields, thirdPartyAuthContext, + countriesCodesList, )); } else { - yield put(getThirdPartyAuthContextSuccess(fieldDescriptions, optionalFields, thirdPartyAuthContext)); + yield put(getThirdPartyAuthContextSuccess( + fieldDescriptions, + optionalFields, + thirdPartyAuthContext, + countriesCodesList, + )); } } catch (e) { yield put(getThirdPartyAuthContextFailure()); diff --git a/src/common-components/data/service.js b/src/common-components/data/service.js index 51df2135..5f2a8e79 100644 --- a/src/common-components/data/service.js +++ b/src/common-components/data/service.js @@ -1,5 +1,8 @@ import { getConfig } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { logError } from '@edx/frontend-platform/logging'; + +import { FIELD_LABELS } from './constants'; // eslint-disable-next-line import/prefer-default-export export async function getThirdPartyAuthContext(urlParams) { @@ -23,3 +26,28 @@ export async function getThirdPartyAuthContext(urlParams) { thirdPartyAuthContext: data.contextData || {}, }; } + +function extractCountryList(data) { + return data?.fields + .find(({ name }) => name === FIELD_LABELS.COUNTRY) + ?.options?.map(({ value }) => (value)) || []; +} + +export async function getCountryList() { + try { + const requestConfig = { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + isPublic: true, + }; + + const { data } = await getAuthenticatedHttpClient() + .get( + `${getConfig().LMS_BASE_URL}/user_api/v1/account/registration/`, + requestConfig, + ); + return extractCountryList(data); + } catch (e) { + logError(e); + return []; + } +} diff --git a/src/common-components/data/tests/sagas.test.js b/src/common-components/data/tests/sagas.test.js index f3bc07ab..f29e2217 100644 --- a/src/common-components/data/tests/sagas.test.js +++ b/src/common-components/data/tests/sagas.test.js @@ -8,6 +8,11 @@ import * as api from '../service'; const { loggingService } = initializeMockLogging(); +jest.mock('../service', () => ({ + getCountryList: jest.fn(), + getThirdPartyAuthContext: jest.fn(), +})); + describe('fetchThirdPartyAuthContext', () => { const params = { payload: { urlParams: {} }, @@ -31,6 +36,7 @@ describe('fetchThirdPartyAuthContext', () => { thirdPartyAuthContext: data, fieldDescriptions: {}, optionalFields: {}, + countriesCodesList: [], })); const dispatched = []; @@ -44,7 +50,7 @@ describe('fetchThirdPartyAuthContext', () => { expect(dispatched).toEqual([ actions.getThirdPartyAuthContextBegin(), setCountryFromThirdPartyAuthContext(), - actions.getThirdPartyAuthContextSuccess({}, {}, data), + actions.getThirdPartyAuthContextSuccess({}, {}, data, []), ]); getThirdPartyAuthContext.mockClear(); }); diff --git a/src/register/RegistrationPage.jsx b/src/register/RegistrationPage.jsx index 275281d3..50236e80 100644 --- a/src/register/RegistrationPage.jsx +++ b/src/register/RegistrationPage.jsx @@ -93,6 +93,7 @@ const RegistrationPage = (props) => { const providers = useSelector(state => state.commonComponents.thirdPartyAuthContext.providers); const secondaryProviders = useSelector(state => state.commonComponents.thirdPartyAuthContext.secondaryProviders); const pipelineUserDetails = useSelector(state => state.commonComponents.thirdPartyAuthContext.pipelineUserDetails); + const countriesCodesList = useSelector(state => state.commonComponents.countriesCodesList); const backendValidations = useSelector(getBackendValidations); const queryParams = useMemo(() => getAllPossibleQueryParams(), []); @@ -392,6 +393,7 @@ const RegistrationPage = (props) => { setFormFields={setConfigurableFormFields} autoSubmitRegisterForm={autoSubmitRegForm} fieldDescriptions={fieldDescriptions} + countriesCodesList={countriesCodesList} /> { setFieldErrors, setFormFields, autoSubmitRegistrationForm, + countriesCodesList, } = props; const dispatch = useDispatch(); @@ -45,10 +46,6 @@ const ConfigurableRegistrationForm = (props) => { confused and unable to create an account. So we added the United States entry in the dropdown list. */ - const countryList = useMemo(() => ( - getCountryList(getLocale()).concat([{ code: 'US', name: 'United States' }]).filter(country => country.code !== 'RU') - ), []); - let showTermsOfServiceAndHonorCode = false; let showCountryField = false; @@ -82,6 +79,16 @@ const ConfigurableRegistrationForm = (props) => { } }, [autoSubmitRegistrationForm]); // eslint-disable-line react-hooks/exhaustive-deps + const removeDisabledCountries = useCallback((countryList) => { + if (!countriesCodesList.length) { + return countryList; + } + return countryList.filter(({ code }) => countriesCodesList.find(x => x === code)); + }, [countriesCodesList]); + + const countryList = useMemo(() => removeDisabledCountries( + getCountryList(getLocale()).concat([{ code: 'US', name: 'United States' }])), [removeDisabledCountries]); + const handleErrorChange = (fieldName, error) => { if (fieldName) { setFieldErrors(prevErrors => ({ @@ -262,11 +269,16 @@ ConfigurableRegistrationForm.propTypes = { setFieldErrors: PropTypes.func.isRequired, setFormFields: PropTypes.func.isRequired, autoSubmitRegistrationForm: PropTypes.bool, + countriesCodesList: PropTypes.arrayOf(PropTypes.shape({ + code: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + })), }; ConfigurableRegistrationForm.defaultProps = { fieldDescriptions: {}, autoSubmitRegistrationForm: false, + countriesCodesList: [], }; export default ConfigurableRegistrationForm; diff --git a/src/register/components/tests/ConfigurableRegistrationForm.test.jsx b/src/register/components/tests/ConfigurableRegistrationForm.test.jsx index fd423b92..ce858d56 100644 --- a/src/register/components/tests/ConfigurableRegistrationForm.test.jsx +++ b/src/register/components/tests/ConfigurableRegistrationForm.test.jsx @@ -192,6 +192,7 @@ describe('ConfigurableRegistrationForm', () => { }, }, autoSubmitRegistrationForm: true, + countriesCodesList: [{ code: 'AX', name: 'Ă…land Islands' }, { code: 'AL', name: 'Albania' }], }; render(routerWrapper(reduxWrapper(