From 6e633dcc6aed0ee1ef06799ee892c31f7be9a4db Mon Sep 17 00:00:00 2001 From: sundasnoreen12 Date: Wed, 19 Feb 2025 22:04:31 +0500 Subject: [PATCH] feat: implemented restricted countries functionality --- src/common-components/data/actions.js | 10 +++++-- src/common-components/data/reducers.js | 1 + src/common-components/data/sagas.js | 4 ++- src/common-components/data/service.js | 28 +++++++++++++++++++ src/data/constants.js | 3 ++ src/register/RegistrationPage.jsx | 2 ++ .../ConfigurableRegistrationForm.jsx | 20 +++++++++++-- 7 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/common-components/data/actions.js b/src/common-components/data/actions.js index f86ddd0851..0c7d3bcb23 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, + countries) => ({ type: THIRD_PARTY_AUTH_CONTEXT.SUCCESS, - payload: { fieldDescriptions, optionalFields, thirdPartyAuthContext }, + payload: { + fieldDescriptions, optionalFields, thirdPartyAuthContext, countries, + }, }); export const getThirdPartyAuthContextFailure = () => ({ diff --git a/src/common-components/data/reducers.js b/src/common-components/data/reducers.js index c2150cda80..afa86d9b3d 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, + countries: action.payload.countries, }; } case THIRD_PARTY_AUTH_CONTEXT.FAILURE: diff --git a/src/common-components/data/sagas.js b/src/common-components/data/sagas.js index ffe0be37c6..8dcb416e5d 100644 --- a/src/common-components/data/sagas.js +++ b/src/common-components/data/sagas.js @@ -8,6 +8,7 @@ import { THIRD_PARTY_AUTH_CONTEXT, } from './actions'; import { + getCountryList, getThirdPartyAuthContext, } from './service'; import { setCountryFromThirdPartyAuthContext } from '../../register/data/actions'; @@ -18,9 +19,10 @@ export function* fetchThirdPartyAuthContext(action) { const { fieldDescriptions, optionalFields, thirdPartyAuthContext, } = yield call(getThirdPartyAuthContext, action.payload.urlParams); + const countries = yield call(getCountryList); yield put(setCountryFromThirdPartyAuthContext(thirdPartyAuthContext.countryCode)); - yield put(getThirdPartyAuthContextSuccess(fieldDescriptions, optionalFields, thirdPartyAuthContext)); + yield put(getThirdPartyAuthContextSuccess(fieldDescriptions, optionalFields, thirdPartyAuthContext, countries)); } catch (e) { yield put(getThirdPartyAuthContextFailure()); logError(e); diff --git a/src/common-components/data/service.js b/src/common-components/data/service.js index 51df2135de..7085fa87ab 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 '../../data/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, name }) => ({ code: value, name })) || []; +} + +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/data/constants.js b/src/data/constants.js index 90fdf75f2b..8a6e6a7bc3 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -37,3 +37,6 @@ export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+ // things like auto-enrollment upon login and registration. export const AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next', 'register_for_free', 'track', 'is_account_recovery', 'variant', 'host', 'cta']; export const REDIRECT = 'redirect'; +export const FIELD_LABELS = { + COUNTRY: 'country', +}; diff --git a/src/register/RegistrationPage.jsx b/src/register/RegistrationPage.jsx index 8c5ea79f5b..2a40b37c3d 100644 --- a/src/register/RegistrationPage.jsx +++ b/src/register/RegistrationPage.jsx @@ -85,6 +85,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 countries = useSelector(state => state.commonComponents.countries); const backendValidations = useSelector(getBackendValidations); const queryParams = useMemo(() => getAllPossibleQueryParams(), []); @@ -358,6 +359,7 @@ const RegistrationPage = (props) => { setFormFields={setConfigurableFormFields} autoSubmitRegisterForm={autoSubmitRegForm} fieldDescriptions={fieldDescriptions} + countries={countries} /> { setFieldErrors, setFormFields, autoSubmitRegistrationForm, + countries, } = props; /** The reason for adding the entry 'United States' is that Chrome browser aut-fill the form with the 'Unites States' instead of 'United States of America' which does not exist in country dropdown list and gets the user 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' }]), []); let showTermsOfServiceAndHonorCode = false; let showCountryField = false; @@ -70,6 +70,17 @@ const ConfigurableRegistrationForm = (props) => { } }, [autoSubmitRegistrationForm]); // eslint-disable-line react-hooks/exhaustive-deps + const removeDisabledCountries = useCallback((countryList) => { + if (!countries.length) { + return countryList; + } + + return countryList.filter((country) => new Set(countries.map(({ code }) => code)).has(country.code)); + }, [countries]); + + const countryList = useMemo(() => removeDisabledCountries( + getCountryList(getLocale()).concat([{ code: 'US', name: 'United States' }]), []), [removeDisabledCountries]); + const handleErrorChange = (fieldName, error) => { if (fieldName) { setFieldErrors(prevErrors => ({ @@ -231,11 +242,16 @@ ConfigurableRegistrationForm.propTypes = { setFieldErrors: PropTypes.func.isRequired, setFormFields: PropTypes.func.isRequired, autoSubmitRegistrationForm: PropTypes.bool, + countries: PropTypes.arrayOf(PropTypes.shape({ + code: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + })), }; ConfigurableRegistrationForm.defaultProps = { fieldDescriptions: {}, autoSubmitRegistrationForm: false, + countries: [], }; export default ConfigurableRegistrationForm;