diff --git a/client/coral-embed-stream/src/actions/login.js b/client/coral-embed-stream/src/actions/login.js
index 84c98ea78..c602bf7b6 100644
--- a/client/coral-embed-stream/src/actions/login.js
+++ b/client/coral-embed-stream/src/actions/login.js
@@ -1,8 +1,4 @@
-import jwtDecode from 'jwt-decode';
-import bowser from 'bowser';
import * as actions from '../constants/login';
-import { notify } from 'coral-framework/actions/notification';
-import t from 'coral-framework/services/i18n';
import { checkLogin } from 'coral-framework/actions/auth';
export const showSignInDialog = () => ({
@@ -10,15 +6,7 @@ export const showSignInDialog = () => ({
});
export const hideSignInDialog = () => dispatch => {
- if (window.opener && window.opener !== window) {
- // TODO: We need to address this when we refactor the
- // login popup out of the embed.
-
- // we are in a popup
- window.close();
- } else {
- dispatch(checkLogin());
- }
+ dispatch(checkLogin());
dispatch({ type: actions.HIDE_SIGNIN_DIALOG });
};
@@ -29,325 +17,3 @@ export const focusSignInDialog = () => ({
export const blurSignInDialog = () => ({
type: actions.BLUR_SIGNIN_DIALOG,
});
-
-// TODO: remove the rest.
-
-export const updateStatus = status => ({
- type: actions.UPDATE_STATUS,
- status,
-});
-
-export const resetSignInDialog = () => dispatch => {
- dispatch({ type: actions.HIDE_SIGNIN_DIALOG });
-};
-
-export const showCreateUsernameDialog = () => ({
- type: actions.SHOW_CREATEUSERNAME_DIALOG,
-});
-
-export const hideCreateUsernameDialog = () => ({
- type: actions.HIDE_CREATEUSERNAME_DIALOG,
-});
-
-export const updateUsername = username => ({
- type: actions.UPDATE_USERNAME,
- username,
-});
-
-export const changeView = view => dispatch => {
- dispatch({
- type: actions.CHANGE_VIEW,
- view,
- });
-
- switch (view) {
- case 'SIGNUP':
- window.resizeTo(500, 800);
- break;
- case 'FORGOT':
- window.resizeTo(500, 400);
- break;
- default:
- window.resizeTo(500, 550);
- }
-};
-
-export const cleanState = () => ({
- type: actions.CLEAN_STATE,
-});
-
-// Sign In Actions
-
-const signInRequest = email => ({
- type: actions.FETCH_SIGNIN_REQUEST,
- email,
-});
-
-const signInFailure = error => ({
- type: actions.FETCH_SIGNIN_FAILURE,
- error,
-});
-
-//==============================================================================
-// AUTH TOKEN
-//==============================================================================
-
-export const handleAuthToken = token => (dispatch, _, { localStorage }) => {
- if (localStorage) {
- localStorage.setItem('exp', jwtDecode(token).exp);
- localStorage.setItem('token', token);
- }
-
- dispatch({ type: 'HANDLE_AUTH_TOKEN' });
-};
-
-//==============================================================================
-// SIGN IN
-//==============================================================================
-
-export const fetchSignIn = formData => {
- return (dispatch, _, { rest }) => {
- dispatch(signInRequest(formData.email));
-
- return rest('/auth/local', { method: 'POST', body: formData })
- .then(({ token }) => {
- if (!bowser.safari && !bowser.ios) {
- dispatch(handleAuthToken(token));
- }
- dispatch(hideSignInDialog());
- })
- .catch(error => {
- console.error(error);
- if (error.metadata) {
- // the user might not have a valid email. prompt the user user re-request the confirmation email
- dispatch(
- signInFailure(t('error.email_not_verified', error.metadata))
- );
- } else if (error.translation_key === 'NOT_AUTHORIZED') {
- // invalid credentials
- dispatch(signInFailure(t('error.email_password'), error.metadata));
- } else {
- dispatch(signInFailure(error));
- }
- });
- };
-};
-
-//==============================================================================
-// SIGN IN - FACEBOOK
-//==============================================================================
-
-const signInFacebookRequest = () => ({
- type: actions.FETCH_SIGNIN_FACEBOOK_REQUEST,
-});
-
-const signInFacebookSuccess = user => ({
- type: actions.FETCH_SIGNIN_FACEBOOK_SUCCESS,
- user,
-});
-
-const signInFacebookFailure = error => ({
- type: actions.FETCH_SIGNIN_FACEBOOK_FAILURE,
- error,
-});
-
-export const fetchSignInFacebook = () => (dispatch, _, { rest }) => {
- dispatch(signInFacebookRequest());
- window.open(
- `${rest.uri}/auth/facebook`,
- 'Continue with Facebook',
- 'menubar=0,resizable=0,width=500,height=500,top=200,left=500'
- );
-};
-
-//==============================================================================
-// SIGN UP - FACEBOOK
-//==============================================================================
-
-const signUpFacebookRequest = () => ({
- type: actions.FETCH_SIGNUP_FACEBOOK_REQUEST,
-});
-
-export const fetchSignUpFacebook = () => (dispatch, _, { rest }) => {
- dispatch(signUpFacebookRequest());
- window.open(
- `${rest.uri}/auth/facebook`,
- 'Continue with Facebook',
- 'menubar=0,resizable=0,width=500,height=500,top=200,left=500'
- );
-};
-
-export const facebookCallback = (err, data) => dispatch => {
- if (err) {
- dispatch(signInFacebookFailure(err));
- return;
- }
- try {
- dispatch(handleAuthToken(data.token));
- dispatch(signInFacebookSuccess(data.user));
- dispatch(hideSignInDialog());
- } catch (err) {
- dispatch(signInFacebookFailure(err));
- return;
- }
-};
-
-//==============================================================================
-// SIGN UP
-//==============================================================================
-
-const signUpRequest = () => ({ type: actions.FETCH_SIGNUP_REQUEST });
-const signUpSuccess = user => ({ type: actions.FETCH_SIGNUP_SUCCESS, user });
-const signUpFailure = error => ({ type: actions.FETCH_SIGNUP_FAILURE, error });
-
-export const fetchSignUp = formData => (dispatch, getState, { rest }) => {
- const redirectUri = getState().auth.redirectUri;
- dispatch(signUpRequest());
-
- rest('/users', {
- method: 'POST',
- body: formData,
- headers: { 'X-Pym-Url': redirectUri },
- })
- .then(({ user }) => {
- dispatch(signUpSuccess(user));
- })
- .catch(error => {
- console.error(error);
- const errorMessage = error.translation_key
- ? t(`error.${error.translation_key}`)
- : error.toString();
- dispatch(signUpFailure(errorMessage));
- });
-};
-
-//==============================================================================
-// FORGOT PASSWORD
-//==============================================================================
-
-const forgotPasswordRequest = () => ({
- type: actions.FETCH_FORGOT_PASSWORD_REQUEST,
-});
-
-const forgotPasswordSuccess = () => ({
- type: actions.FETCH_FORGOT_PASSWORD_SUCCESS,
-});
-
-const forgotPasswordFailure = error => ({
- type: actions.FETCH_FORGOT_PASSWORD_FAILURE,
- error,
-});
-
-export const fetchForgotPassword = email => (dispatch, getState, { rest }) => {
- dispatch(forgotPasswordRequest(email));
- const redirectUri = getState().auth.redirectUri;
- rest('/account/password/reset', {
- method: 'POST',
- body: { email, loc: redirectUri },
- })
- .then(() => dispatch(forgotPasswordSuccess()))
- .catch(error => {
- console.error(error);
- const errorMessage = error.translation_key
- ? t(`error.${error.translation_key}`)
- : error.toString();
- dispatch(forgotPasswordFailure(errorMessage));
- });
-};
-
-//==============================================================================
-// LOGOUT
-//==============================================================================
-
-export const logout = () => async (
- dispatch,
- _,
- { rest, client, pym, localStorage }
-) => {
- await rest('/auth', { method: 'DELETE' });
-
- if (localStorage) {
- localStorage.removeItem('token');
- localStorage.removeItem('exp');
- }
-
- // Reset the websocket.
- client.resetWebsocket();
-
- dispatch({ type: actions.LOGOUT });
- pym.sendMessage('coral-auth-changed');
-};
-
-export const validForm = () => ({ type: actions.VALID_FORM });
-export const invalidForm = error => ({ type: actions.INVALID_FORM, error });
-
-//==============================================================================
-// VERIFY EMAIL
-//==============================================================================
-
-const verifyEmailRequest = () => ({
- type: actions.VERIFY_EMAIL_REQUEST,
-});
-
-const verifyEmailSuccess = () => ({
- type: actions.VERIFY_EMAIL_SUCCESS,
-});
-
-const verifyEmailFailure = error => ({
- type: actions.VERIFY_EMAIL_FAILURE,
- error,
-});
-
-export const requestConfirmEmail = email => (dispatch, getState, { rest }) => {
- const redirectUri = getState().auth.redirectUri;
- dispatch(verifyEmailRequest());
- return rest('/users/resend-verify', {
- method: 'POST',
- body: { email },
- headers: { 'X-Pym-Url': redirectUri },
- })
- .then(() => {
- dispatch(verifyEmailSuccess());
- })
- .catch(error => {
- console.error(error);
- dispatch(verifyEmailFailure(error));
- throw error;
- });
-};
-
-// Login Popup actions.
-export const setRequireEmailVerification = required => ({
- type: actions.SET_REQUIRE_EMAIL_VERIFICATION,
- required,
-});
-
-export const setRedirectUri = uri => ({
- type: actions.SET_REDIRECT_URI,
- uri,
-});
-
-//==============================================================================
-// Edit Username
-//==============================================================================
-
-const editUsernameFailure = error => ({
- type: actions.EDIT_USERNAME_FAILURE,
- error,
-});
-const editUsernameSuccess = () => ({ type: actions.EDIT_USERNAME_SUCCESS });
-
-export const editName = username => (dispatch, _, { rest }) => {
- return rest('/account/username', { method: 'PUT', body: { username } })
- .then(() => {
- dispatch(editUsernameSuccess());
- dispatch(notify('success', t('framework.success_name_update')));
- })
- .catch(error => {
- console.error(error);
- const errorMessage = error.translation_key
- ? t(`error.${error.translation_key}`)
- : error.toString();
- dispatch(editUsernameFailure(errorMessage));
- });
-};
diff --git a/client/coral-embed-stream/src/constants/login.js b/client/coral-embed-stream/src/constants/login.js
index 3187873fe..1ad142bc2 100644
--- a/client/coral-embed-stream/src/constants/login.js
+++ b/client/coral-embed-stream/src/constants/login.js
@@ -1,57 +1,4 @@
-export const CHANGE_VIEW = 'CHANGE_VIEW';
-export const CLEAN_STATE = 'CLEAN_STATE';
-
export const SHOW_SIGNIN_DIALOG = 'SHOW_SIGNIN_DIALOG';
export const HIDE_SIGNIN_DIALOG = 'HIDE_SIGNIN_DIALOG';
export const FOCUS_SIGNIN_DIALOG = 'FOCUS_SIGNIN_DIALOG';
export const BLUR_SIGNIN_DIALOG = 'BLUR_SIGNIN_DIALOG';
-
-export const CREATE_USERNAME_REQUEST = 'CREATE_USERNAME_REQUEST';
-export const CREATE_USERNAME_SUCCESS = 'CREATE_USERNAME_SUCCESS';
-export const CREATE_USERNAME_FAILURE = 'CREATE_USERNAME_FAILURE';
-export const CREATE_USERNAME = 'CREATE_USERNAME';
-export const SHOW_CREATEUSERNAME_DIALOG = 'SHOW_CREATEUSERNAME_DIALOG';
-export const HIDE_CREATEUSERNAME_DIALOG = 'HIDE_CREATEUSERNAME_DIALOG';
-
-export const EDIT_USERNAME_REQUEST = 'CREATE_USERNAME_REQUEST';
-export const EDIT_USERNAME_SUCCESS = 'CREATE_USERNAME_SUCCESS';
-export const EDIT_USERNAME_FAILURE = 'CREATE_USERNAME_FAILURE';
-export const EDIT_USERNAME = 'CREATE_USERNAME';
-
-export const FETCH_SIGNUP_REQUEST = 'FETCH_SIGNUP_REQUEST';
-export const FETCH_SIGNUP_FAILURE = 'FETCH_SIGNUP_FAILURE';
-export const FETCH_SIGNUP_SUCCESS = 'FETCH_SIGNUP_SUCCESS';
-
-export const FETCH_SIGNIN_REQUEST = 'FETCH_SIGNIN_REQUEST';
-export const FETCH_SIGNIN_FAILURE = 'FETCH_SIGNIN_FAILURE';
-export const FETCH_SIGNIN_SUCCESS = 'FETCH_SIGNIN_SUCCESS';
-
-export const FETCH_SIGNIN_FACEBOOK_REQUEST = 'FETCH_SIGNIN_FACEBOOK_REQUEST';
-export const FETCH_SIGNIN_FACEBOOK_FAILURE = 'FETCH_SIGNIN_FACEBOOK_FAILURE';
-export const FETCH_SIGNIN_FACEBOOK_SUCCESS = 'FETCH_SIGNIN_FACEBOOK_SUCCESS';
-
-export const FETCH_SIGNUP_FACEBOOK_REQUEST = 'FETCH_SIGNUP_FACEBOOK_REQUEST';
-export const FETCH_FORGOT_PASSWORD_REQUEST = 'FETCH_FORGOT_PASSWORD_REQUEST';
-export const FETCH_FORGOT_PASSWORD_SUCCESS = 'FETCH_FORGOT_PASSWORD_SUCCESS';
-export const FETCH_FORGOT_PASSWORD_FAILURE = 'FETCH_FORGOT_PASSWORD_FAILURE';
-
-export const LOGOUT = 'LOGOUT';
-
-export const INVALID_FORM = 'INVALID_FORM';
-export const VALID_FORM = 'VALID_FORM';
-
-export const CHECK_LOGIN_REQUEST = 'CHECK_LOGIN_REQUEST';
-export const CHECK_LOGIN_SUCCESS = 'CHECK_LOGIN_SUCCESS';
-export const CHECK_LOGIN_FAILURE = 'CHECK_LOGIN_FAILURE';
-
-export const VERIFY_EMAIL_REQUEST = 'VERIFY_EMAIL_REQUEST';
-export const VERIFY_EMAIL_SUCCESS = 'VERIFY_EMAIL_SUCCESS';
-export const VERIFY_EMAIL_FAILURE = 'VERIFY_EMAIL_FAILURE';
-export const UPDATE_USERNAME = 'UPDATE_USERNAME';
-
-// Login Popup actions.
-export const SET_REQUIRE_EMAIL_VERIFICATION = 'SET_REQUIRE_EMAIL_VERIFICATION';
-export const SET_REDIRECT_URI = 'SET_REDIRECT_URI';
-
-export const RESET_SIGNIN_DIALOG = 'RESET_SIGNIN_DIALOG';
-export const UPDATE_STATUS = 'UPDATE_STATUS';
diff --git a/client/coral-embed-stream/src/reducers/login.js b/client/coral-embed-stream/src/reducers/login.js
index febf4fd51..c24d36f96 100644
--- a/client/coral-embed-stream/src/reducers/login.js
+++ b/client/coral-embed-stream/src/reducers/login.js
@@ -1,34 +1,10 @@
import * as actions from '../constants/login';
import pym from 'coral-framework/services/pym';
-import merge from 'lodash/merge';
const initialState = {
parentUrl: pym.parentUrl || location.href,
showSignInDialog: false,
signInDialogFocus: false,
-
- // TODO: remove the rest
- isLoading: false,
- loggedIn: false,
- user: null,
- showCreateUsernameDialog: false,
- checkedInitialLogin: false,
- view: 'SIGNIN',
- error: null,
- passwordRequestSuccess: null,
- passwordRequestFailure: null,
- emailVerificationFailure: false,
- emailVerificationLoading: false,
- emailVerificationSuccess: false,
- successSignUp: false,
- fromSignUp: false,
- requireEmailConfirmation: false,
- redirectUri: pym.parentUrl || location.href,
-};
-
-const purge = user => {
- const {settings, ...userData} = user; // eslint-disable-line
- return userData;
};
export default function login(state = initialState, action) {
@@ -56,204 +32,6 @@ export default function login(state = initialState, action) {
showSignInDialog: false,
signInDialogFocus: false,
};
-
- // TODO: remove the rest.
- case actions.RESET_SIGNIN_DIALOG:
- return {
- ...state,
- isLoading: false,
- showSignInDialog: false,
- signInDialogFocus: false,
- view: 'SIGNIN',
- error: null,
- passwordRequestFailure: null,
- passwordRequestSuccess: null,
- emailVerificationFailure: false,
- emailVerificationSuccess: false,
- emailVerificationLoading: false,
- successSignUp: false,
- };
- case actions.SHOW_CREATEUSERNAME_DIALOG:
- return {
- ...state,
- showCreateUsernameDialog: true,
- };
- case actions.HIDE_CREATEUSERNAME_DIALOG:
- return {
- ...state,
- showCreateUsernameDialog: false,
- };
- case actions.CREATE_USERNAME_SUCCESS:
- return {
- ...state,
- showCreateUsernameDialog: false,
- error: null,
- };
- case actions.CREATE_USERNAME_FAILURE:
- return {
- ...state,
- error: action.error,
- };
- case actions.CHANGE_VIEW:
- return {
- ...state,
- error: action.error,
- view: action.view,
- };
- case actions.CLEAN_STATE:
- return initialState;
- case actions.FETCH_SIGNIN_REQUEST:
- return {
- ...state,
- email: action.email,
- isLoading: true,
- };
- case actions.CHECK_LOGIN_FAILURE:
- return {
- ...state,
- checkedInitialLogin: true,
- loggedIn: false,
- user: null,
- };
- case actions.CHECK_LOGIN_SUCCESS:
- return {
- ...state,
- checkedInitialLogin: true,
- loggedIn: true,
- user: purge(action.user),
- };
- case actions.FETCH_SIGNIN_SUCCESS:
- return {
- ...state,
- loggedIn: true,
- user: purge(action.user),
- };
- case actions.FETCH_SIGNIN_FAILURE:
- return {
- ...state,
- isLoading: false,
- error: action.error,
- user: null,
- view:
- action.error.translation_key === 'EMAIL_NOT_VERIFIED'
- ? 'RESEND_VERIFICATION'
- : state.view,
- };
- case actions.FETCH_SIGNUP_FACEBOOK_REQUEST:
- return {
- ...state,
- fromSignUp: true,
- };
- case actions.FETCH_SIGNIN_FACEBOOK_REQUEST:
- return {
- ...state,
- fromSignUp: false,
- };
- case actions.FETCH_SIGNIN_FACEBOOK_SUCCESS:
- return {
- ...state,
- loggedIn: true,
- user: purge(action.user),
- };
- case actions.FETCH_SIGNIN_FACEBOOK_FAILURE:
- return {
- ...state,
- error: action.error,
- user: null,
- };
- case actions.FETCH_SIGNUP_REQUEST:
- return {
- ...state,
- isLoading: true,
- };
- case actions.FETCH_SIGNUP_FAILURE:
- return {
- ...state,
- error: action.error,
- isLoading: false,
- };
- case actions.FETCH_SIGNUP_SUCCESS:
- return {
- ...state,
- isLoading: false,
- successSignUp: true,
- };
- case actions.LOGOUT:
- return {
- ...state,
- user: null,
- isLoading: false,
- loggedIn: false,
- };
- case actions.INVALID_FORM:
- return {
- ...state,
- error: action.error,
- };
- case actions.VALID_FORM:
- return {
- ...state,
- error: null,
- };
- case actions.FETCH_FORGOT_PASSWORD_SUCCESS:
- return {
- ...state,
- passwordRequestFailure: null,
- passwordRequestSuccess:
- 'If you have a registered account, a password reset link was sent to that email',
- };
- case actions.FETCH_FORGOT_PASSWORD_FAILURE:
- return {
- ...state,
- passwordRequestFailure:
- 'There was an error sending your password reset email. Please try again soon!',
- passwordRequestSuccess: null,
- };
- case actions.UPDATE_USERNAME:
- return {
- ...state,
- user: {
- ...state.user,
- username: action.username,
- lowercaseUsername: action.username.toLowerCase(),
- },
- };
- case actions.VERIFY_EMAIL_FAILURE:
- return {
- ...state,
- emailVerificationFailure: action.error,
- emailVerificationLoading: false,
- };
- case actions.VERIFY_EMAIL_REQUEST:
- return {
- ...state,
- emailVerificationLoading: true,
- };
- case actions.VERIFY_EMAIL_SUCCESS:
- return {
- ...state,
- emailVerificationSuccess: true,
- emailVerificationLoading: false,
- };
- case actions.SET_REQUIRE_EMAIL_VERIFICATION:
- return {
- ...state,
- requireEmailConfirmation: action.required,
- };
- case actions.SET_REDIRECT_URI:
- return {
- ...state,
- redirectUri: action.uri,
- };
- case actions.UPDATE_STATUS: {
- return {
- ...state,
- user: {
- ...state.user,
- status: merge({}, state.user.status, action.status),
- },
- };
- }
default:
return state;
}
diff --git a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js
index 6884bcd8e..06632dfcc 100644
--- a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js
+++ b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js
@@ -15,10 +15,7 @@ import {
withEditComment,
} from 'coral-framework/graphql/mutations';
-import {
- showSignInDialog,
- editName,
-} from 'coral-embed-stream/src/actions/login';
+import { showSignInDialog } from 'coral-embed-stream/src/actions/login';
import { notify } from 'coral-framework/actions/notification';
import {
setActiveReplyBox,
@@ -465,7 +462,6 @@ const mapDispatchToProps = dispatch =>
showSignInDialog,
notify,
setActiveReplyBox,
- editName,
viewAllComments,
setActiveStreamTab: setActiveTab,
},
diff --git a/client/coral-framework/hocs/index.js b/client/coral-framework/hocs/index.js
index c8b8f6bb6..eb481de99 100644
--- a/client/coral-framework/hocs/index.js
+++ b/client/coral-framework/hocs/index.js
@@ -9,6 +9,7 @@ export { default as withMergedSettings } from './withMergedSettings';
export { default as withSignIn } from './withSignIn';
export { default as withSignUp } from './withSignUp';
export { default as withForgotPassword } from './withForgotPassword';
+export { default as withSetUsername } from './withSetUsername';
export {
default as withResendEmailConfirmation,
} from './withResendEmailConfirmation';
diff --git a/client/coral-framework/hocs/withSetUsername.js b/client/coral-framework/hocs/withSetUsername.js
new file mode 100644
index 000000000..2cec90c00
--- /dev/null
+++ b/client/coral-framework/hocs/withSetUsername.js
@@ -0,0 +1,100 @@
+import React from 'react';
+import hoistStatics from 'recompose/hoistStatics';
+import PropTypes from 'prop-types';
+import { getErrorMessages } from '../utils';
+import validate from '../helpers/validate';
+import errorMsg from 'coral-framework/helpers/error';
+import t from '../services/i18n';
+import { withSetUsername as withSetUsernameMutation } from 'coral-framework/graphql/mutations';
+import { updateUsername, updateStatus } from '../actions/auth';
+import { compose } from 'recompose';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import get from 'lodash/get';
+
+/**
+ * withSetUsername provides properties
+ * `setUsername`,
+ * `loading`,
+ * `errorMessage`,
+ * `requireEmailVerification`,
+ * `success`,
+ * `validate`.
+ */
+const withSetUsername = hoistStatics(WrappedComponent => {
+ class WithSetUsername extends React.Component {
+ static propTypes = {
+ setUsername: PropTypes.func.isRequired,
+ currentUserId: PropTypes.string,
+ updateUsername: PropTypes.func.isRequired,
+ updateStatus: PropTypes.func.isRequired,
+ };
+
+ state = {
+ error: null,
+ loading: false,
+ success: false,
+ };
+
+ validateUsername = value => {
+ if (!value) {
+ return t('sign_in.required_field');
+ }
+ return validate.username(value) ? '' : errorMsg.username;
+ };
+
+ setUsername = async username => {
+ if (!this.props.currentUserId) {
+ throw new Error('User not logged in');
+ }
+
+ try {
+ await this.props.setUsername(this.props.currentUserId, username);
+ this.props.updateUsername(username);
+ this.props.updateStatus({ username: { status: 'SET' } });
+ this.setState({ success: true, loading: false, error: null });
+ } catch (error) {
+ if (!error.status || error.status !== 401) {
+ console.error(error);
+ }
+ const changeSet = { success: false, loading: false, error };
+ this.setState(changeSet);
+ }
+ };
+
+ getErrorMessage() {
+ if (!this.state.error) {
+ return '';
+ }
+ return getErrorMessages(this.state.error).join(', ');
+ }
+
+ render() {
+ return (
+