+
+
{label}
+ {isEditable ? (
+
+ {intl.formatMessage(messages['account.settings.editable.field.action.edit'])}
+
+ ) : null}
+
+
+ {renderValue(fullName)}
+
+
{renderConfirmationMessage() || helpText}
+
+ ),
+ }}
+ />
+ );
+};
+
+NameField.propTypes = {
+ name: PropTypes.string.isRequired,
+ label: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.node]),
+ emptyLabel: PropTypes.node,
+ type: PropTypes.string.isRequired,
+ fullNameValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ firstNameValue: PropTypes.string,
+ lastNameValue: PropTypes.string,
+ pendingNameChange: PropTypes.string,
+ verifiedName: PropTypes.shape({
+ verified_name: PropTypes.string,
+ status: PropTypes.string,
+ proctored_exam_attempt_id: PropTypes.number,
+ }),
+ userSuppliedValue: PropTypes.string,
+ saveState: PropTypes.oneOf(['default', 'pending', 'complete', 'error']),
+ error: PropTypes.string,
+ firstNameError: PropTypes.string,
+ lastNameError: PropTypes.string,
+ confirmationMessageDefinition: PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ defaultMessage: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ }),
+ confirmationValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ helpText: PropTypes.node,
+ onEdit: PropTypes.func.isRequired,
+ onCancel: PropTypes.func.isRequired,
+ onSubmit: PropTypes.func.isRequired,
+ onChange: PropTypes.func.isRequired,
+ isEditing: PropTypes.bool,
+ isEditable: PropTypes.bool,
+ isGrayedOut: PropTypes.bool,
+ intl: intlShape.isRequired,
+};
+
+NameField.defaultProps = {
+ fullNameValue: undefined,
+ firstNameValue: undefined,
+ lastNameValue: undefined,
+ pendingNameChange: null,
+ verifiedName: null,
+ saveState: undefined,
+ label: undefined,
+ emptyLabel: undefined,
+ error: undefined,
+ firstNameError: undefined,
+ lastNameError: undefined,
+ confirmationMessageDefinition: undefined,
+ confirmationValue: undefined,
+ helpText: undefined,
+ isEditing: false,
+ isEditable: true,
+ isGrayedOut: false,
+ userSuppliedValue: undefined,
+};
+
+export default connect(nameFieldSelector, {
+ onEdit: openForm,
+ onCancel: closeForm,
+})(injectIntl(NameField));
diff --git a/src/account-settings/data/actions.js b/src/account-settings/data/actions.js
index 27d8f7682..0f80510bf 100644
--- a/src/account-settings/data/actions.js
+++ b/src/account-settings/data/actions.js
@@ -105,9 +105,9 @@ export const savePreviousSiteLanguage = previousSiteLanguage => ({
payload: { previousSiteLanguage },
});
-export const saveMultipleSettings = (settingsArray, form = null) => ({
+export const saveMultipleSettings = (settingsArray, form = null, saveInSeparateCalls = true) => ({
type: SAVE_MULTIPLE_SETTINGS.BASE,
- payload: { settingsArray, form },
+ payload: { settingsArray, form, saveInSeparateCalls },
});
export const saveMultipleSettingsBegin = () => ({
diff --git a/src/account-settings/data/sagas.js b/src/account-settings/data/sagas.js
index c27cbe9ef..9eb9c13e8 100644
--- a/src/account-settings/data/sagas.js
+++ b/src/account-settings/data/sagas.js
@@ -124,14 +124,24 @@ export function* handleSaveMultipleSettings(action) {
try {
yield put(saveMultipleSettingsBegin());
const { username, userId } = getAuthenticatedUser();
- const { settingsArray, form } = action.payload;
- for (let i = 0; i < settingsArray.length; i += 1) {
- const { formId, commitValues } = settingsArray[i];
+ const { settingsArray, form, saveInSeparateCalls } = action.payload;
+ if (saveInSeparateCalls) {
+ for (let i = 0; i < settingsArray.length; i += 1) {
+ const { formId, commitValues } = settingsArray[i];
+ yield put(saveSettingsBegin());
+ const commitData = { [formId]: commitValues };
+ const savedSettings = yield call(patchSettings, username, commitData, userId);
+ yield put(saveSettingsSuccess(savedSettings, commitData));
+ }
+ } else {
+ const commitData = settingsArray.reduce((data, setting) => (
+ { ...data, [setting.formId]: setting.commitValues }
+ ), {});
yield put(saveSettingsBegin());
- const commitData = { [formId]: commitValues };
const savedSettings = yield call(patchSettings, username, commitData, userId);
yield put(saveSettingsSuccess(savedSettings, commitData));
}
+
yield put(saveMultipleSettingsSuccess(action));
if (form) {
yield delay(1000);
diff --git a/src/account-settings/data/selectors.js b/src/account-settings/data/selectors.js
index 7650aa01e..d683bfa1a 100644
--- a/src/account-settings/data/selectors.js
+++ b/src/account-settings/data/selectors.js
@@ -128,6 +128,16 @@ export const editableFieldSelector = createStructuredSelector({
isEditing: isEditingSelector,
});
+export const nameFieldSelector = createSelector(
+ editableFieldSelector,
+ accountSettingsSelector,
+ (editableFieldSettings, accountSettings) => ({
+ ...editableFieldSettings,
+ firstNameError: accountSettings.errors?.first_name,
+ lastNameError: accountSettings.errors?.last_name,
+ }),
+);
+
export const profileDataManagerSelector = createSelector(
accountSettingsSelector,
accountSettings => accountSettings.profileDataManager,
diff --git a/src/account-settings/name-change/NameChange.jsx b/src/account-settings/name-change/NameChange.jsx
index d08a840c5..10d56a9fe 100644
--- a/src/account-settings/name-change/NameChange.jsx
+++ b/src/account-settings/name-change/NameChange.jsx
@@ -62,7 +62,10 @@ const NameChangeModal = ({
}));
} else {
const draftProfileName = targetFormId === 'name' ? formValues.name : null;
- dispatch(requestNameChange(username, draftProfileName, verifiedNameInput));
+ const draftFirstName = targetFormId === 'name' ? formValues?.first_name : null;
+ const draftLastName = targetFormId === 'name' ? formValues?.last_name : null;
+
+ dispatch(requestNameChange(username, draftProfileName, verifiedNameInput, draftFirstName, draftLastName));
}
};
@@ -190,6 +193,8 @@ NameChangeModal.propTypes = {
errors: PropTypes.shape({}).isRequired,
formValues: PropTypes.shape({
name: PropTypes.string,
+ first_name: PropTypes.string,
+ last_name: PropTypes.string,
verified_name: PropTypes.string,
}).isRequired,
saveState: PropTypes.string,
diff --git a/src/account-settings/name-change/data/actions.js b/src/account-settings/name-change/data/actions.js
index f80fbbbf5..efd0a0935 100644
--- a/src/account-settings/name-change/data/actions.js
+++ b/src/account-settings/name-change/data/actions.js
@@ -2,9 +2,11 @@ import { AsyncActionType } from '../../data/utils';
export const REQUEST_NAME_CHANGE = new AsyncActionType('ACCOUNT_SETTINGS', 'REQUEST_NAME_CHANGE');
-export const requestNameChange = (username, profileName, verifiedName) => ({
+export const requestNameChange = (username, profileName, verifiedName, firstName, lastName) => ({
type: REQUEST_NAME_CHANGE.BASE,
- payload: { username, profileName, verifiedName },
+ payload: {
+ username, profileName, verifiedName, firstName, lastName,
+ },
});
export const requestNameChangeBegin = () => ({
diff --git a/src/account-settings/name-change/data/sagas.js b/src/account-settings/name-change/data/sagas.js
index dfbae8e87..4971a8807 100644
--- a/src/account-settings/name-change/data/sagas.js
+++ b/src/account-settings/name-change/data/sagas.js
@@ -17,7 +17,7 @@ export function* handleRequestNameChange(action) {
try {
yield put(requestNameChangeBegin());
if (action.payload.profileName) {
- yield call(postNameChange, action.payload.profileName);
+ yield call(postNameChange, action.payload.profileName, action.payload.firstName, action.payload.lastName);
profileName = action.payload.profileName;
}
yield call(postVerifiedName, {
diff --git a/src/account-settings/name-change/data/service.js b/src/account-settings/name-change/data/service.js
index 70a6cfc15..565850589 100644
--- a/src/account-settings/name-change/data/service.js
+++ b/src/account-settings/name-change/data/service.js
@@ -4,13 +4,19 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { handleRequestError } from '../../data/utils';
// eslint-disable-next-line import/prefer-default-export
-export async function postNameChange(name) {
+export async function postNameChange(name, firstName, lastName) {
// Requests a pending name change, rather than saving the account name immediately
const requestConfig = { headers: { Accept: 'application/json' } };
const requestUrl = `${getConfig().LMS_BASE_URL}/api/user/v1/accounts/name_change/`;
+ const nameChangePayload = { name };
+ if (firstName && lastName) {
+ nameChangePayload.first_name = firstName;
+ nameChangePayload.last_name = lastName;
+ }
+
const { data } = await getAuthenticatedHttpClient()
- .post(requestUrl, { name }, requestConfig)
+ .post(requestUrl, nameChangePayload, requestConfig)
.catch(error => handleRequestError(error));
return data;