From a40b28722686b4cb9d7e86469f6df2a52adc8f5d Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 8 Jan 2018 18:52:00 +0100 Subject: [PATCH 1/2] Use correct mutation and show errors --- client/coral-framework/graphql/fragments.js | 1 + client/coral-framework/graphql/mutations.js | 20 ++++++++++++++++ .../client/components/ChangeUsername.js | 24 +++++++++++++++---- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/client/coral-framework/graphql/fragments.js b/client/coral-framework/graphql/fragments.js index 9d6ff3f72..3f478677e 100644 --- a/client/coral-framework/graphql/fragments.js +++ b/client/coral-framework/graphql/fragments.js @@ -5,6 +5,7 @@ export default { ...createDefaultResponseFragments( 'SetUserRoleResponse', 'ChangeUsernameResponse', + 'SetUsernameResponse', 'BanUsersResponse', 'UnbanUserResponse', 'SetUserSuspensionStatusResponse', diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index 27b10669b..794363931 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -254,6 +254,26 @@ export const withChangeUsername = withMutation( }) }); +export const withSetUsername = withMutation( + gql` + mutation SetUsername($id: ID!, $username: String!) { + setUsername(id: $id, username: $username) { + ...SetUsernameResponse + } + } + `, { + props: ({mutate}) => ({ + setUsername: (id, username) => { + return mutate({ + variables: { + id, + username, + }, + }); + } + }) + }); + export const withBanUser = withMutation( gql` mutation BanUser($input: BanUserInput!) { diff --git a/plugins/talk-plugin-auth/client/components/ChangeUsername.js b/plugins/talk-plugin-auth/client/components/ChangeUsername.js index 95f1393e9..9d9b124b8 100644 --- a/plugins/talk-plugin-auth/client/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/components/ChangeUsername.js @@ -6,7 +6,8 @@ import {bindActionCreators} from 'redux'; import errorMsj from 'coral-framework/helpers/error'; import validate from 'coral-framework/helpers/validate'; import CreateUsernameDialog from './CreateUsernameDialog'; -import {withChangeUsername} from 'coral-framework/graphql/mutations'; +import {withSetUsername} from 'coral-framework/graphql/mutations'; +import {forEachError} from 'plugin-api/beta/client/utils'; import t from 'coral-framework/services/i18n'; @@ -88,21 +89,34 @@ class ChangeUsernameContainer extends React.Component { this.setState({showErrors: show}); }; + async setUsernameAndClose(username, props = this.props) { + const {validForm, invalidForm, setUsername, hideCreateUsernameDialog} = props; + try { + await setUsername(this.props.auth.user.id, username); + hideCreateUsernameDialog(); + validForm(); + } + catch(error) { + const msgs = []; + forEachError(error, ({msg}) => msgs.push(msg)); + invalidForm(t(msgs.join(', '))); + } + } + handleSubmitUsername = (e) => { e.preventDefault(); const {errors, formData: {username}} = this.state; const {validForm, invalidForm} = this.props; this.displayErrors(); if (this.isCompleted() && !Object.keys(errors).length) { - this.props.changeUsername(this.props.auth.user.id, username); - validForm(); + this.setUsernameAndClose(username); } else { invalidForm(t('createdisplay.check_the_form')); } }; handleClose = () => { - this.props.hideCreateUsernameDialog(); + this.setUsernameAndClose(this.props.auth.user.username); }; render() { @@ -148,6 +162,6 @@ const mapDispatchToProps = (dispatch) => ); export default compose( - withChangeUsername, + withSetUsername, connect(mapStateToProps, mapDispatchToProps) )(ChangeUsernameContainer); From a2eb474a5ce89cad4b3aba300988f749dfbd932b Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 9 Jan 2018 12:25:44 +0100 Subject: [PATCH 2/2] Fully implement SetUsername --- client/coral-embed-stream/src/actions/auth.js | 2 +- .../coral-embed-stream/src/reducers/auth.js | 3 ++- client/coral-framework/graphql/mutations.js | 21 +++++++++++++++++++ .../client/components/ChangeUsername.js | 14 ++++++++++--- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/client/coral-embed-stream/src/actions/auth.js b/client/coral-embed-stream/src/actions/auth.js index 64e29a31a..a597d2467 100644 --- a/client/coral-embed-stream/src/actions/auth.js +++ b/client/coral-embed-stream/src/actions/auth.js @@ -43,7 +43,7 @@ export const hideCreateUsernameDialog = () => ({ type: actions.HIDE_CREATEUSERNAME_DIALOG }); -export const updateUsername = ({username}) => ({ +export const updateUsername = (username) => ({ type: actions.UPDATE_USERNAME, username }); diff --git a/client/coral-embed-stream/src/reducers/auth.js b/client/coral-embed-stream/src/reducers/auth.js index 156c53515..76be05d40 100644 --- a/client/coral-embed-stream/src/reducers/auth.js +++ b/client/coral-embed-stream/src/reducers/auth.js @@ -198,6 +198,7 @@ export default function auth (state = initialState, action) { user: { ...state.user, username: action.username, + lowercaseUsername: action.username.toLowerCase(), } }; case actions.VERIFY_EMAIL_FAILURE: @@ -230,7 +231,7 @@ export default function auth (state = initialState, action) { case 'APOLLO_SUBSCRIPTION_RESULT': // @TODO: These don't work anymore because apollo store has been decoupled - + if (action.operationName === 'UserBanned' && state.user.id === action.variables.user_id) { return { ...state, diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index 794363931..30dc9df2b 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -234,6 +234,11 @@ export const withRejectUsername = withMutation( }) }); +const SetUsernameFragment = gql` + fragment Talk_SetUsername on User { + username + }`; + export const withChangeUsername = withMutation( gql` mutation ChangeUsername($id: ID!, $username: String!) { @@ -249,6 +254,14 @@ export const withChangeUsername = withMutation( id, username, }, + update: (proxy) => { + const fragmentId = `User_${id}`; + const data = { + __typename: 'User', + username, + }; + proxy.writeFragment({fragment: SetUsernameFragment, id: fragmentId, data}); + } }); } }) @@ -269,6 +282,14 @@ export const withSetUsername = withMutation( id, username, }, + update: (proxy) => { + const fragmentId = `User_${id}`; + const data = { + __typename: 'User', + username, + }; + proxy.writeFragment({fragment: SetUsernameFragment, id: fragmentId, data}); + } }); } }) diff --git a/plugins/talk-plugin-auth/client/components/ChangeUsername.js b/plugins/talk-plugin-auth/client/components/ChangeUsername.js index 9d9b124b8..3aa29630d 100644 --- a/plugins/talk-plugin-auth/client/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/components/ChangeUsername.js @@ -16,6 +16,7 @@ import { hideCreateUsernameDialog, invalidForm, validForm, + updateUsername, } from 'coral-embed-stream/src/actions/auth'; class ChangeUsernameContainer extends React.Component { @@ -90,9 +91,15 @@ class ChangeUsernameContainer extends React.Component { }; async setUsernameAndClose(username, props = this.props) { - const {validForm, invalidForm, setUsername, hideCreateUsernameDialog} = props; + const {validForm, invalidForm, setUsername, hideCreateUsernameDialog, updateUsername} = props; try { + + // Perform mutation await setUsername(this.props.auth.user.id, username); + + // Also change in redux store... + updateUsername(username); + hideCreateUsernameDialog(); validForm(); } @@ -106,7 +113,7 @@ class ChangeUsernameContainer extends React.Component { handleSubmitUsername = (e) => { e.preventDefault(); const {errors, formData: {username}} = this.state; - const {validForm, invalidForm} = this.props; + const {invalidForm} = this.props; this.displayErrors(); if (this.isCompleted() && !Object.keys(errors).length) { this.setUsernameAndClose(username); @@ -156,7 +163,8 @@ const mapDispatchToProps = (dispatch) => showCreateUsernameDialog, hideCreateUsernameDialog, invalidForm, - validForm + validForm, + updateUsername, }, dispatch );