feat: enter name change flow when submitting a new verified name
This commit is contained in:
@@ -24,6 +24,7 @@ import {
|
||||
saveMultipleSettings,
|
||||
saveSettings,
|
||||
updateDraft,
|
||||
beginNameChange,
|
||||
} from './data/actions';
|
||||
import { accountSettingsPageSelector } from './data/selectors';
|
||||
import PageLoading from './PageLoading';
|
||||
@@ -168,7 +169,7 @@ class AccountSettingsPage extends React.Component {
|
||||
this.props.saveSettings(formId, values);
|
||||
}
|
||||
|
||||
handleSubmitName = (formId, values) => {
|
||||
handleSubmitProfileName = (formId, values) => {
|
||||
if (Object.keys(this.props.drafts).includes('useVerifiedNameForCerts')) {
|
||||
this.props.saveMultipleSettings([
|
||||
{
|
||||
@@ -185,6 +186,15 @@ class AccountSettingsPage extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
handleSubmitVerifiedName = (formId, values) => {
|
||||
if (Object.keys(this.props.drafts).includes('useVerifiedNameForCerts')) {
|
||||
this.props.saveSettings('useVerifiedNameForCerts', this.props.formValues.useVerifiedNameForCerts);
|
||||
}
|
||||
if (values !== this.props.committedValues?.verified_name) {
|
||||
this.props.beginNameChange(formId);
|
||||
}
|
||||
}
|
||||
|
||||
isEditable(fieldName) {
|
||||
return !this.props.staticFields.includes(fieldName);
|
||||
}
|
||||
@@ -249,8 +259,8 @@ class AccountSettingsPage extends React.Component {
|
||||
|
||||
renderFullNameHelpText = (status) => {
|
||||
if (
|
||||
!this.props.formValues.verifiedNameHistory
|
||||
|| !this.props.formValues.verifiedNameHistory.verified_name_enabled
|
||||
!this.props.verifiedNameHistory
|
||||
|| !this.props.verifiedNameEnabled
|
||||
) {
|
||||
return this.props.intl.formatMessage(messages['account.settings.field.full.name.help.text']);
|
||||
}
|
||||
@@ -375,12 +385,8 @@ class AccountSettingsPage extends React.Component {
|
||||
}
|
||||
|
||||
renderNameChangeModal() {
|
||||
const shouldDisplayNameChangeModal = (
|
||||
this.props.formErrors.name
|
||||
&& this.props.formErrors.name.includes('ID verification')
|
||||
);
|
||||
if (shouldDisplayNameChangeModal) {
|
||||
return <NameChange />;
|
||||
if (this.props.nameChangeModal && this.props.nameChangeModal.formId) {
|
||||
return <NameChange targetFormId={this.props.nameChangeModal.formId} />;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -431,8 +437,7 @@ class AccountSettingsPage extends React.Component {
|
||||
// Show State field only if the country is US (could include Canada later)
|
||||
const showState = this.props.formValues.country === COUNTRY_WITH_STATES;
|
||||
|
||||
const { verifiedName } = this.props.formValues;
|
||||
const verifiedNameEnabled = this.props.formValues.verifiedNameHistory.verified_name_enabled;
|
||||
const { verifiedName, verifiedNameEnabled } = this.props;
|
||||
|
||||
const timeZoneOptions = this.getLocalizedTimeZoneOptions(
|
||||
this.props.timeZoneOptions,
|
||||
@@ -444,7 +449,7 @@ class AccountSettingsPage extends React.Component {
|
||||
return (
|
||||
<>
|
||||
<div className="account-section" id="basic-information" ref={this.navLinkRefs['#basic-information']}>
|
||||
{verifiedNameEnabled && this.renderVerifiedNameMessage(this.props.formValues.mostRecentVerifiedName)}
|
||||
{verifiedNameEnabled && this.renderVerifiedNameMessage(this.props.mostRecentVerifiedName)}
|
||||
|
||||
<h2 className="section-heading">
|
||||
{this.props.intl.formatMessage(messages['account.settings.section.account.information'])}
|
||||
@@ -471,7 +476,7 @@ class AccountSettingsPage extends React.Component {
|
||||
type="text"
|
||||
value={
|
||||
verifiedNameEnabled
|
||||
&& verifiedName.status === 'submitted'
|
||||
&& verifiedName?.status === 'submitted'
|
||||
&& this.props.formValues.pending_name_change
|
||||
? this.props.formValues.pending_name_change
|
||||
: this.props.formValues.name
|
||||
@@ -496,14 +501,14 @@ class AccountSettingsPage extends React.Component {
|
||||
verifiedNameEnabled && verifiedName && !this.isEditable('verifiedName')
|
||||
}
|
||||
onChange={this.handleEditableFieldChange}
|
||||
onSubmit={this.handleSubmitName}
|
||||
onSubmit={this.handleSubmitProfileName}
|
||||
/>
|
||||
{verifiedNameEnabled && verifiedName
|
||||
&& (
|
||||
<EditableField
|
||||
name="verifiedName"
|
||||
name="verified_name"
|
||||
type="text"
|
||||
value={this.props.formValues.verifiedName.verified_name}
|
||||
value={this.props.formValues.verified_name}
|
||||
label={
|
||||
(
|
||||
<div className="d-flex">
|
||||
@@ -518,7 +523,7 @@ class AccountSettingsPage extends React.Component {
|
||||
isEditable={this.isEditable('verifiedName')}
|
||||
isGrayedOut={!this.isEditable('verifiedName')}
|
||||
onChange={this.handleEditableFieldChange}
|
||||
onSubmit={this.handleSubmitName}
|
||||
onSubmit={this.handleSubmitVerifiedName}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -798,27 +803,11 @@ AccountSettingsPage.propTypes = {
|
||||
state: PropTypes.string,
|
||||
shouldDisplayDemographicsSection: PropTypes.bool,
|
||||
useVerifiedNameForCerts: PropTypes.bool.isRequired,
|
||||
verifiedNameHistory: PropTypes.shape({
|
||||
verified_name_enabled: PropTypes.bool,
|
||||
use_verified_name_for_certs: PropTypes.bool,
|
||||
results: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
verified_name: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
verifiedName: PropTypes.shape({
|
||||
verified_name: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
}),
|
||||
mostRecentVerifiedName: PropTypes.shape({
|
||||
verified_name: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
}),
|
||||
verified_name: PropTypes.string,
|
||||
}).isRequired,
|
||||
committedValues: PropTypes.shape({
|
||||
useVerifiedNameForCerts: PropTypes.bool,
|
||||
verified_name: PropTypes.string,
|
||||
}),
|
||||
drafts: PropTypes.shape({}),
|
||||
formErrors: PropTypes.shape({
|
||||
@@ -850,7 +839,28 @@ AccountSettingsPage.propTypes = {
|
||||
saveMultipleSettings: PropTypes.func.isRequired,
|
||||
saveSettings: PropTypes.func.isRequired,
|
||||
fetchSettings: PropTypes.func.isRequired,
|
||||
tpaProviders: PropTypes.arrayOf(PropTypes.object),
|
||||
beginNameChange: PropTypes.func.isRequired,
|
||||
tpaProviders: PropTypes.arrayOf(PropTypes.shape({
|
||||
connected: PropTypes.bool,
|
||||
})),
|
||||
nameChangeModal: PropTypes.shape({
|
||||
formId: PropTypes.string,
|
||||
}),
|
||||
verifiedNameEnabled: PropTypes.bool,
|
||||
verifiedName: PropTypes.shape({
|
||||
verified_name: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
}),
|
||||
mostRecentVerifiedName: PropTypes.shape({
|
||||
verified_name: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
}),
|
||||
verifiedNameHistory: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
verified_name: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
}),
|
||||
),
|
||||
};
|
||||
|
||||
AccountSettingsPage.defaultProps = {
|
||||
@@ -859,6 +869,7 @@ AccountSettingsPage.defaultProps = {
|
||||
loadingError: null,
|
||||
committedValues: {
|
||||
useVerifiedNameForCerts: false,
|
||||
verified_name: null,
|
||||
},
|
||||
drafts: {},
|
||||
formErrors: {},
|
||||
@@ -871,6 +882,11 @@ AccountSettingsPage.defaultProps = {
|
||||
tpaProviders: [],
|
||||
isActive: true,
|
||||
secondary_email_enabled: false,
|
||||
nameChangeModal: {},
|
||||
verifiedNameEnabled: false,
|
||||
verifiedName: null,
|
||||
mostRecentVerifiedName: {},
|
||||
verifiedNameHistory: [],
|
||||
};
|
||||
|
||||
export default connect(accountSettingsPageSelector, {
|
||||
@@ -879,4 +895,5 @@ export default connect(accountSettingsPageSelector, {
|
||||
saveMultipleSettings,
|
||||
updateDraft,
|
||||
fetchSiteLanguages,
|
||||
beginNameChange,
|
||||
})(injectIntl(AccountSettingsPage));
|
||||
|
||||
@@ -121,6 +121,11 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Verification has been submitted. This usually takes 48 hours or less. Verified name cannot be changed at this time.',
|
||||
description: 'Help text for the account settings verified name field when a verified name has been submitted.',
|
||||
},
|
||||
'account.settings.field.name.verified.verification.alert': {
|
||||
id: 'account.settings.field.name.verified.verification.help',
|
||||
defaultMessage: 'Enter your name as it appears on your government-issued ID.',
|
||||
description: 'Form label instructing the user to enter the name on their ID.',
|
||||
},
|
||||
'account.settings.field.full.name.help.text.submitted': {
|
||||
id: 'account.settings.field.full.name.help.text.submitted',
|
||||
defaultMessage: 'When identity verification is successful, this name will appear on your certificates and public-facing records. Full name cannot be changed at this time.',
|
||||
|
||||
@@ -153,7 +153,7 @@ function EditableField(props) {
|
||||
</Button>
|
||||
</p>
|
||||
</form>
|
||||
{['name', 'verifiedName'].includes(name) && <CertificatePreference fieldName={name} />}
|
||||
{['name', 'verified_name'].includes(name) && <CertificatePreference fieldName={name} />}
|
||||
</>
|
||||
),
|
||||
default: (
|
||||
|
||||
@@ -42,7 +42,7 @@ function CertificatePreference({
|
||||
|
||||
function handleCheckboxChange() {
|
||||
if (!checked) {
|
||||
if (fieldName === 'verifiedName') {
|
||||
if (fieldName === 'verified_name') {
|
||||
dispatch(updateDraft(formId, true));
|
||||
} else {
|
||||
dispatch(updateDraft(formId, false));
|
||||
|
||||
@@ -9,6 +9,7 @@ export const OPEN_FORM = 'OPEN_FORM';
|
||||
export const CLOSE_FORM = 'CLOSE_FORM';
|
||||
export const UPDATE_DRAFT = 'UPDATE_DRAFT';
|
||||
export const RESET_DRAFTS = 'RESET_DRAFTS';
|
||||
export const BEGIN_NAME_CHANGE = 'BEGIN_NAME_CHANGE';
|
||||
|
||||
// FETCH SETTINGS ACTIONS
|
||||
|
||||
@@ -25,6 +26,7 @@ export const fetchSettingsSuccess = ({
|
||||
thirdPartyAuthProviders,
|
||||
profileDataManager,
|
||||
timeZones,
|
||||
verifiedNameHistory,
|
||||
}) => ({
|
||||
type: FETCH_SETTINGS.SUCCESS,
|
||||
payload: {
|
||||
@@ -32,6 +34,7 @@ export const fetchSettingsSuccess = ({
|
||||
thirdPartyAuthProviders,
|
||||
profileDataManager,
|
||||
timeZones,
|
||||
verifiedNameHistory,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -68,6 +71,10 @@ export const resetDrafts = () => ({
|
||||
type: RESET_DRAFTS,
|
||||
});
|
||||
|
||||
export const beginNameChange = (formId) => ({
|
||||
type: BEGIN_NAME_CHANGE,
|
||||
payload: { formId },
|
||||
});
|
||||
// SAVE SETTINGS ACTIONS
|
||||
|
||||
export const saveSettings = (formId, commitValues) => ({
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
UPDATE_DRAFT,
|
||||
RESET_DRAFTS,
|
||||
SAVE_MULTIPLE_SETTINGS,
|
||||
BEGIN_NAME_CHANGE,
|
||||
} from './actions';
|
||||
|
||||
import { reducer as deleteAccountReducer, DELETE_ACCOUNT } from '../delete-account';
|
||||
@@ -34,6 +35,11 @@ export const defaultState = {
|
||||
resetPassword: resetPasswordReducer(),
|
||||
nameChange: nameChangeReducer(),
|
||||
thirdPartyAuth: thirdPartyAuthReducer(),
|
||||
nameChangeModal: false,
|
||||
verifiedName: null,
|
||||
mostRecentVerifiedName: {},
|
||||
verifiedNameHistory: {},
|
||||
verifiedNameEnabled: false,
|
||||
};
|
||||
|
||||
const reducer = (state = defaultState, action) => {
|
||||
@@ -58,6 +64,7 @@ const reducer = (state = defaultState, action) => {
|
||||
loading: false,
|
||||
loaded: true,
|
||||
loadingError: null,
|
||||
verifiedNameHistory: action.payload.verifiedNameHistory,
|
||||
};
|
||||
case FETCH_SETTINGS.FAILURE:
|
||||
return {
|
||||
@@ -91,6 +98,7 @@ const reducer = (state = defaultState, action) => {
|
||||
saveState: null,
|
||||
errors: {},
|
||||
drafts: {},
|
||||
nameChangeModal: false,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
@@ -108,6 +116,15 @@ const reducer = (state = defaultState, action) => {
|
||||
drafts: {},
|
||||
};
|
||||
|
||||
case BEGIN_NAME_CHANGE:
|
||||
return {
|
||||
...state,
|
||||
saveState: 'error',
|
||||
nameChangeModal: {
|
||||
formId: action.payload.formId,
|
||||
},
|
||||
};
|
||||
|
||||
case SAVE_SETTINGS.BEGIN:
|
||||
return {
|
||||
...state,
|
||||
@@ -121,7 +138,6 @@ const reducer = (state = defaultState, action) => {
|
||||
values: { ...state.values, ...action.payload.values },
|
||||
errors: {},
|
||||
confirmationValues: {
|
||||
|
||||
...state.confirmationValues,
|
||||
...action.payload.confirmationValues,
|
||||
},
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
saveMultipleSettingsBegin,
|
||||
saveMultipleSettingsSuccess,
|
||||
saveMultipleSettingsFailure,
|
||||
beginNameChange,
|
||||
} from './actions';
|
||||
|
||||
// Sub-modules
|
||||
@@ -43,6 +44,7 @@ import {
|
||||
getSettings,
|
||||
patchSettings,
|
||||
getTimeZones,
|
||||
getVerifiedNameHistory,
|
||||
} from './service';
|
||||
|
||||
export function* handleFetchSettings() {
|
||||
@@ -59,6 +61,8 @@ export function* handleFetchSettings() {
|
||||
userId,
|
||||
);
|
||||
|
||||
const verifiedNameHistory = yield call(getVerifiedNameHistory);
|
||||
|
||||
if (values.country) { yield put(fetchTimeZones(values.country)); }
|
||||
|
||||
yield put(fetchSettingsSuccess({
|
||||
@@ -66,6 +70,7 @@ export function* handleFetchSettings() {
|
||||
thirdPartyAuthProviders,
|
||||
profileDataManager,
|
||||
timeZones,
|
||||
verifiedNameHistory,
|
||||
}));
|
||||
} catch (e) {
|
||||
yield put(fetchSettingsFailure(e.message));
|
||||
@@ -103,6 +108,9 @@ export function* handleSaveSettings(action) {
|
||||
yield put(closeForm(action.payload.formId));
|
||||
} catch (e) {
|
||||
if (e.fieldErrors) {
|
||||
if (Object.keys(e.fieldErrors).includes('name')) {
|
||||
yield put(beginNameChange('name'));
|
||||
}
|
||||
yield put(saveSettingsFailure({ fieldErrors: e.fieldErrors }));
|
||||
} else {
|
||||
yield put(saveSettingsFailure(e.message));
|
||||
@@ -131,6 +139,9 @@ export function* handleSaveMultipleSettings(action) {
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.fieldErrors) {
|
||||
if (Object.keys(e.fieldErrors).includes('name')) {
|
||||
yield put(beginNameChange('name'));
|
||||
}
|
||||
yield put(saveMultipleSettingsFailure({ fieldErrors: e.fieldErrors }));
|
||||
} else {
|
||||
yield put(saveMultipleSettingsFailure(e.message));
|
||||
|
||||
@@ -8,10 +8,19 @@ export const accountSettingsSelector = state => ({ ...state[storeName] });
|
||||
|
||||
const editableFieldNameSelector = (state, props) => props.name;
|
||||
|
||||
const sortedVerifiedNameHistorySelector = createSelector(
|
||||
const verifiedNameSettingsSelector = createSelector(
|
||||
accountSettingsSelector,
|
||||
accountSettings => {
|
||||
const history = accountSettings.values.verifiedNameHistory && accountSettings.values.verifiedNameHistory.results;
|
||||
accountSettings => ({
|
||||
history: accountSettings.verifiedNameHistory.results,
|
||||
verifiedNameEnabled: accountSettings?.verifiedNameHistory.verified_name_enabled,
|
||||
useVerifiedNameForCerts: accountSettings?.verifiedNameHistory.use_verified_name_for_certs,
|
||||
}),
|
||||
);
|
||||
|
||||
const sortedVerifiedNameHistorySelector = createSelector(
|
||||
verifiedNameSettingsSelector,
|
||||
verifiedNameSettings => {
|
||||
const { history } = verifiedNameSettings;
|
||||
|
||||
if (Array.isArray(history)) {
|
||||
return history.sort(compareVerifiedNamesByCreatedDate);
|
||||
@@ -51,9 +60,8 @@ const mostRecentApprovedVerifiedNameValueSelector = createSelector(
|
||||
|
||||
const valuesSelector = createSelector(
|
||||
accountSettingsSelector,
|
||||
mostRecentVerifiedNameSelector,
|
||||
mostRecentApprovedVerifiedNameValueSelector,
|
||||
(accountSettings, mostRecentVerifiedNameValue, mostRecentApprovedVerifiedNameValue) => {
|
||||
(accountSettings, mostRecentApprovedVerifiedNameValue) => {
|
||||
let useVerifiedNameForCerts = (
|
||||
accountSettings.values.verifiedNameHistory?.use_verified_name_for_certs || false
|
||||
);
|
||||
@@ -64,8 +72,7 @@ const valuesSelector = createSelector(
|
||||
|
||||
return {
|
||||
...accountSettings.values,
|
||||
verifiedName: mostRecentApprovedVerifiedNameValue,
|
||||
mostRecentVerifiedName: mostRecentVerifiedNameValue,
|
||||
verified_name: mostRecentApprovedVerifiedNameValue?.verified_name,
|
||||
useVerifiedNameForCerts,
|
||||
};
|
||||
},
|
||||
@@ -109,6 +116,11 @@ const errorSelector = createSelector(
|
||||
accountSettings => accountSettings.errors,
|
||||
);
|
||||
|
||||
const nameChangeModalSelector = createSelector(
|
||||
accountSettingsSelector,
|
||||
accountSettings => accountSettings.nameChangeModal,
|
||||
);
|
||||
|
||||
const saveStateSelector = createSelector(
|
||||
accountSettingsSelector,
|
||||
accountSettings => accountSettings.saveState,
|
||||
@@ -212,6 +224,11 @@ export const accountSettingsPageSelector = createSelector(
|
||||
timeZonesSelector,
|
||||
countryTimeZonesSelector,
|
||||
activeAccountSelector,
|
||||
nameChangeModalSelector,
|
||||
mostRecentApprovedVerifiedNameValueSelector,
|
||||
mostRecentVerifiedNameSelector,
|
||||
sortedVerifiedNameHistorySelector,
|
||||
verifiedNameSettingsSelector,
|
||||
(
|
||||
accountSettings,
|
||||
siteLanguageOptions,
|
||||
@@ -225,6 +242,11 @@ export const accountSettingsPageSelector = createSelector(
|
||||
timeZoneOptions,
|
||||
countryTimeZoneOptions,
|
||||
activeAccount,
|
||||
nameChangeModal,
|
||||
verifiedName,
|
||||
mostRecentVerifiedName,
|
||||
verifiedNameHistory,
|
||||
verifiedNameSettings,
|
||||
) => ({
|
||||
siteLanguageOptions,
|
||||
siteLanguage,
|
||||
@@ -241,16 +263,23 @@ export const accountSettingsPageSelector = createSelector(
|
||||
profileDataManager,
|
||||
staticFields,
|
||||
tpaProviders: accountSettings.thirdPartyAuth.providers,
|
||||
nameChangeModal,
|
||||
verifiedName,
|
||||
mostRecentVerifiedName,
|
||||
verifiedNameHistory,
|
||||
verifiedNameEnabled: verifiedNameSettings?.verifiedNameEnabled,
|
||||
}),
|
||||
);
|
||||
|
||||
export const certPreferenceSelector = createSelector(
|
||||
verifiedNameSettingsSelector,
|
||||
valuesSelector,
|
||||
formValuesSelector,
|
||||
mostRecentApprovedVerifiedNameValueSelector,
|
||||
saveStateSelector,
|
||||
errorSelector,
|
||||
(
|
||||
verifiedNameSettings,
|
||||
committedValues,
|
||||
formValues,
|
||||
mostRecentApprovedVerifiedNameValue,
|
||||
@@ -261,7 +290,7 @@ export const certPreferenceSelector = createSelector(
|
||||
originalVerifiedName: mostRecentApprovedVerifiedNameValue?.verified_name || '',
|
||||
useVerifiedNameForCerts: formValues.useVerifiedNameForCerts || false,
|
||||
saveState,
|
||||
verifiedNameEnabled: formValues.verifiedNameHistory?.verified_name_enabled || false,
|
||||
verifiedNameEnabled: verifiedNameSettings.verifiedNameEnabled || false,
|
||||
formErrors: errors,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -240,7 +240,6 @@ export async function getSettings(username, userRoles, userId) {
|
||||
shouldDisplayDemographicsQuestionsResponse,
|
||||
demographics,
|
||||
demographicsOptions,
|
||||
verifiedNameHistory,
|
||||
] = await Promise.all([
|
||||
getAccount(username),
|
||||
getPreferences(username),
|
||||
@@ -251,7 +250,6 @@ export async function getSettings(username, userRoles, userId) {
|
||||
getConfig().ENABLE_DEMOGRAPHICS_COLLECTION && shouldDisplayDemographicsQuestions(),
|
||||
getConfig().ENABLE_DEMOGRAPHICS_COLLECTION && getDemographics(userId),
|
||||
getConfig().ENABLE_DEMOGRAPHICS_COLLECTION && getDemographicsOptions(),
|
||||
getVerifiedNameHistory(),
|
||||
]);
|
||||
|
||||
return {
|
||||
@@ -264,7 +262,6 @@ export async function getSettings(username, userRoles, userId) {
|
||||
shouldDisplayDemographicsSection: shouldDisplayDemographicsQuestionsResponse,
|
||||
...demographics,
|
||||
demographicsOptions,
|
||||
verifiedNameHistory,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import { requestNameChange, requestNameChangeFailure, requestNameChangeReset } f
|
||||
import messages from './messages';
|
||||
|
||||
function NameChangeModal({
|
||||
targetFormId,
|
||||
errors,
|
||||
formValues,
|
||||
intl,
|
||||
@@ -30,7 +31,7 @@ function NameChangeModal({
|
||||
const dispatch = useDispatch();
|
||||
const { push } = useHistory();
|
||||
const { username } = getAuthenticatedUser();
|
||||
const [verifiedNameInput, setVerifiedNameInput] = useState('');
|
||||
const [verifiedNameInput, setVerifiedNameInput] = useState(formValues.verified_name || '');
|
||||
const [confirmedWarning, setConfirmedWarning] = useState(false);
|
||||
|
||||
function resetLocalState() {
|
||||
@@ -44,7 +45,7 @@ function NameChangeModal({
|
||||
|
||||
function handleClose() {
|
||||
resetLocalState();
|
||||
dispatch(closeForm('name'));
|
||||
dispatch(closeForm(targetFormId));
|
||||
dispatch(saveSettingsReset());
|
||||
}
|
||||
|
||||
@@ -60,7 +61,8 @@ function NameChangeModal({
|
||||
verified_name: intl.formatMessage(messages['account.settings.name.change.error.valid.name']),
|
||||
}));
|
||||
} else {
|
||||
dispatch(requestNameChange(username, formValues.name, verifiedNameInput));
|
||||
const draftProfileName = targetFormId === 'name' ? formValues.name : null;
|
||||
dispatch(requestNameChange(username, draftProfileName, verifiedNameInput));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,8 +186,12 @@ function NameChangeModal({
|
||||
}
|
||||
|
||||
NameChangeModal.propTypes = {
|
||||
targetFormId: PropTypes.string.isRequired,
|
||||
errors: PropTypes.shape({}).isRequired,
|
||||
formValues: PropTypes.shape({ name: PropTypes.string }).isRequired,
|
||||
formValues: PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
verified_name: PropTypes.string,
|
||||
}).isRequired,
|
||||
saveState: PropTypes.string,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
@@ -2,9 +2,9 @@ import { AsyncActionType } from '../../data/utils';
|
||||
|
||||
export const REQUEST_NAME_CHANGE = new AsyncActionType('ACCOUNT_SETTINGS', 'REQUEST_NAME_CHANGE');
|
||||
|
||||
export const requestNameChange = (username, newName, verifiedName) => ({
|
||||
export const requestNameChange = (username, profileName, verifiedName) => ({
|
||||
type: REQUEST_NAME_CHANGE.BASE,
|
||||
payload: { username, newName, verifiedName },
|
||||
payload: { username, profileName, verifiedName },
|
||||
});
|
||||
|
||||
export const requestNameChangeBegin = () => ({
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { put, call, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { postVerifiedName } from '../../data/service';
|
||||
|
||||
import {
|
||||
@@ -11,13 +13,17 @@ import {
|
||||
import { postNameChange } from './service';
|
||||
|
||||
export function* handleRequestNameChange(action) {
|
||||
let { name: profileName } = getAuthenticatedUser();
|
||||
try {
|
||||
yield put(requestNameChangeBegin());
|
||||
yield call(postNameChange, action.payload.newName);
|
||||
if (action.payload.profileName) {
|
||||
yield call(postNameChange, action.payload.profileName);
|
||||
profileName = action.payload.profileName;
|
||||
}
|
||||
yield call(postVerifiedName, {
|
||||
username: action.payload.username,
|
||||
verified_name: action.payload.verifiedName,
|
||||
profile_name: action.payload.newName,
|
||||
profile_name: profileName,
|
||||
});
|
||||
yield put(requestNameChangeSuccess());
|
||||
} catch (err) {
|
||||
|
||||
@@ -48,8 +48,12 @@ describe('NameChange', () => {
|
||||
beforeEach(() => {
|
||||
store = mockStore();
|
||||
props = {
|
||||
targetFormId: 'test_form',
|
||||
errors: {},
|
||||
formValues: { name: 'edx edx' },
|
||||
formValues: {
|
||||
name: 'edx edx',
|
||||
verified_name: 'edX Verified',
|
||||
},
|
||||
saveState: null,
|
||||
intl: {},
|
||||
};
|
||||
@@ -65,7 +69,7 @@ describe('NameChange', () => {
|
||||
|
||||
afterEach(() => jest.clearAllMocks());
|
||||
|
||||
it('renders input after clicking continue', async () => {
|
||||
it('renders populated input after clicking continue if verified_name in form data', async () => {
|
||||
const getInput = () => screen.queryByPlaceholderText('Enter the name on your government ID');
|
||||
|
||||
render(reduxWrapper(<IntlNameChange {...props} />));
|
||||
@@ -74,13 +78,29 @@ describe('NameChange', () => {
|
||||
const continueButton = screen.getByText('Continue');
|
||||
fireEvent.click(continueButton);
|
||||
|
||||
expect(getInput()).toBeTruthy();
|
||||
expect(getInput().value).toBe('edX Verified');
|
||||
});
|
||||
|
||||
it('dispatches action on submit', async () => {
|
||||
it('renders empty input after clicking continue if verified_name not in form data', async () => {
|
||||
const getInput = () => screen.queryByPlaceholderText('Enter the name on your government ID');
|
||||
const formProps = {
|
||||
...props,
|
||||
formValues: {
|
||||
name: 'edx edx',
|
||||
},
|
||||
};
|
||||
render(reduxWrapper(<IntlNameChange {...formProps} />));
|
||||
|
||||
const continueButton = screen.getByText('Continue');
|
||||
fireEvent.click(continueButton);
|
||||
|
||||
expect(getInput().value).toBe('');
|
||||
});
|
||||
|
||||
it('dispatches verifiedName on submit if targetForm is not "name"', async () => {
|
||||
const dispatchData = {
|
||||
payload: {
|
||||
newName: 'edx edx',
|
||||
profileName: null,
|
||||
username: 'edx',
|
||||
verifiedName: 'Verified Name',
|
||||
},
|
||||
@@ -100,6 +120,33 @@ describe('NameChange', () => {
|
||||
expect(mockDispatch).toHaveBeenCalledWith(dispatchData);
|
||||
});
|
||||
|
||||
it('dispatches both profileName and verifiedName on submit if the targetForm is "name"', async () => {
|
||||
const dispatchData = {
|
||||
payload: {
|
||||
profileName: 'edx edx',
|
||||
username: 'edx',
|
||||
verifiedName: 'Verified Name',
|
||||
},
|
||||
type: 'ACCOUNT_SETTINGS__REQUEST_NAME_CHANGE',
|
||||
};
|
||||
const formProps = {
|
||||
...props,
|
||||
targetFormId: 'name',
|
||||
};
|
||||
|
||||
render(reduxWrapper(<IntlNameChange {...formProps} />));
|
||||
|
||||
const continueButton = screen.getByText('Continue');
|
||||
fireEvent.click(continueButton);
|
||||
|
||||
const input = screen.getByPlaceholderText('Enter the name on your government ID');
|
||||
fireEvent.change(input, { target: { value: 'Verified Name' } });
|
||||
|
||||
const submitButton = screen.getByText('Continue');
|
||||
fireEvent.click(submitButton);
|
||||
expect(mockDispatch).toHaveBeenCalledWith(dispatchData);
|
||||
});
|
||||
|
||||
it('does not dispatch action while pending', async () => {
|
||||
props.saveState = 'pending';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user