Add distinct thunks for email and phone updates

This commit is contained in:
Hannu Lyytikainen 2018-04-05 07:45:30 +03:00
parent 70c5f559d7
commit 14669b389f
3 changed files with 139 additions and 14 deletions

View file

@ -1,3 +1,4 @@
import merge from 'lodash/merge';
import { storableError } from '../../util/errors';
import { currentUserShowSuccess } from '../../ducks/user.duck';
@ -5,14 +6,16 @@ import { currentUserShowSuccess } from '../../ducks/user.duck';
export const SAVE_CONTACT_DETAILS_REQUEST = 'app/ContactDetailsPage/SAVE_CONTACT_DETAILS_REQUEST';
export const SAVE_CONTACT_DETAILS_SUCCESS = 'app/ContactDetailsPage/SAVE_CONTACT_DETAILS_SUCCESS';
export const SAVE_CONTACT_DETAILS_ERROR = 'app/ContactDetailsPage/SAVE_CONTACT_DETAILS_ERROR';
export const SAVE_EMAIL_ERROR = 'app/ContactDetailsPage/SAVE_EMAIL_ERROR';
export const SAVE_PHONE_NUMBER_ERROR = 'app/ContactDetailsPage/SAVE_PHONE_NUMBER_ERROR';
export const SAVE_CONTACT_DETAILS_CLEAR = 'app/ContactDetailsPage/SAVE_CONTACT_DETAILS_CLEAR';
// ================ Reducer ================ //
const initialState = {
saveContactDetailsError: null,
saveEmailError: null,
savePhoneNumberError: null,
saveContactDetailsInProgress: false,
contactDetailsChanged: false,
};
@ -29,8 +32,10 @@ export default function reducer(state = initialState, action = {}) {
};
case SAVE_CONTACT_DETAILS_SUCCESS:
return { ...state, saveContactDetailsInProgress: false, contactDetailsChanged: true };
case SAVE_CONTACT_DETAILS_ERROR:
return { ...state, saveContactDetailsInProgress: false, saveContactDetailsError: payload };
case SAVE_EMAIL_ERROR:
return { ...state, saveContactDetailsInProgress: false, saveEmailError: payload };
case SAVE_PHONE_NUMBER_ERROR:
return { ...state, saveContactDetailsInProgress: false, savePhoneNumberError: payload };
case SAVE_CONTACT_DETAILS_CLEAR:
return {
@ -49,8 +54,13 @@ export default function reducer(state = initialState, action = {}) {
export const saveContactDetailsRequest = () => ({ type: SAVE_CONTACT_DETAILS_REQUEST });
export const saveContactDetailsSuccess = () => ({ type: SAVE_CONTACT_DETAILS_SUCCESS });
export const saveContactDetailsError = error => ({
type: SAVE_CONTACT_DETAILS_ERROR,
export const saveEmailError = error => ({
type: SAVE_EMAIL_ERROR,
payload: error,
error: true,
});
export const savePhoneNumberError = error => ({
type: SAVE_PHONE_NUMBER_ERROR,
payload: error,
error: true,
});
@ -59,16 +69,104 @@ export const saveContactDetailsClear = () => ({ type: SAVE_CONTACT_DETAILS_CLEAR
// ================ Thunks ================ //
export const saveContactDetails = params => (dispatch, getState, sdk) => {
dispatch(saveContactDetailsRequest());
/**
* Make a phone number update request to the API and return the current user.
*/
const requestSavePhoneNumber = params => (dispatch, getState, sdk) => {
const phoneNumber = params.phoneNumber;
return sdk.currentUser
.updateProfile({ protectedData: { phoneNumber } }, { expand: true })
.then(response => {
// return user
return response.data.data;
})
.catch(e => {
dispatch(savePhoneNumberError(storableError(e)));
// pass the same error so that the SAVE_CONTACT_DETAILS_SUCCESS
// action will not be fired
throw e;
});
};
/**
* Make a email update request to the API and return the current user.
*/
const requestSaveEmail = params => (dispatch, getState, sdk) => {
const { email, currentPassword } = params;
return sdk.currentUser
.changeEmail({ email, currentPassword }, { expand: true })
.then(response => {
const currentUser = response.data.data;
dispatch(saveContactDetailsSuccess());
dispatch(currentUserShowSuccess(currentUser));
// return user
return response.data.data;
})
.catch(e => dispatch(saveContactDetailsError(storableError(e))));
.catch(e => {
dispatch(saveEmailError(storableError(e)));
// pass the same error so that the SAVE_CONTACT_DETAILS_SUCCESS
// action will not be fired
throw e;
});
};
/**
* Save email and update the current user.
*/
export const saveEmail = params => (dispatch, getState, sdk) => {
dispatch(saveContactDetailsRequest());
return dispatch(requestSaveEmail(params))
.then(user => {
dispatch(currentUserShowSuccess(user));
dispatch(saveContactDetailsSuccess());
})
.catch(e => null);
};
/**
* Save phone number and update the current user.
*/
export const savePhoneNumber = params => (dispatch, getState, sdk) => {
dispatch(saveContactDetailsRequest());
return dispatch(requestSavePhoneNumber(params))
.then(user => {
dispatch(currentUserShowSuccess(user));
dispatch(saveContactDetailsSuccess());
})
.catch(e => null);
};
/**
* Save email and phone number and update the current user.
*/
export const saveContactDetails = params => (dispatch, getState, sdk) => {
dispatch(saveContactDetailsRequest());
const { email, phoneNumber, currentPassword } = params;
// order of promises: 1. email, 2. phone number
const promises = [
dispatch(requestSaveEmail({ email, currentPassword })),
dispatch(requestSavePhoneNumber({ phoneNumber })),
];
return Promise.all(promises)
.then(values => {
// Array of two user objects is resolved
// the first one is from the email update
// the second one is from the phone number update
const saveEmailUser = values[0];
const savePhoneNumberUser = values[1];
// merge the protected data from the user object returned
// by the phone update operation
const protectedData = savePhoneNumberUser.attributes.profile.protectedData;
const phoneNumberMergeSource = { attributes: { profile: { protectedData } } };
const currentUser = merge(saveEmailUser, phoneNumberMergeSource);
dispatch(currentUserShowSuccess(currentUser));
dispatch(saveContactDetailsSuccess());
})
.catch(e => null);
};

View file

@ -19,7 +19,12 @@ import {
import { ContactDetailsForm, TopbarContainer } from '../../containers';
import { isScrollingDisabled } from '../../ducks/UI.duck';
import { saveContactDetails, saveContactDetailsClear } from './ContactDetailsPage.duck';
import {
saveContactDetails,
saveContactDetailsClear,
saveEmail,
savePhoneNumber,
} from './ContactDetailsPage.duck';
import css from './ContactDetailsPage.css';
export const ContactDetailsPageComponent = props => {
@ -34,9 +39,25 @@ export const ContactDetailsPageComponent = props => {
sendVerificationEmailError,
onResendVerificationEmail,
onSubmitContactDetails,
onSubmitEmail,
onSubmitPhoneNumber,
intl,
} = props;
const handleSubmit = (values, currentEmail, currentPhoneNumber) => {
const { email, currentPassword, phoneNumber } = values;
const emailChanged = email !== currentEmail;
const phoneNumberChanged = phoneNumber !== currentPhoneNumber;
if (emailChanged && phoneNumberChanged) {
onSubmitContactDetails({ email, currentPassword, phoneNumber });
} else if (emailChanged) {
onSubmitEmail({ email, currentPassword });
} else if (phoneNumberChanged) {
onSubmitPhoneNumber({ phoneNumber });
}
};
const tabs = [
{
text: <FormattedMessage id="ContactDetailsPage.contactDetailsTabTitle" />,
@ -72,7 +93,7 @@ export const ContactDetailsPageComponent = props => {
saveContactDetailsError={saveContactDetailsError}
currentUser={currentUser}
onResendVerificationEmail={onResendVerificationEmail}
onSubmit={onSubmitContactDetails}
onSubmit={values => handleSubmit(values, email, phoneNumber)}
onChange={onChange}
inProgress={saveContactDetailsInProgress}
ready={contactDetailsChanged}
@ -126,6 +147,8 @@ ContactDetailsPageComponent.propTypes = {
contactDetailsChanged: bool.isRequired,
onChange: func.isRequired,
onSubmitContactDetails: func.isRequired,
onSubmitEmail: func.isRequired,
onSubmitPhoneNumber: func.isRequired,
scrollingDisabled: bool.isRequired,
sendVerificationEmailInProgress: bool.isRequired,
sendVerificationEmailError: propTypes.error,
@ -158,6 +181,8 @@ const mapDispatchToProps = dispatch => ({
onChange: () => dispatch(saveContactDetailsClear()),
onResendVerificationEmail: () => dispatch(sendVerificationEmail()),
onSubmitContactDetails: values => dispatch(saveContactDetails(values)),
onSubmitEmail: values => dispatch(saveEmail(values)),
onSubmitPhoneNumber: values => dispatch(savePhoneNumber(values)),
});
const ContactDetailsPage = compose(connect(mapStateToProps, mapDispatchToProps), injectIntl)(

View file

@ -22,6 +22,8 @@ describe('ContactDetailsPage', () => {
sendVerificationEmailInProgress={false}
onResendVerificationEmail={noop}
onSubmitContactDetails={noop}
onSubmitEmail={noop}
onSubmitPhoneNumber={noop}
saveContactDetailsInProgress={false}
contactDetailsChanged={false}
intl={fakeIntl}