From 6a06cb4684aec652a815ed58b6314a71d7e65f34 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 22 Jan 2018 22:42:17 +0100 Subject: [PATCH 01/14] Show notification when encountering an error in modqueue --- .../routes/Moderation/containers/Moderation.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/client/coral-admin/src/routes/Moderation/containers/Moderation.js b/client/coral-admin/src/routes/Moderation/containers/Moderation.js index fd96c598b..c315cdca2 100644 --- a/client/coral-admin/src/routes/Moderation/containers/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/containers/Moderation.js @@ -35,6 +35,7 @@ import { Spinner } from 'coral-ui'; import Moderation from '../components/Moderation'; import Comment from './Comment'; import baseQueueConfig from '../queueConfig'; +import { notifyOnMutationError } from 'coral-framework/hocs'; function prepareNotificationText(text) { return truncate(text, { length: 50 }).replace('\n', ' '); @@ -213,6 +214,16 @@ class ModerationContainer extends Component { ) { this.resubscribe(nextProps.data.variables); } + + // Notify on fetching errors. + if ( + (!this.props.data.error && nextProps.data.error) || + (this.props.data.error && + nextProps.data.error && + this.props.data.error.message !== nextProps.data.error.message) + ) { + return this.props.notify('error', nextProps.data.error.message); + } } cleanUpQueue = queue => { @@ -269,10 +280,6 @@ class ModerationContainer extends Component { const { root, root: { asset, settings }, data } = this.props; const assetId = getAssetId(this.props); - if (data.error) { - return
Error
; - } - if (assetId) { if (asset === null) { // Not found. @@ -534,5 +541,6 @@ export default compose( withQueueConfig(baseQueueConfig), connect(mapStateToProps, mapDispatchToProps), withSetCommentStatus, + notifyOnMutationError(['setCommentStatus']), withModQueueQuery )(ModerationContainer); From f4e4c1d810416957cfe4c79fee5f461dc92adace Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 16:27:02 +0100 Subject: [PATCH 02/14] Notify on error (UserDetail) --- .../coral-admin/src/components/UserDetail.js | 38 ++++--------------- .../coral-admin/src/containers/UserDetail.js | 7 ++-- .../Moderation/containers/Moderation.js | 15 ++------ client/coral-framework/hocs/index.js | 1 + .../coral-framework/hocs/notifyOnDataError.js | 32 ++++++++++++++++ .../hocs/notifyOnMutationError.js | 17 +++++---- 6 files changed, 58 insertions(+), 52 deletions(-) create mode 100644 client/coral-framework/hocs/notifyOnDataError.js diff --git a/client/coral-admin/src/components/UserDetail.js b/client/coral-admin/src/components/UserDetail.js index d226ac744..e99668b38 100644 --- a/client/coral-admin/src/components/UserDetail.js +++ b/client/coral-admin/src/components/UserDetail.js @@ -2,7 +2,6 @@ import React from 'react'; import cn from 'classnames'; import PropTypes from 'prop-types'; import capitalize from 'lodash/capitalize'; -import { getErrorMessages } from 'coral-framework/utils'; import styles from './UserDetail.css'; import AccountHistory from './AccountHistory'; import { Slot } from 'coral-framework/components'; @@ -29,43 +28,23 @@ import UserInfoTooltip from './UserInfoTooltip'; class UserDetail extends React.Component { rejectThenReload = async info => { - try { - await this.props.rejectComment(info); - this.props.data.refetch(); - } catch (err) { - console.error(err); - this.props.notify('error', getErrorMessages(err)); - } + await this.props.rejectComment(info); + this.props.data.refetch(); }; acceptThenReload = async info => { - try { - await this.props.acceptComment(info); - this.props.data.refetch(); - } catch (err) { - console.error(err); - this.props.notify('error', getErrorMessages(err)); - } + await this.props.acceptComment(info); + this.props.data.refetch(); }; bulkAcceptThenReload = async () => { - try { - await this.props.bulkAccept(); - this.props.data.refetch(); - } catch (err) { - console.error(err); - this.props.notify('error', getErrorMessages(err)); - } + await this.props.bulkAccept(); + this.props.data.refetch(); }; bulkRejectThenReload = async () => { - try { - await this.props.bulkReject(); - this.props.data.refetch(); - } catch (err) { - console.error(err); - this.props.notify('error', getErrorMessages(err)); - } + await this.props.bulkReject(); + this.props.data.refetch(); }; changeTab = tab => { @@ -371,7 +350,6 @@ UserDetail.propTypes = { selectedCommentIds: PropTypes.array.isRequired, viewUserDetail: PropTypes.any.isRequired, loadMore: PropTypes.any.isRequired, - notify: PropTypes.func.isRequired, showSuspendUserDialog: PropTypes.func, showBanUserDialog: PropTypes.func, unbanUser: PropTypes.func.isRequired, diff --git a/client/coral-admin/src/containers/UserDetail.js b/client/coral-admin/src/containers/UserDetail.js index bd34ac4d8..ea9a3a5b2 100644 --- a/client/coral-admin/src/containers/UserDetail.js +++ b/client/coral-admin/src/containers/UserDetail.js @@ -24,9 +24,9 @@ import { } from 'coral-framework/graphql/mutations'; import UserDetailComment from './UserDetailComment'; import update from 'immutability-helper'; -import { notify } from 'coral-framework/actions/notification'; import { showBanUserDialog } from 'actions/banUserDialog'; import { showSuspendUserDialog } from 'actions/suspendUserDialog'; +import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; const commentConnectionFragment = gql` fragment CoralAdmin_UserDetail_CommentConnection on CommentConnection { @@ -271,7 +271,6 @@ const mapDispatchToProps = dispatch => ({ viewUserDetail, hideUserDetail, toggleSelectAllCommentInUserDetail, - notify, }, dispatch ), @@ -282,5 +281,7 @@ export default compose( withUserDetailQuery, withSetCommentStatus, withUnbanUser, - withUnsuspendUser + withUnsuspendUser, + notifyOnMutationError(['unbanUser', 'unsuspendUser', 'setCommentStatus']), + notifyOnDataError )(UserDetailContainer); diff --git a/client/coral-admin/src/routes/Moderation/containers/Moderation.js b/client/coral-admin/src/routes/Moderation/containers/Moderation.js index c315cdca2..70dd2730d 100644 --- a/client/coral-admin/src/routes/Moderation/containers/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/containers/Moderation.js @@ -35,7 +35,7 @@ import { Spinner } from 'coral-ui'; import Moderation from '../components/Moderation'; import Comment from './Comment'; import baseQueueConfig from '../queueConfig'; -import { notifyOnMutationError } from 'coral-framework/hocs'; +import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; function prepareNotificationText(text) { return truncate(text, { length: 50 }).replace('\n', ' '); @@ -214,16 +214,6 @@ class ModerationContainer extends Component { ) { this.resubscribe(nextProps.data.variables); } - - // Notify on fetching errors. - if ( - (!this.props.data.error && nextProps.data.error) || - (this.props.data.error && - nextProps.data.error && - this.props.data.error.message !== nextProps.data.error.message) - ) { - return this.props.notify('error', nextProps.data.error.message); - } } cleanUpQueue = queue => { @@ -542,5 +532,6 @@ export default compose( connect(mapStateToProps, mapDispatchToProps), withSetCommentStatus, notifyOnMutationError(['setCommentStatus']), - withModQueueQuery + withModQueueQuery, + notifyOnDataError )(ModerationContainer); diff --git a/client/coral-framework/hocs/index.js b/client/coral-framework/hocs/index.js index 275f6df42..7094ad53d 100644 --- a/client/coral-framework/hocs/index.js +++ b/client/coral-framework/hocs/index.js @@ -7,3 +7,4 @@ export { default as excludeIf } from './excludeIf'; export { default as connect } from './connect'; export { default as withMergedSettings } from './withMergedSettings'; export { default as notifyOnMutationError } from './notifyOnMutationError'; +export { default as notifyOnDataError } from './notifyOnDataError'; diff --git a/client/coral-framework/hocs/notifyOnDataError.js b/client/coral-framework/hocs/notifyOnDataError.js new file mode 100644 index 000000000..77e675ba1 --- /dev/null +++ b/client/coral-framework/hocs/notifyOnDataError.js @@ -0,0 +1,32 @@ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { notify } from 'coral-framework/actions/notification'; +import { branch, lifecycle, compose } from 'recompose'; +import { get } from 'lodash'; + +const notifyOnMutationError = compose( + branch( + ({ notify }) => !notify, + connect(null, dispatch => + bindActionCreators( + { + notify, + }, + dispatch + ) + ) + ), + lifecycle({ + componentWillReceiveProps(next) { + if ( + get(next, 'data.error.message') && + get(this.props, 'data.error.message') !== + get(next, 'data.error.message') + ) { + return this.props.notify('error', next.data.error.message); + } + }, + }) +); + +export default notifyOnMutationError; diff --git a/client/coral-framework/hocs/notifyOnMutationError.js b/client/coral-framework/hocs/notifyOnMutationError.js index c9429ad15..4046d8927 100644 --- a/client/coral-framework/hocs/notifyOnMutationError.js +++ b/client/coral-framework/hocs/notifyOnMutationError.js @@ -3,16 +3,19 @@ import { bindActionCreators } from 'redux'; import { compose } from 'react-apollo'; import { notify } from 'coral-framework/actions/notification'; import { forEachError } from 'coral-framework/utils'; -import { withProps } from 'recompose'; +import { withProps, branch } from 'recompose'; const notifyOnMutationError = keys => compose( - connect(null, dispatch => - bindActionCreators( - { - notify, - }, - dispatch + branch( + ({ notify }) => !notify, + connect(null, dispatch => + bindActionCreators( + { + notify, + }, + dispatch + ) ) ), withProps(ownProps => From 196ae5e29cf545d9a3e4c346aca2c5de239939a2 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 16:41:44 +0100 Subject: [PATCH 03/14] Notify on error (Communit > People) --- .../src/routes/Community/containers/People.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/client/coral-admin/src/routes/Community/containers/People.js b/client/coral-admin/src/routes/Community/containers/People.js index f8271b236..bd7fd2bac 100644 --- a/client/coral-admin/src/routes/Community/containers/People.js +++ b/client/coral-admin/src/routes/Community/containers/People.js @@ -16,6 +16,7 @@ import { appendNewNodes } from 'plugin-api/beta/client/utils'; import update from 'immutability-helper'; import { Spinner } from 'coral-ui'; import withQuery from 'coral-framework/hocs/withQuery'; +import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; class PeopleContainer extends React.Component { timer = null; @@ -84,10 +85,6 @@ class PeopleContainer extends React.Component { }; render() { - if (this.props.data.error) { - return
{this.props.data.error.message}
; - } - if (this.props.data.loading) { return (
@@ -204,6 +201,7 @@ export default compose( withSetUserRole, withUnsuspendUser, withUnbanUser, + notifyOnMutationError(['setUserRole', 'unsuspendUser', 'unbanUser']), withQuery( gql` query TalkAdmin_Community_People { @@ -239,5 +237,6 @@ export default compose( fetchPolicy: 'network-only', }, } - ) + ), + notifyOnDataError )(PeopleContainer); From dd836ad28e2052f7a109e6524f12e85fd99fc3c9 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 16:45:32 +0100 Subject: [PATCH 04/14] Notify on error (Community > Reported Username) --- .../routes/Community/containers/FlaggedAccounts.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js b/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js index 09240b8f3..1bf9c257b 100644 --- a/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js +++ b/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js @@ -15,7 +15,7 @@ import { handleFlaggedUsernameChange } from '../graphql'; import { notify } from 'coral-framework/actions/notification'; import { isFlaggedUserDangling } from '../utils'; import t from 'coral-framework/services/i18n'; -import { notifyOnMutationError } from 'coral-framework/hocs'; +import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; import FlaggedAccounts from '../components/FlaggedAccounts'; import FlaggedUser from '../containers/FlaggedUser'; @@ -159,11 +159,7 @@ class FlaggedAccountsContainer extends Component { }; render() { - if (this.props.data.error) { - return
{this.props.data.error.message}
; - } - - if (this.props.data.loading) { + if (this.props.data.loading || this.props.data.error) { return (
@@ -312,7 +308,7 @@ export default compose( username: [SET, CHANGED] } } - limit: 10 + limit: 9 }){ hasNextPage endCursor @@ -334,5 +330,6 @@ export default compose( fetchPolicy: 'network-only', }, } - ) + ), + notifyOnDataError )(FlaggedAccountsContainer); From 957fd34168fd28de8a08c18d2b991d1be4846c9a Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 16:53:03 +0100 Subject: [PATCH 05/14] Show error message on data error --- client/coral-admin/src/components/UserDetail.js | 14 ++++++++++++++ client/coral-admin/src/containers/UserDetail.js | 1 + .../routes/Community/containers/FlaggedAccounts.js | 8 ++++++-- .../src/routes/Community/containers/People.js | 4 ++++ .../src/routes/Moderation/containers/Moderation.js | 4 ++++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/client/coral-admin/src/components/UserDetail.js b/client/coral-admin/src/components/UserDetail.js index e99668b38..71d2ed1a3 100644 --- a/client/coral-admin/src/components/UserDetail.js +++ b/client/coral-admin/src/components/UserDetail.js @@ -73,6 +73,16 @@ class UserDetail extends React.Component { ); } + renderError() { + return ( + + +
{this.props.data.error.message}
+
+
+ ); + } + getActionMenuLabel() { const { root: { user } } = this.props; @@ -324,6 +334,10 @@ class UserDetail extends React.Component { } render() { + if (this.props.data.error) { + return this.renderError(); + } + if (this.props.loading) { return this.renderLoading(); } diff --git a/client/coral-admin/src/containers/UserDetail.js b/client/coral-admin/src/containers/UserDetail.js index ea9a3a5b2..62eb32dc5 100644 --- a/client/coral-admin/src/containers/UserDetail.js +++ b/client/coral-admin/src/containers/UserDetail.js @@ -130,6 +130,7 @@ class UserDetailContainer extends React.Component { acceptComment={this.acceptComment} rejectComment={this.rejectComment} loading={loading} + error={this.props.data && this.props.data.error} loadMore={this.loadMore} {...this.props} /> diff --git a/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js b/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js index 1bf9c257b..054c5dd5f 100644 --- a/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js +++ b/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js @@ -159,7 +159,11 @@ class FlaggedAccountsContainer extends Component { }; render() { - if (this.props.data.loading || this.props.data.error) { + if (this.props.data.error) { + return
{this.props.data.error.message}
; + } + + if (this.props.data.loading) { return (
@@ -308,7 +312,7 @@ export default compose( username: [SET, CHANGED] } } - limit: 9 + limit: 10 }){ hasNextPage endCursor diff --git a/client/coral-admin/src/routes/Community/containers/People.js b/client/coral-admin/src/routes/Community/containers/People.js index bd7fd2bac..c5d36517c 100644 --- a/client/coral-admin/src/routes/Community/containers/People.js +++ b/client/coral-admin/src/routes/Community/containers/People.js @@ -85,6 +85,10 @@ class PeopleContainer extends React.Component { }; render() { + if (this.props.data.error) { + return
{this.props.data.error.message}
; + } + if (this.props.data.loading) { return (
diff --git a/client/coral-admin/src/routes/Moderation/containers/Moderation.js b/client/coral-admin/src/routes/Moderation/containers/Moderation.js index 70dd2730d..adb60fc31 100644 --- a/client/coral-admin/src/routes/Moderation/containers/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/containers/Moderation.js @@ -277,6 +277,10 @@ class ModerationContainer extends Component { } } + if (data.error) { + return
{data.error.message}
; + } + if (data.loading && data.networkStatus !== 3) { // loading. return ; From 74b545a8d990a1cc8f110c3a538f044ebb98282b Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 16:58:11 +0100 Subject: [PATCH 06/14] Refetch configure and notify on error --- .../routes/Configure/containers/Configure.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index 0d9d5faf9..e94c89788 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -4,34 +4,33 @@ import { bindActionCreators } from 'redux'; import { compose, gql } from 'react-apollo'; import { withQuery, withMergedSettings } from 'coral-framework/hocs'; import { Spinner } from 'coral-ui'; -import { notify } from 'coral-framework/actions/notification'; import PropTypes from 'prop-types'; import { withUpdateSettings } from 'coral-framework/graphql/mutations'; -import { getErrorMessages, getDefinitionName } from 'coral-framework/utils'; +import { getDefinitionName } from 'coral-framework/utils'; import StreamSettings from './StreamSettings'; import TechSettings from './TechSettings'; import ModerationSettings from './ModerationSettings'; import { clearPending, setActiveSection } from '../../../actions/configure'; import Configure from '../components/Configure'; +import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; class ConfigureContainer extends Component { savePending = async () => { - try { - await this.props.updateSettings(this.props.pending); - this.props.clearPending(); - } catch (err) { - this.props.notify('error', getErrorMessages(err)); - } + await this.props.updateSettings(this.props.pending); + this.props.clearPending(); }; render() { + if (this.props.data.error) { + return
{this.props.data.error.message}
; + } + if (this.props.data.loading) { return ; } return ( ({ variables: {}, + fetchPolicy: 'network-only', }), } ); @@ -81,7 +81,6 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => bindActionCreators( { - notify, clearPending, setActiveSection, }, @@ -90,7 +89,9 @@ const mapDispatchToProps = dispatch => export default compose( withUpdateSettings, + notifyOnMutationError(['updateSettings']), withConfigureQuery, + notifyOnDataError, connect(mapStateToProps, mapDispatchToProps), withMergedSettings('root.settings', 'pending', 'mergedSettings') )(ConfigureContainer); @@ -99,7 +100,6 @@ ConfigureContainer.propTypes = { updateSettings: PropTypes.func.isRequired, clearPending: PropTypes.func.isRequired, setActiveSection: PropTypes.func.isRequired, - notify: PropTypes.func.isRequired, auth: PropTypes.object.isRequired, data: PropTypes.object.isRequired, root: PropTypes.object.isRequired, From 04fd056cab7826eeea1846b58499ccb588f04454 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 17:36:07 +0100 Subject: [PATCH 07/14] Notify on errors (embed stream - configure) --- .../configure/containers/AssetStatusInfo.js | 4 +++- .../tabs/configure/containers/Configure.js | 4 ++++ .../src/tabs/configure/containers/Settings.js | 24 +++++++------------ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js b/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js index ed0746d29..db74beff6 100644 --- a/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js +++ b/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js @@ -7,6 +7,7 @@ import { withUpdateAssetStatus, withCloseAsset, } from 'coral-framework/graphql/mutations'; +import { notifyOnMutationError } from 'coral-framework/hocs'; class AssetStatusInfoContainer extends React.Component { openAsset = () => @@ -45,7 +46,8 @@ const withAssetStatusInfoFragments = withFragments({ const enhance = compose( withAssetStatusInfoFragments, withUpdateAssetStatus, - withCloseAsset + withCloseAsset, + notifyOnMutationError(['updateAssetStatus', 'closeAsset']) ); export default enhance(AssetStatusInfoContainer); diff --git a/client/coral-embed-stream/src/tabs/configure/containers/Configure.js b/client/coral-embed-stream/src/tabs/configure/containers/Configure.js index c408d67fc..b6104b067 100644 --- a/client/coral-embed-stream/src/tabs/configure/containers/Configure.js +++ b/client/coral-embed-stream/src/tabs/configure/containers/Configure.js @@ -9,6 +9,10 @@ import { getDefinitionName } from 'coral-framework/utils'; class ConfigureContainer extends React.Component { render() { + if (this.props.data.error) { + return
{this.props.data.error.message}
; + } + return ( { - try { - await this.props.updateAssetSettings( - this.props.asset.id, - this.props.pending - ); - this.props.clearPending(); - } catch (err) { - this.props.notify('error', getErrorMessages(err)); - } + await this.props.updateAssetSettings( + this.props.asset.id, + this.props.pending + ); + this.props.clearPending(); }; render() { @@ -98,7 +91,6 @@ SettingsContainer.propTypes = { mergedSettings: PropTypes.object.isRequired, updateAssetSettings: PropTypes.func.isRequired, clearPending: PropTypes.func.isRequired, - notify: PropTypes.func.isRequired, updatePending: PropTypes.func.isRequired, canSave: PropTypes.bool.isRequired, }; @@ -135,7 +127,6 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => bindActionCreators( { - notify, clearPending, updatePending, }, @@ -145,6 +136,7 @@ const mapDispatchToProps = dispatch => const enhance = compose( withSettingsFragments, withUpdateAssetSettings, + notifyOnMutationError(['updateAssetSettings']), connect(mapStateToProps, mapDispatchToProps), withMergedSettings('asset.settings', 'pending', 'mergedSettings') ); From 303e2e84c5d793da91c0f70a0b9d388216d6cf39 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 17:37:52 +0100 Subject: [PATCH 08/14] Notify on error (embed stream -> profile) --- client/coral-settings/containers/ProfileContainer.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/coral-settings/containers/ProfileContainer.js b/client/coral-settings/containers/ProfileContainer.js index fb9d8de17..e1bcf7f13 100644 --- a/client/coral-settings/containers/ProfileContainer.js +++ b/client/coral-settings/containers/ProfileContainer.js @@ -65,6 +65,10 @@ class ProfileContainer extends Component { const { me } = this.props.root; const loading = this.props.data.loading; + if (this.props.data.error) { + return
{this.props.data.error.message}
; + } + if (!auth.loggedIn) { return ; } From 0523faee2bfe9bb1abeb7e57577de175e9fa68ad Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 19:05:08 +0100 Subject: [PATCH 09/14] withQuery and withMutation support for notifyOnError (default: true) --- .../src/containers/BanUserDialog.js | 18 +++----- .../src/containers/SuspendUserDialog.js | 19 +++----- .../coral-admin/src/containers/UserDetail.js | 7 ++- .../Community/containers/FlaggedAccounts.js | 5 +- .../src/routes/Community/containers/People.js | 7 ++- .../containers/RejectUsernameDialog.js | 4 +- .../routes/Configure/containers/Configure.js | 9 ++-- .../Moderation/containers/Moderation.js | 5 +- .../configure/containers/AssetStatusInfo.js | 16 +++++-- .../src/tabs/configure/containers/Settings.js | 6 +-- .../tabs/stream/containers/ChangeUsername.js | 15 +++++- client/coral-framework/hocs/index.js | 2 - .../coral-framework/hocs/notifyOnDataError.js | 32 ------------- .../hocs/notifyOnMutationError.js | 38 --------------- client/coral-framework/hocs/withMutation.js | 43 ++++++++++++++--- client/coral-framework/hocs/withQuery.js | 46 ++++++++++++++++--- 16 files changed, 133 insertions(+), 139 deletions(-) delete mode 100644 client/coral-framework/hocs/notifyOnDataError.js delete mode 100644 client/coral-framework/hocs/notifyOnMutationError.js diff --git a/client/coral-admin/src/containers/BanUserDialog.js b/client/coral-admin/src/containers/BanUserDialog.js index d2dc642a7..642f7f6ee 100644 --- a/client/coral-admin/src/containers/BanUserDialog.js +++ b/client/coral-admin/src/containers/BanUserDialog.js @@ -10,7 +10,6 @@ import { } from 'coral-framework/graphql/mutations'; import { compose } from 'react-apollo'; import t from 'coral-framework/services/i18n'; -import { getErrorMessages } from 'coral-framework/utils'; import { notify } from 'coral-framework/actions/notification'; class BanUserDialogContainer extends Component { @@ -22,16 +21,11 @@ class BanUserDialogContainer extends Component { banUser, setCommentStatus, hideBanUserDialog, - notify, } = this.props; - try { - await banUser({ id: userId, message: '' }); - hideBanUserDialog(); - if (commentId && commentStatus && commentStatus !== 'REJECTED') { - await setCommentStatus({ commentId, status: 'REJECTED' }); - } - } catch (err) { - notify('error', getErrorMessages(err)); + await banUser({ id: userId, message: '' }); + hideBanUserDialog(); + if (commentId && commentStatus && commentStatus !== 'REJECTED') { + await setCommentStatus({ commentId, status: 'REJECTED' }); } }; @@ -85,7 +79,7 @@ const mapDispatchToProps = dispatch => ({ }); export default compose( + connect(mapStateToProps, mapDispatchToProps), withBanUser, - withSetCommentStatus, - connect(mapStateToProps, mapDispatchToProps) + withSetCommentStatus )(BanUserDialogContainer); diff --git a/client/coral-admin/src/containers/SuspendUserDialog.js b/client/coral-admin/src/containers/SuspendUserDialog.js index e058faad6..f03d48f52 100644 --- a/client/coral-admin/src/containers/SuspendUserDialog.js +++ b/client/coral-admin/src/containers/SuspendUserDialog.js @@ -11,7 +11,6 @@ import { import { compose, gql } from 'react-apollo'; import t, { timeago } from 'coral-framework/services/i18n'; import withQuery from 'coral-framework/hocs/withQuery'; -import { getErrorMessages } from 'coral-framework/utils'; import get from 'lodash/get'; import { notify } from 'coral-framework/actions/notification'; @@ -28,17 +27,13 @@ class SuspendUserDialogContainer extends Component { notify, } = this.props; hideSuspendUserDialog(); - try { - await suspendUser({ id: userId, message, until }); - notify( - 'success', - t('suspenduser.notify_suspend_until', username, timeago(until)) - ); - if (commentId && commentStatus && commentStatus !== 'REJECTED') { - await setCommentStatus({ commentId, status: 'REJECTED' }); - } - } catch (err) { - notify('error', getErrorMessages(err)); + await suspendUser({ id: userId, message, until }); + notify( + 'success', + t('suspenduser.notify_suspend_until', username, timeago(until)) + ); + if (commentId && commentStatus && commentStatus !== 'REJECTED') { + await setCommentStatus({ commentId, status: 'REJECTED' }); } }; diff --git a/client/coral-admin/src/containers/UserDetail.js b/client/coral-admin/src/containers/UserDetail.js index 62eb32dc5..5b5c12bec 100644 --- a/client/coral-admin/src/containers/UserDetail.js +++ b/client/coral-admin/src/containers/UserDetail.js @@ -26,7 +26,7 @@ import UserDetailComment from './UserDetailComment'; import update from 'immutability-helper'; import { showBanUserDialog } from 'actions/banUserDialog'; import { showSuspendUserDialog } from 'actions/suspendUserDialog'; -import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; +import { notify } from 'coral-framework/actions/notification'; const commentConnectionFragment = gql` fragment CoralAdmin_UserDetail_CommentConnection on CommentConnection { @@ -272,6 +272,7 @@ const mapDispatchToProps = dispatch => ({ viewUserDetail, hideUserDetail, toggleSelectAllCommentInUserDetail, + notify, }, dispatch ), @@ -282,7 +283,5 @@ export default compose( withUserDetailQuery, withSetCommentStatus, withUnbanUser, - withUnsuspendUser, - notifyOnMutationError(['unbanUser', 'unsuspendUser', 'setCommentStatus']), - notifyOnDataError + withUnsuspendUser )(UserDetailContainer); diff --git a/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js b/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js index 054c5dd5f..1d7e089e2 100644 --- a/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js +++ b/client/coral-admin/src/routes/Community/containers/FlaggedAccounts.js @@ -15,7 +15,6 @@ import { handleFlaggedUsernameChange } from '../graphql'; import { notify } from 'coral-framework/actions/notification'; import { isFlaggedUserDangling } from '../utils'; import t from 'coral-framework/services/i18n'; -import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; import FlaggedAccounts from '../components/FlaggedAccounts'; import FlaggedUser from '../containers/FlaggedUser'; @@ -295,7 +294,6 @@ const mapDispatchToProps = dispatch => export default compose( connect(null, mapDispatchToProps), withApproveUsername, - notifyOnMutationError(['approveUsername']), withQuery( gql` query TalkAdmin_Community_FlaggedAccounts { @@ -334,6 +332,5 @@ export default compose( fetchPolicy: 'network-only', }, } - ), - notifyOnDataError + ) )(FlaggedAccountsContainer); diff --git a/client/coral-admin/src/routes/Community/containers/People.js b/client/coral-admin/src/routes/Community/containers/People.js index c5d36517c..d958d7378 100644 --- a/client/coral-admin/src/routes/Community/containers/People.js +++ b/client/coral-admin/src/routes/Community/containers/People.js @@ -16,7 +16,7 @@ import { appendNewNodes } from 'plugin-api/beta/client/utils'; import update from 'immutability-helper'; import { Spinner } from 'coral-ui'; import withQuery from 'coral-framework/hocs/withQuery'; -import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; +import { notify } from 'coral-framework/actions/notification'; class PeopleContainer extends React.Component { timer = null; @@ -132,6 +132,7 @@ const mapDispatchToProps = dispatch => viewUserDetail, showSuspendUserDialog, showBanUserDialog, + notify, }, dispatch ); @@ -205,7 +206,6 @@ export default compose( withSetUserRole, withUnsuspendUser, withUnbanUser, - notifyOnMutationError(['setUserRole', 'unsuspendUser', 'unbanUser']), withQuery( gql` query TalkAdmin_Community_People { @@ -241,6 +241,5 @@ export default compose( fetchPolicy: 'network-only', }, } - ), - notifyOnDataError + ) )(PeopleContainer); diff --git a/client/coral-admin/src/routes/Community/containers/RejectUsernameDialog.js b/client/coral-admin/src/routes/Community/containers/RejectUsernameDialog.js index f9ada0945..bf4490284 100644 --- a/client/coral-admin/src/routes/Community/containers/RejectUsernameDialog.js +++ b/client/coral-admin/src/routes/Community/containers/RejectUsernameDialog.js @@ -5,7 +5,6 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { compose } from 'react-apollo'; import { notify } from 'coral-framework/actions/notification'; -import { notifyOnMutationError } from 'coral-framework/hocs'; const mapStateToProps = state => ({ user: state.community.user, @@ -23,6 +22,5 @@ const mapDispatchToProps = dispatch => export default compose( connect(mapStateToProps, mapDispatchToProps), - withRejectUsername, - notifyOnMutationError(['rejectUsername']) + withRejectUsername )(RejectUsernameDialog); diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index e94c89788..254e39d70 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -12,7 +12,7 @@ import TechSettings from './TechSettings'; import ModerationSettings from './ModerationSettings'; import { clearPending, setActiveSection } from '../../../actions/configure'; import Configure from '../components/Configure'; -import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; +import { notify } from 'coral-framework/actions/notification'; class ConfigureContainer extends Component { savePending = async () => { @@ -83,16 +83,15 @@ const mapDispatchToProps = dispatch => { clearPending, setActiveSection, + notify, }, dispatch ); export default compose( - withUpdateSettings, - notifyOnMutationError(['updateSettings']), - withConfigureQuery, - notifyOnDataError, connect(mapStateToProps, mapDispatchToProps), + withUpdateSettings, + withConfigureQuery, withMergedSettings('root.settings', 'pending', 'mergedSettings') )(ConfigureContainer); diff --git a/client/coral-admin/src/routes/Moderation/containers/Moderation.js b/client/coral-admin/src/routes/Moderation/containers/Moderation.js index adb60fc31..e0e3f14fe 100644 --- a/client/coral-admin/src/routes/Moderation/containers/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/containers/Moderation.js @@ -35,7 +35,6 @@ import { Spinner } from 'coral-ui'; import Moderation from '../components/Moderation'; import Comment from './Comment'; import baseQueueConfig from '../queueConfig'; -import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs'; function prepareNotificationText(text) { return truncate(text, { length: 50 }).replace('\n', ' '); @@ -535,7 +534,5 @@ export default compose( withQueueConfig(baseQueueConfig), connect(mapStateToProps, mapDispatchToProps), withSetCommentStatus, - notifyOnMutationError(['setCommentStatus']), - withModQueueQuery, - notifyOnDataError + withModQueueQuery )(ModerationContainer); diff --git a/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js b/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js index db74beff6..c97d8e068 100644 --- a/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js +++ b/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js @@ -7,7 +7,9 @@ import { withUpdateAssetStatus, withCloseAsset, } from 'coral-framework/graphql/mutations'; -import { notifyOnMutationError } from 'coral-framework/hocs'; +import { notify } from 'coral-framework/actions/notification'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; class AssetStatusInfoContainer extends React.Component { openAsset = () => @@ -43,11 +45,19 @@ const withAssetStatusInfoFragments = withFragments({ `, }); +const mapDispatchToProps = dispatch => + bindActionCreators( + { + notify, + }, + dispatch + ); + const enhance = compose( + connect(null, mapDispatchToProps), withAssetStatusInfoFragments, withUpdateAssetStatus, - withCloseAsset, - notifyOnMutationError(['updateAssetStatus', 'closeAsset']) + withCloseAsset ); export default enhance(AssetStatusInfoContainer); diff --git a/client/coral-embed-stream/src/tabs/configure/containers/Settings.js b/client/coral-embed-stream/src/tabs/configure/containers/Settings.js index 22be4ef9a..9bfeb149e 100644 --- a/client/coral-embed-stream/src/tabs/configure/containers/Settings.js +++ b/client/coral-embed-stream/src/tabs/configure/containers/Settings.js @@ -8,7 +8,7 @@ import { withUpdateAssetSettings } from 'coral-framework/graphql/mutations'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { clearPending, updatePending } from '../../../actions/configure'; -import { notifyOnMutationError } from 'coral-framework/hocs'; +import { notify } from 'coral-framework/actions/notification'; const slots = ['streamSettings']; @@ -129,15 +129,15 @@ const mapDispatchToProps = dispatch => { clearPending, updatePending, + notify, }, dispatch ); const enhance = compose( + connect(mapStateToProps, mapDispatchToProps), withSettingsFragments, withUpdateAssetSettings, - notifyOnMutationError(['updateAssetSettings']), - connect(mapStateToProps, mapDispatchToProps), withMergedSettings('asset.settings', 'pending', 'mergedSettings') ); diff --git a/client/coral-embed-stream/src/tabs/stream/containers/ChangeUsername.js b/client/coral-embed-stream/src/tabs/stream/containers/ChangeUsername.js index cc0b84f02..098513aaf 100644 --- a/client/coral-embed-stream/src/tabs/stream/containers/ChangeUsername.js +++ b/client/coral-embed-stream/src/tabs/stream/containers/ChangeUsername.js @@ -1,5 +1,18 @@ import { compose } from 'react-apollo'; import { withChangeUsername } from 'coral-framework/graphql/mutations'; import ChangeUsername from '../components/ChangeUsername'; +import { notify } from 'coral-framework/actions/notification'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -export default compose(withChangeUsername)(ChangeUsername); +const mapDispatchToProps = dispatch => + bindActionCreators( + { + notify, + }, + dispatch + ); + +export default compose(connect(null, mapDispatchToProps), withChangeUsername)( + ChangeUsername +); diff --git a/client/coral-framework/hocs/index.js b/client/coral-framework/hocs/index.js index 7094ad53d..174f25a63 100644 --- a/client/coral-framework/hocs/index.js +++ b/client/coral-framework/hocs/index.js @@ -6,5 +6,3 @@ export { default as withEmit } from './withEmit'; export { default as excludeIf } from './excludeIf'; export { default as connect } from './connect'; export { default as withMergedSettings } from './withMergedSettings'; -export { default as notifyOnMutationError } from './notifyOnMutationError'; -export { default as notifyOnDataError } from './notifyOnDataError'; diff --git a/client/coral-framework/hocs/notifyOnDataError.js b/client/coral-framework/hocs/notifyOnDataError.js deleted file mode 100644 index 77e675ba1..000000000 --- a/client/coral-framework/hocs/notifyOnDataError.js +++ /dev/null @@ -1,32 +0,0 @@ -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import { notify } from 'coral-framework/actions/notification'; -import { branch, lifecycle, compose } from 'recompose'; -import { get } from 'lodash'; - -const notifyOnMutationError = compose( - branch( - ({ notify }) => !notify, - connect(null, dispatch => - bindActionCreators( - { - notify, - }, - dispatch - ) - ) - ), - lifecycle({ - componentWillReceiveProps(next) { - if ( - get(next, 'data.error.message') && - get(this.props, 'data.error.message') !== - get(next, 'data.error.message') - ) { - return this.props.notify('error', next.data.error.message); - } - }, - }) -); - -export default notifyOnMutationError; diff --git a/client/coral-framework/hocs/notifyOnMutationError.js b/client/coral-framework/hocs/notifyOnMutationError.js deleted file mode 100644 index 4046d8927..000000000 --- a/client/coral-framework/hocs/notifyOnMutationError.js +++ /dev/null @@ -1,38 +0,0 @@ -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import { compose } from 'react-apollo'; -import { notify } from 'coral-framework/actions/notification'; -import { forEachError } from 'coral-framework/utils'; -import { withProps, branch } from 'recompose'; - -const notifyOnMutationError = keys => - compose( - branch( - ({ notify }) => !notify, - connect(null, dispatch => - bindActionCreators( - { - notify, - }, - dispatch - ) - ) - ), - withProps(ownProps => - keys.reduce((props, key) => { - props[key] = async (...args) => { - try { - return await ownProps[key](...args); - } catch (e) { - forEachError(e, ({ msg }) => { - ownProps.notify('error', msg); - }); - throw e; - } - }; - return props; - }, {}) - ) - ); - -export default notifyOnMutationError; diff --git a/client/coral-framework/hocs/withMutation.js b/client/coral-framework/hocs/withMutation.js index b72e56f40..c31e89ce8 100644 --- a/client/coral-framework/hocs/withMutation.js +++ b/client/coral-framework/hocs/withMutation.js @@ -4,7 +4,11 @@ import merge from 'lodash/merge'; import uniq from 'lodash/uniq'; import flatten from 'lodash/flatten'; import isEmpty from 'lodash/isEmpty'; -import { getDefinitionName, getResponseErrors } from '../utils'; +import { + getDefinitionName, + getResponseErrors, + getErrorMessages, +} from '../utils'; import PropTypes from 'prop-types'; import t from 'coral-framework/services/i18n'; import hoistStatics from 'recompose/hoistStatics'; @@ -27,11 +31,7 @@ class ResponseError { } } -/** - * Exports a HOC with the same signature as `graphql`, that will - * apply mutation options registered in the graphRegistry. - */ -export default (document, config = {}) => +const createHOC = (document, config, { notifyOnError = true }) => hoistStatics(WrappedComponent => { config = { ...config, @@ -46,10 +46,25 @@ export default (document, config = {}) => graphql: PropTypes.object, }; + static propTypes = { + notify: PropTypes.func, + }; + get graphqlRegistry() { return this.context.graphql.registry; } + notifyErrors(messages) { + if (this.props.notify) { + this.props.notify('error', messages); + } else { + console.error( + '`notifyOnError` is set to `true` but missing `notify` property' + ); + console.error(messages); + } + } + resolveDocument(documentOrCallback) { return this.context.graphql.resolveDocument( documentOrCallback, @@ -165,6 +180,11 @@ export default (document, config = {}) => variables, error, }); + + // Show errors as notifications. + if (notifyOnError) { + this.notifyErrors(getErrorMessages(error)); + } throw error; }); }; @@ -213,3 +233,14 @@ export default (document, config = {}) => } }; }); + +/** + * Exports a HOC with the same signature as `graphql`, that will + * apply mutation options registered in the graphRegistry. + */ +export default (document, config = {}) => settingsOrComponent => { + if (typeof settingsOrComponent === 'function') { + return createHOC(document, config, {})(settingsOrComponent); + } + return createHOC(document, config, settingsOrComponent); +}; diff --git a/client/coral-framework/hocs/withQuery.js b/client/coral-framework/hocs/withQuery.js index d5609c340..08556b1b3 100644 --- a/client/coral-framework/hocs/withQuery.js +++ b/client/coral-framework/hocs/withQuery.js @@ -9,6 +9,7 @@ import PropTypes from 'prop-types'; import hoistStatics from 'recompose/hoistStatics'; import { getOperationName } from 'apollo-client/queries/getFromAST'; import throttle from 'lodash/throttle'; +import get from 'lodash/get'; const withSkipOnErrors = reducer => (prev, action, ...rest) => { if ( @@ -36,15 +37,12 @@ function networkStatusToString(networkStatus) { return 'ready'; case 8: return 'error'; + default: + throw new Error(`Unknown network status ${networkStatus}`); } - throw new Error(`Unknown network status ${networkStatus}`); } -/** - * Exports a HOC with the same signature as `graphql`, that will - * apply query options registered in the graphRegistry. - */ -export default (document, config = {}) => +const createHOC = (document, config, { notifyOnError = true }) => hoistStatics(WrappedComponent => { return class WithQuery extends React.Component { static contextTypes = { @@ -53,6 +51,10 @@ export default (document, config = {}) => client: PropTypes.object, }; + static propTypes = { + notify: PropTypes.func, + }; + // Lazily resolve fragments from graphRegistry to support circular dependencies. memoized = null; resolvedDocument = null; @@ -166,10 +168,31 @@ export default (document, config = {}) => return () => this.client.networkInterface.unsubscribe(id); }; + notifyErrors(messages) { + if (this.props.notify) { + this.props.notify('error', messages); + } else { + console.error( + '`notifyOnError` is set to `true` but missing `notify` property' + ); + console.error(messages); + } + } + nextData(data) { this.apolloData = data; this.emitWhenNeeded(data); + if ( + get(data, 'error.message') && + get(this, 'data.error.message') !== get(data, 'error.message') + ) { + // Show errors as notifications. + if (notifyOnError) { + this.notifyErrors(data.error.message); + } + } + // If data was previously set, we update it in a immutable way. if (this.data) { if (this.data.loading && !data.loading) { @@ -319,3 +342,14 @@ export default (document, config = {}) => } }; }); + +/** + * Exports a HOC with the same signature as `graphql`, that will + * apply query options registered in the graphRegistry. + */ +export default (document, config = {}) => settingsOrComponent => { + if (typeof settingsOrComponent === 'function') { + return createHOC(document, config, {})(settingsOrComponent); + } + return createHOC(document, config, settingsOrComponent); +}; From ace6cbb158e17d080e240dc5a6f9a784017961a5 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 19:41:00 +0100 Subject: [PATCH 10/14] Error reporting for the rest --- .../src/tabs/stream/components/AllCommentsPane.js | 6 +----- .../src/tabs/stream/components/Comment.js | 6 +----- .../src/tabs/stream/components/EditableCommentContent.js | 4 +--- .../src/tabs/stream/components/Stream.js | 2 +- .../src/tabs/stream/components/StreamError.js | 2 +- .../src/tabs/stream/containers/Stream.js | 8 +++++++- client/talk-plugin-commentbox/CommentBox.js | 4 +--- client/talk-plugin-history/CommentHistory.js | 7 +------ 8 files changed, 14 insertions(+), 25 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/stream/components/AllCommentsPane.js b/client/coral-embed-stream/src/tabs/stream/components/AllCommentsPane.js index ed1fe73f9..3190ab155 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/AllCommentsPane.js +++ b/client/coral-embed-stream/src/tabs/stream/components/AllCommentsPane.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import LoadMore from './LoadMore'; import NewCount from './NewCount'; import { TransitionGroup } from 'react-transition-group'; -import { forEachError } from 'coral-framework/utils'; import Comment from '../containers/Comment'; import NoComments from './NoComments'; @@ -91,11 +90,8 @@ class AllCommentsPane extends React.Component { .then(() => { this.setState({ loadingState: 'success' }); }) - .catch(error => { + .catch(() => { this.setState({ loadingState: 'error' }); - forEachError(error, ({ msg }) => { - this.props.notify('error', msg); - }); }); }; diff --git a/client/coral-embed-stream/src/tabs/stream/components/Comment.js b/client/coral-embed-stream/src/tabs/stream/components/Comment.js index f4e8404e4..cd0fab9e9 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Comment.js +++ b/client/coral-embed-stream/src/tabs/stream/components/Comment.js @@ -24,7 +24,6 @@ import { EditableCommentContent } from './EditableCommentContent'; import { getActionSummary, iPerformedThisAction, - forEachError, isCommentActive, getShallowChanges, } from 'coral-framework/utils'; @@ -261,11 +260,8 @@ export default class Comment extends React.Component { loadingState: 'success', }); }) - .catch(error => { + .catch(() => { this.setState({ loadingState: 'error' }); - forEachError(error, ({ msg }) => { - this.props.notify('error', msg); - }); }); emit('ui.Comment.showMoreReplies', { id }); return; diff --git a/client/coral-embed-stream/src/tabs/stream/components/EditableCommentContent.js b/client/coral-embed-stream/src/tabs/stream/components/EditableCommentContent.js index bfd2c8bad..f4cfc42e8 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/EditableCommentContent.js +++ b/client/coral-embed-stream/src/tabs/stream/components/EditableCommentContent.js @@ -6,7 +6,6 @@ import styles from './Comment.css'; import { CountdownSeconds } from './CountdownSeconds'; import { getEditableUntilDate } from './util'; import { can } from 'coral-framework/services/perms'; -import { forEachError } from 'coral-framework/utils'; import { Icon } from 'coral-ui'; import t from 'coral-framework/services/i18n'; @@ -80,7 +79,7 @@ export class EditableCommentContent extends React.Component { this.setState({ loadingState: 'loading' }); - const { editComment, notify, stopEditing } = this.props; + const { editComment, stopEditing } = this.props; if (typeof editComment !== 'function') { return; } @@ -95,7 +94,6 @@ export class EditableCommentContent extends React.Component { } } catch (error) { this.setState({ loadingState: 'error' }); - forEachError(error, ({ msg }) => notify('error', msg)); } }; diff --git a/client/coral-embed-stream/src/tabs/stream/components/Stream.js b/client/coral-embed-stream/src/tabs/stream/components/Stream.js index d82f49498..6288a2b6b 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/components/Stream.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { StreamError } from './StreamError'; +import StreamError from './StreamError'; import Comment from '../containers/Comment'; import BannedAccount from '../../../components/BannedAccount'; import ChangeUsername from '../containers/ChangeUsername'; diff --git a/client/coral-embed-stream/src/tabs/stream/components/StreamError.js b/client/coral-embed-stream/src/tabs/stream/components/StreamError.js index 0955de2ef..79d6b03fc 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/StreamError.js +++ b/client/coral-embed-stream/src/tabs/stream/components/StreamError.js @@ -1,6 +1,6 @@ import React from 'react'; import styles from './StreamError.css'; -export const StreamError = ({ children }) => ( +export default ({ children }) => (
{children}
); 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 70cbadae5..51b4d9d9e 100644 --- a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js @@ -38,6 +38,7 @@ import { insertFetchedCommentsIntoEmbedQuery, nest, } from '../../../graphql/utils'; +import StreamError from '../components/StreamError'; const { showSignInDialog, editName } = authActions; const { notify } = notificationActions; @@ -208,6 +209,10 @@ class StreamContainer extends React.Component { } render() { + if (this.props.data.error) { + return {this.props.data.error.message}; + } + if ( !this.props.asset || (this.props.asset.comment === undefined && !this.props.asset.comments) @@ -424,7 +429,8 @@ export default compose( withEmit, connect(mapStateToProps, mapDispatchToProps), withPostComment, - withPostFlag, + // `talk-plugin-flags` has a custom error handling logic. + withPostFlag({ notifyOnError: false }), withPostDontAgree, withDeleteAction, withEditComment diff --git a/client/talk-plugin-commentbox/CommentBox.js b/client/talk-plugin-commentbox/CommentBox.js index a8da78f3f..8eac1ff2f 100644 --- a/client/talk-plugin-commentbox/CommentBox.js +++ b/client/talk-plugin-commentbox/CommentBox.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import t from 'coral-framework/services/i18n'; import { can } from 'coral-framework/services/perms'; -import { forEachError } from 'coral-framework/utils'; import Slot from 'coral-framework/components/Slot'; import { connect } from 'react-redux'; @@ -93,9 +92,8 @@ class CommentBox extends React.Component { commentPostedHandler(); } }) - .catch(err => { + .catch(() => { this.setState({ loadingState: 'error' }); - forEachError(err, ({ msg }) => notify('error', msg)); }); }; diff --git a/client/talk-plugin-history/CommentHistory.js b/client/talk-plugin-history/CommentHistory.js index a56350c4a..a17a347c5 100644 --- a/client/talk-plugin-history/CommentHistory.js +++ b/client/talk-plugin-history/CommentHistory.js @@ -2,7 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import Comment from './Comment'; import LoadMore from './LoadMore'; -import { forEachError } from 'plugin-api/beta/client/utils'; class CommentHistory extends React.Component { state = { @@ -16,11 +15,8 @@ class CommentHistory extends React.Component { .then(() => { this.setState({ loadingState: 'success' }); }) - .catch(error => { + .catch(() => { this.setState({ loadingState: 'error' }); - forEachError(error, ({ msg }) => { - this.props.notify('error', msg); - }); }); }; @@ -55,7 +51,6 @@ class CommentHistory extends React.Component { CommentHistory.propTypes = { comments: PropTypes.object.isRequired, loadMore: PropTypes.func, - notify: PropTypes.func, link: PropTypes.func, data: PropTypes.object, root: PropTypes.object, From c7242f5d984b6b6577acdf226eb8c496af053c2d Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 19:47:11 +0100 Subject: [PATCH 11/14] Improve error handling of report feature --- .../components/FlagButton.js | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/client/talk-plugin-flags/components/FlagButton.js b/client/talk-plugin-flags/components/FlagButton.js index 64841a893..b2048e105 100644 --- a/client/talk-plugin-flags/components/FlagButton.js +++ b/client/talk-plugin-flags/components/FlagButton.js @@ -60,9 +60,10 @@ export default class FlagButton extends Component { }); }; - onPopupContinue = () => { + onPopupContinue = async () => { const { postFlag, postDontAgree, id, author_id } = this.props; const { itemType, reason, step, message } = this.state; + let failed = false; switch (step) { case 0: @@ -75,13 +76,9 @@ export default class FlagButton extends Component { return; } break; - } - - // Proceed to the next step or close the menu if we've reached the end - if (step + 1 >= this.props.getPopupMenu.length) { - this.closeMenu(); - } else { - this.setState({ step: step + 1 }); + case this.props.getPopupMenu.length: + this.closeMenu(); + return; } // If itemType and reason are both set, post the action @@ -96,43 +93,46 @@ export default class FlagButton extends Component { break; } - if (itemType === 'COMMENTS') { - this.setState({ localPost: 'temp' }); - } - let action = { item_id, item_type: itemType, message, }; + if (reason === REASONS.comment.noagree) { - postDontAgree(action) - .then(({ data }) => { - if (itemType === 'COMMENTS') { - this.setState({ localPost: data.createDontAgree.dontagree.id }); - } - }) - .catch(err => { - this.props.notify('error', getErrorMessages(err)); - console.error(err); - }); - } else { - postFlag({ ...action, reason }) - .then(({ data }) => { - if (itemType === 'COMMENTS') { - this.setState({ localPost: data.createFlag.flag.id }); - } - }) - .catch(errors => { - forEachError(errors, ({ error, msg }) => { - if (error.translation_key === 'ALREADY_EXISTS') { - msg = t('already_flagged_username'); - } - this.props.notify('error', msg); + const result = await postDontAgree(action); + try { + if (itemType === 'COMMENTS') { + this.setState({ + localPost: result.data.createDontAgree.dontagree.id, }); + } + } catch (err) { + this.props.notify('error', getErrorMessages(err)); + console.error(err); + failed = true; + } + } else { + try { + const result = await postFlag({ ...action, reason }); + if (itemType === 'COMMENTS') { + this.setState({ localPost: result.data.createFlag.flag.id }); + } + } catch (errors) { + forEachError(errors, ({ error, msg }) => { + if (error.translation_key === 'ALREADY_EXISTS') { + msg = t('already_flagged_username'); + } + this.props.notify('error', msg); }); + failed = true; + } } } + + if (!failed) { + this.setState({ step: step + 1 }); + } }; onPopupOptionClick = sets => e => { From b196bb379a2981f83d0c1cb70951ed3a0053b227 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 19:52:04 +0100 Subject: [PATCH 12/14] Comments --- client/coral-framework/hocs/withMutation.js | 4 ++++ client/coral-framework/hocs/withQuery.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/client/coral-framework/hocs/withMutation.js b/client/coral-framework/hocs/withMutation.js index c31e89ce8..d30598cf0 100644 --- a/client/coral-framework/hocs/withMutation.js +++ b/client/coral-framework/hocs/withMutation.js @@ -237,6 +237,10 @@ const createHOC = (document, config, { notifyOnError = true }) => /** * Exports a HOC with the same signature as `graphql`, that will * apply mutation options registered in the graphRegistry. + * + * The returned HOC accepts a settings object with the following properties: + * notifyOnError: show a notification to the user when an error occured. + * Defaults to true, requires the `notify` action to be mounted. */ export default (document, config = {}) => settingsOrComponent => { if (typeof settingsOrComponent === 'function') { diff --git a/client/coral-framework/hocs/withQuery.js b/client/coral-framework/hocs/withQuery.js index 08556b1b3..ec5433609 100644 --- a/client/coral-framework/hocs/withQuery.js +++ b/client/coral-framework/hocs/withQuery.js @@ -346,6 +346,10 @@ const createHOC = (document, config, { notifyOnError = true }) => /** * Exports a HOC with the same signature as `graphql`, that will * apply query options registered in the graphRegistry. + * + * The returned HOC accepts a settings object with the following properties: + * notifyOnError: show a notification to the user when an error occured. + * Defaults to true, requires the `notify` action to be mounted. */ export default (document, config = {}) => settingsOrComponent => { if (typeof settingsOrComponent === 'function') { From 59cdc9fd5deb0950c5294054f928edfa0cc93f46 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 20:06:55 +0100 Subject: [PATCH 13/14] Port plugins --- plugin-api/beta/client/hocs/withReaction.js | 8 +---- plugin-api/beta/client/hocs/withTags.js | 8 ++--- .../client/components/TabPane.js | 4 +-- .../client/containers/ModActionButton.js | 6 ++-- .../client/containers/ModTag.js | 4 +-- .../containers/IgnoreUserConfirmation.js | 17 ++++------- .../client/containers/ApproveCommentAction.js | 15 ++++------ .../client/containers/BanUserDialog.js | 30 ++++++++----------- .../client/containers/RejectCommentAction.js | 15 ++++------ 9 files changed, 39 insertions(+), 68 deletions(-) diff --git a/plugin-api/beta/client/hocs/withReaction.js b/plugin-api/beta/client/hocs/withReaction.js index f5a0167b7..6020d4002 100644 --- a/plugin-api/beta/client/hocs/withReaction.js +++ b/plugin-api/beta/client/hocs/withReaction.js @@ -9,11 +9,7 @@ import withFragments from 'coral-framework/hocs/withFragments'; import withMutation from 'coral-framework/hocs/withMutation'; import { notify } from 'coral-framework/actions/notification'; import { capitalize } from 'coral-framework/helpers/strings'; -import { - getMyActionSummary, - getTotalActionCount, - getErrorMessages, -} from 'coral-framework/utils'; +import { getMyActionSummary, getTotalActionCount } from 'coral-framework/utils'; import hoistStatics from 'recompose/hoistStatics'; import * as PropTypes from 'prop-types'; import { getDefinitionName } from '../utils'; @@ -282,7 +278,6 @@ export default (reaction, options = {}) => }) .catch(err => { this.duringMutation = false; - this.props.notify('error', getErrorMessages(err)); throw err; }); }; @@ -307,7 +302,6 @@ export default (reaction, options = {}) => }) .catch(err => { this.duringMutation = false; - this.props.notify('error', getErrorMessages(err)); throw err; }); }; diff --git a/plugin-api/beta/client/hocs/withTags.js b/plugin-api/beta/client/hocs/withTags.js index 7b95a5e6c..469718ef9 100644 --- a/plugin-api/beta/client/hocs/withTags.js +++ b/plugin-api/beta/client/hocs/withTags.js @@ -7,7 +7,7 @@ import { capitalize } from 'coral-framework/helpers/strings'; import { withAddTag, withRemoveTag } from 'coral-framework/graphql/mutations'; import withFragments from 'coral-framework/hocs/withFragments'; import { notify } from 'coral-framework/actions/notification'; -import { getErrorMessages, isTagged } from 'coral-framework/utils'; +import { isTagged } from 'coral-framework/utils'; import hoistStatics from 'recompose/hoistStatics'; import { getDefinitionName } from '../utils'; @@ -38,7 +38,7 @@ export default (tag, options = {}) => loading = false; postTag = () => { - const { comment, asset, notify } = this.props; + const { comment, asset } = this.props; if (this.loading) { return; @@ -59,13 +59,12 @@ export default (tag, options = {}) => }) .catch(err => { this.loading = false; - notify('error', getErrorMessages(err)); throw err; }); }; deleteTag = () => { - const { comment, asset, notify } = this.props; + const { comment, asset } = this.props; if (this.loading) { return; @@ -84,7 +83,6 @@ export default (tag, options = {}) => }) .catch(err => { this.loading = false; - notify('error', getErrorMessages(err)); throw err; }); }; diff --git a/plugins/talk-plugin-featured-comments/client/components/TabPane.js b/plugins/talk-plugin-featured-comments/client/components/TabPane.js index 084de7d0a..9bdba6fe8 100644 --- a/plugins/talk-plugin-featured-comments/client/components/TabPane.js +++ b/plugins/talk-plugin-featured-comments/client/components/TabPane.js @@ -1,7 +1,6 @@ import React from 'react'; import Comment from '../containers/Comment'; import LoadMore from './LoadMore'; -import { getErrorMessages } from 'plugin-api/beta/client/utils'; class TabPane extends React.Component { state = { @@ -15,9 +14,8 @@ class TabPane extends React.Component { .then(() => { this.setState({ loadingState: 'success' }); }) - .catch(error => { + .catch(() => { this.setState({ loadingState: 'error' }); - this.props.notify('error', getErrorMessages(error)); }); }; diff --git a/plugins/talk-plugin-featured-comments/client/containers/ModActionButton.js b/plugins/talk-plugin-featured-comments/client/containers/ModActionButton.js index 1f210cb95..ea20bddec 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/ModActionButton.js +++ b/plugins/talk-plugin-featured-comments/client/containers/ModActionButton.js @@ -3,18 +3,20 @@ import { bindActionCreators } from 'redux'; import ModActionButton from '../components/ModActionButton'; import { withTags, connect } from 'plugin-api/beta/client/hocs'; import { closeMenu } from 'plugins/talk-plugin-moderation-actions/client/actions'; +import { notify } from 'plugin-api/beta/client/actions/notification'; const mapDispatchToProps = dispatch => bindActionCreators( { + notify, closeMenu, }, dispatch ); const enhance = compose( - withTags('featured'), - connect(null, mapDispatchToProps) + connect(null, mapDispatchToProps), + withTags('featured') ); export default enhance(ModActionButton); diff --git a/plugins/talk-plugin-featured-comments/client/containers/ModTag.js b/plugins/talk-plugin-featured-comments/client/containers/ModTag.js index 990a8a2e9..f120e6f1a 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/ModTag.js +++ b/plugins/talk-plugin-featured-comments/client/containers/ModTag.js @@ -24,8 +24,8 @@ const fragments = { `, }; const enhance = compose( - withTags('featured', { fragments }), - connect(null, mapDispatchToProps) + connect(null, mapDispatchToProps), + withTags('featured', { fragments }) ); export default enhance(ModTag); diff --git a/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js b/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js index 733dab756..5aa834034 100644 --- a/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js +++ b/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js @@ -10,21 +10,16 @@ import { bindActionCreators } from 'redux'; import { closeMenu } from 'plugins/talk-plugin-author-menu/client/actions'; import { notify } from 'plugin-api/beta/client/actions/notification'; import { t } from 'plugin-api/beta/client/services'; -import { getErrorMessages } from 'plugin-api/beta/client/utils'; class IgnoreUserConfirmationContainer extends React.Component { ignoreUser = () => { const { ignoreUser, notify, comment, closeMenu } = this.props; - ignoreUser(comment.user.id) - .then(() => { - notify( - 'success', - t('talk-plugin-ignore-user.notify_success', comment.user.username) - ); - }) - .catch(err => { - notify('error', getErrorMessages(err)); - }); + ignoreUser(comment.user.id).then(() => { + notify( + 'success', + t('talk-plugin-ignore-user.notify_success', comment.user.username) + ); + }); closeMenu(); }; diff --git a/plugins/talk-plugin-moderation-actions/client/containers/ApproveCommentAction.js b/plugins/talk-plugin-moderation-actions/client/containers/ApproveCommentAction.js index 70cb2ce4b..83402115b 100644 --- a/plugins/talk-plugin-moderation-actions/client/containers/ApproveCommentAction.js +++ b/plugins/talk-plugin-moderation-actions/client/containers/ApproveCommentAction.js @@ -1,23 +1,18 @@ import React from 'react'; import { compose } from 'react-apollo'; import { bindActionCreators } from 'redux'; -import { getErrorMessages } from 'plugin-api/beta/client/utils'; import { notify } from 'plugin-api/beta/client/actions/notification'; import ApproveCommentAction from '../components/ApproveCommentAction'; import { connect, withSetCommentStatus } from 'plugin-api/beta/client/hocs'; class ApproveCommentActionContainer extends React.Component { approveComment = async () => { - const { setCommentStatus, comment, hideMenu, notify } = this.props; + const { setCommentStatus, comment, hideMenu } = this.props; - try { - await setCommentStatus({ - commentId: comment.id, - status: 'ACCEPTED', - }); - } catch (err) { - notify('error', getErrorMessages(err)); - } + await setCommentStatus({ + commentId: comment.id, + status: 'ACCEPTED', + }); hideMenu(); }; diff --git a/plugins/talk-plugin-moderation-actions/client/containers/BanUserDialog.js b/plugins/talk-plugin-moderation-actions/client/containers/BanUserDialog.js index 6d64addca..fc7117298 100644 --- a/plugins/talk-plugin-moderation-actions/client/containers/BanUserDialog.js +++ b/plugins/talk-plugin-moderation-actions/client/containers/BanUserDialog.js @@ -9,13 +9,11 @@ import { withSetCommentStatus, withBanUser, } from 'plugin-api/beta/client/hocs'; -import { getErrorMessages } from 'plugin-api/beta/client/utils'; import BanUserDialog from '../components/BanUserDialog'; class BanUserDialogContainer extends React.Component { banUser = async () => { const { - notify, authorId, commentId, commentStatus, @@ -25,23 +23,19 @@ class BanUserDialogContainer extends React.Component { banUser, } = this.props; - try { - await banUser({ - id: authorId, - message: '', + await banUser({ + id: authorId, + message: '', + }); + + closeMenu(); + closeBanDialog(); + + if (commentStatus !== 'REJECTED') { + await setCommentStatus({ + commentId: commentId, + status: 'REJECTED', }); - - closeMenu(); - closeBanDialog(); - - if (commentStatus !== 'REJECTED') { - await setCommentStatus({ - commentId: commentId, - status: 'REJECTED', - }); - } - } catch (err) { - notify('error', getErrorMessages(err)); } }; diff --git a/plugins/talk-plugin-moderation-actions/client/containers/RejectCommentAction.js b/plugins/talk-plugin-moderation-actions/client/containers/RejectCommentAction.js index e49fdddba..498eae0f5 100644 --- a/plugins/talk-plugin-moderation-actions/client/containers/RejectCommentAction.js +++ b/plugins/talk-plugin-moderation-actions/client/containers/RejectCommentAction.js @@ -1,23 +1,18 @@ import React from 'react'; import { compose } from 'react-apollo'; import { bindActionCreators } from 'redux'; -import { getErrorMessages } from 'plugin-api/beta/client/utils'; import { notify } from 'plugin-api/beta/client/actions/notification'; import RejectCommentAction from '../components/RejectCommentAction'; import { connect, withSetCommentStatus } from 'plugin-api/beta/client/hocs'; class RejectCommentActionContainer extends React.Component { rejectComment = async () => { - const { setCommentStatus, comment, hideMenu, notify } = this.props; + const { setCommentStatus, comment, hideMenu } = this.props; - try { - await setCommentStatus({ - commentId: comment.id, - status: 'REJECTED', - }); - } catch (err) { - notify('error', getErrorMessages(err)); - } + await setCommentStatus({ + commentId: comment.id, + status: 'REJECTED', + }); hideMenu(); }; From d15694041aec1057c5a11f8742622436bb7fd4a1 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 23 Jan 2018 20:27:46 +0100 Subject: [PATCH 14/14] Don't require notify property --- .../coral-admin/src/containers/BanUserDialog.js | 2 -- client/coral-admin/src/containers/UserDetail.js | 2 -- .../src/routes/Community/containers/People.js | 2 -- .../containers/RejectUsernameDialog.js | 2 -- .../routes/Configure/containers/Configure.js | 2 -- .../configure/containers/AssetStatusInfo.js | 12 ------------ .../src/tabs/configure/containers/Settings.js | 2 -- .../tabs/stream/containers/ChangeUsername.js | 15 +-------------- client/coral-framework/hocs/withMutation.js | 12 +++--------- client/coral-framework/hocs/withQuery.js | 13 ++++--------- plugin-api/beta/client/hocs/withTags.js | 7 +------ .../client/components/ModTag.js | 1 - .../client/containers/ModActionButton.js | 2 -- .../client/containers/ModTag.js | 2 -- .../client/containers/TabPane.js | 2 -- .../client/containers/ApproveCommentAction.js | 17 ++--------------- .../client/containers/BanUserDialog.js | 2 -- .../client/containers/RejectCommentAction.js | 17 ++--------------- 18 files changed, 13 insertions(+), 101 deletions(-) diff --git a/client/coral-admin/src/containers/BanUserDialog.js b/client/coral-admin/src/containers/BanUserDialog.js index 642f7f6ee..3617902ff 100644 --- a/client/coral-admin/src/containers/BanUserDialog.js +++ b/client/coral-admin/src/containers/BanUserDialog.js @@ -10,7 +10,6 @@ import { } from 'coral-framework/graphql/mutations'; import { compose } from 'react-apollo'; import t from 'coral-framework/services/i18n'; -import { notify } from 'coral-framework/actions/notification'; class BanUserDialogContainer extends Component { banUser = async () => { @@ -72,7 +71,6 @@ const mapDispatchToProps = dispatch => ({ ...bindActionCreators( { hideBanUserDialog, - notify, }, dispatch ), diff --git a/client/coral-admin/src/containers/UserDetail.js b/client/coral-admin/src/containers/UserDetail.js index 5b5c12bec..fb1508a2f 100644 --- a/client/coral-admin/src/containers/UserDetail.js +++ b/client/coral-admin/src/containers/UserDetail.js @@ -26,7 +26,6 @@ import UserDetailComment from './UserDetailComment'; import update from 'immutability-helper'; import { showBanUserDialog } from 'actions/banUserDialog'; import { showSuspendUserDialog } from 'actions/suspendUserDialog'; -import { notify } from 'coral-framework/actions/notification'; const commentConnectionFragment = gql` fragment CoralAdmin_UserDetail_CommentConnection on CommentConnection { @@ -272,7 +271,6 @@ const mapDispatchToProps = dispatch => ({ viewUserDetail, hideUserDetail, toggleSelectAllCommentInUserDetail, - notify, }, dispatch ), diff --git a/client/coral-admin/src/routes/Community/containers/People.js b/client/coral-admin/src/routes/Community/containers/People.js index d958d7378..f8271b236 100644 --- a/client/coral-admin/src/routes/Community/containers/People.js +++ b/client/coral-admin/src/routes/Community/containers/People.js @@ -16,7 +16,6 @@ import { appendNewNodes } from 'plugin-api/beta/client/utils'; import update from 'immutability-helper'; import { Spinner } from 'coral-ui'; import withQuery from 'coral-framework/hocs/withQuery'; -import { notify } from 'coral-framework/actions/notification'; class PeopleContainer extends React.Component { timer = null; @@ -132,7 +131,6 @@ const mapDispatchToProps = dispatch => viewUserDetail, showSuspendUserDialog, showBanUserDialog, - notify, }, dispatch ); diff --git a/client/coral-admin/src/routes/Community/containers/RejectUsernameDialog.js b/client/coral-admin/src/routes/Community/containers/RejectUsernameDialog.js index bf4490284..325eadfb5 100644 --- a/client/coral-admin/src/routes/Community/containers/RejectUsernameDialog.js +++ b/client/coral-admin/src/routes/Community/containers/RejectUsernameDialog.js @@ -4,7 +4,6 @@ import { hideRejectUsernameDialog } from '../../../actions/community'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { compose } from 'react-apollo'; -import { notify } from 'coral-framework/actions/notification'; const mapStateToProps = state => ({ user: state.community.user, @@ -15,7 +14,6 @@ const mapDispatchToProps = dispatch => bindActionCreators( { handleClose: hideRejectUsernameDialog, - notify, }, dispatch ); diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index 254e39d70..ce33fa1f4 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -12,7 +12,6 @@ import TechSettings from './TechSettings'; import ModerationSettings from './ModerationSettings'; import { clearPending, setActiveSection } from '../../../actions/configure'; import Configure from '../components/Configure'; -import { notify } from 'coral-framework/actions/notification'; class ConfigureContainer extends Component { savePending = async () => { @@ -83,7 +82,6 @@ const mapDispatchToProps = dispatch => { clearPending, setActiveSection, - notify, }, dispatch ); diff --git a/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js b/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js index c97d8e068..ed0746d29 100644 --- a/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js +++ b/client/coral-embed-stream/src/tabs/configure/containers/AssetStatusInfo.js @@ -7,9 +7,6 @@ import { withUpdateAssetStatus, withCloseAsset, } from 'coral-framework/graphql/mutations'; -import { notify } from 'coral-framework/actions/notification'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; class AssetStatusInfoContainer extends React.Component { openAsset = () => @@ -45,16 +42,7 @@ const withAssetStatusInfoFragments = withFragments({ `, }); -const mapDispatchToProps = dispatch => - bindActionCreators( - { - notify, - }, - dispatch - ); - const enhance = compose( - connect(null, mapDispatchToProps), withAssetStatusInfoFragments, withUpdateAssetStatus, withCloseAsset diff --git a/client/coral-embed-stream/src/tabs/configure/containers/Settings.js b/client/coral-embed-stream/src/tabs/configure/containers/Settings.js index 9bfeb149e..2058ceaa2 100644 --- a/client/coral-embed-stream/src/tabs/configure/containers/Settings.js +++ b/client/coral-embed-stream/src/tabs/configure/containers/Settings.js @@ -8,7 +8,6 @@ import { withUpdateAssetSettings } from 'coral-framework/graphql/mutations'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { clearPending, updatePending } from '../../../actions/configure'; -import { notify } from 'coral-framework/actions/notification'; const slots = ['streamSettings']; @@ -129,7 +128,6 @@ const mapDispatchToProps = dispatch => { clearPending, updatePending, - notify, }, dispatch ); diff --git a/client/coral-embed-stream/src/tabs/stream/containers/ChangeUsername.js b/client/coral-embed-stream/src/tabs/stream/containers/ChangeUsername.js index 098513aaf..cc0b84f02 100644 --- a/client/coral-embed-stream/src/tabs/stream/containers/ChangeUsername.js +++ b/client/coral-embed-stream/src/tabs/stream/containers/ChangeUsername.js @@ -1,18 +1,5 @@ import { compose } from 'react-apollo'; import { withChangeUsername } from 'coral-framework/graphql/mutations'; import ChangeUsername from '../components/ChangeUsername'; -import { notify } from 'coral-framework/actions/notification'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; -const mapDispatchToProps = dispatch => - bindActionCreators( - { - notify, - }, - dispatch - ); - -export default compose(connect(null, mapDispatchToProps), withChangeUsername)( - ChangeUsername -); +export default compose(withChangeUsername)(ChangeUsername); diff --git a/client/coral-framework/hocs/withMutation.js b/client/coral-framework/hocs/withMutation.js index d30598cf0..dae38071f 100644 --- a/client/coral-framework/hocs/withMutation.js +++ b/client/coral-framework/hocs/withMutation.js @@ -13,6 +13,7 @@ import PropTypes from 'prop-types'; import t from 'coral-framework/services/i18n'; import hoistStatics from 'recompose/hoistStatics'; import union from 'lodash/union'; +import { notify } from 'coral-framework/actions/notification'; class ResponseErrors extends Error { constructor(errors) { @@ -55,14 +56,7 @@ const createHOC = (document, config, { notifyOnError = true }) => } notifyErrors(messages) { - if (this.props.notify) { - this.props.notify('error', messages); - } else { - console.error( - '`notifyOnError` is set to `true` but missing `notify` property' - ); - console.error(messages); - } + this.context.store.dispatch(notify('error', messages)); } resolveDocument(documentOrCallback) { @@ -240,7 +234,7 @@ const createHOC = (document, config, { notifyOnError = true }) => * * The returned HOC accepts a settings object with the following properties: * notifyOnError: show a notification to the user when an error occured. - * Defaults to true, requires the `notify` action to be mounted. + * Defaults to true. */ export default (document, config = {}) => settingsOrComponent => { if (typeof settingsOrComponent === 'function') { diff --git a/client/coral-framework/hocs/withQuery.js b/client/coral-framework/hocs/withQuery.js index ec5433609..c4b9074b4 100644 --- a/client/coral-framework/hocs/withQuery.js +++ b/client/coral-framework/hocs/withQuery.js @@ -10,6 +10,7 @@ import hoistStatics from 'recompose/hoistStatics'; import { getOperationName } from 'apollo-client/queries/getFromAST'; import throttle from 'lodash/throttle'; import get from 'lodash/get'; +import { notify } from 'coral-framework/actions/notification'; const withSkipOnErrors = reducer => (prev, action, ...rest) => { if ( @@ -49,6 +50,7 @@ const createHOC = (document, config, { notifyOnError = true }) => eventEmitter: PropTypes.object, graphql: PropTypes.object, client: PropTypes.object, + store: PropTypes.object, }; static propTypes = { @@ -169,14 +171,7 @@ const createHOC = (document, config, { notifyOnError = true }) => }; notifyErrors(messages) { - if (this.props.notify) { - this.props.notify('error', messages); - } else { - console.error( - '`notifyOnError` is set to `true` but missing `notify` property' - ); - console.error(messages); - } + this.context.store.dispatch(notify('error', messages)); } nextData(data) { @@ -349,7 +344,7 @@ const createHOC = (document, config, { notifyOnError = true }) => * * The returned HOC accepts a settings object with the following properties: * notifyOnError: show a notification to the user when an error occured. - * Defaults to true, requires the `notify` action to be mounted. + * Defaults to true. */ export default (document, config = {}) => settingsOrComponent => { if (typeof settingsOrComponent === 'function') { diff --git a/plugin-api/beta/client/hocs/withTags.js b/plugin-api/beta/client/hocs/withTags.js index 469718ef9..958028a4b 100644 --- a/plugin-api/beta/client/hocs/withTags.js +++ b/plugin-api/beta/client/hocs/withTags.js @@ -1,12 +1,10 @@ import React from 'react'; import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; import { compose, gql } from 'react-apollo'; import { getDisplayName } from 'coral-framework/helpers/hoc'; import { capitalize } from 'coral-framework/helpers/strings'; import { withAddTag, withRemoveTag } from 'coral-framework/graphql/mutations'; import withFragments from 'coral-framework/hocs/withFragments'; -import { notify } from 'coral-framework/actions/notification'; import { isTagged } from 'coral-framework/utils'; import hoistStatics from 'recompose/hoistStatics'; import { getDefinitionName } from '../utils'; @@ -112,9 +110,6 @@ export default (tag, options = {}) => user: state.auth.user, }); - const mapDispatchToProps = dispatch => - bindActionCreators({ notify }, dispatch); - const enhance = compose( withFragments({ ...fragments, @@ -144,7 +139,7 @@ export default (tag, options = {}) => }), withAddTag, withRemoveTag, - connect(mapStateToProps, mapDispatchToProps) + connect(mapStateToProps, null) ); WithTags.displayName = `WithTags(${getDisplayName(WrappedComponent)})`; diff --git a/plugins/talk-plugin-featured-comments/client/components/ModTag.js b/plugins/talk-plugin-featured-comments/client/components/ModTag.js index 420ee9417..659b2cea4 100644 --- a/plugins/talk-plugin-featured-comments/client/components/ModTag.js +++ b/plugins/talk-plugin-featured-comments/client/components/ModTag.js @@ -64,7 +64,6 @@ export default class ModTag extends React.Component { ModTag.propTypes = { alreadyTagged: PropTypes.bool, deleteTag: PropTypes.func, - notify: PropTypes.func, openFeaturedDialog: PropTypes.func, comment: PropTypes.object, asset: PropTypes.object, diff --git a/plugins/talk-plugin-featured-comments/client/containers/ModActionButton.js b/plugins/talk-plugin-featured-comments/client/containers/ModActionButton.js index ea20bddec..7c8f94fb3 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/ModActionButton.js +++ b/plugins/talk-plugin-featured-comments/client/containers/ModActionButton.js @@ -3,12 +3,10 @@ import { bindActionCreators } from 'redux'; import ModActionButton from '../components/ModActionButton'; import { withTags, connect } from 'plugin-api/beta/client/hocs'; import { closeMenu } from 'plugins/talk-plugin-moderation-actions/client/actions'; -import { notify } from 'plugin-api/beta/client/actions/notification'; const mapDispatchToProps = dispatch => bindActionCreators( { - notify, closeMenu, }, dispatch diff --git a/plugins/talk-plugin-featured-comments/client/containers/ModTag.js b/plugins/talk-plugin-featured-comments/client/containers/ModTag.js index f120e6f1a..42c653418 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/ModTag.js +++ b/plugins/talk-plugin-featured-comments/client/containers/ModTag.js @@ -3,12 +3,10 @@ import { withTags, connect } from 'plugin-api/beta/client/hocs'; import { gql, compose } from 'react-apollo'; import { bindActionCreators } from 'redux'; import { openFeaturedDialog } from '../actions'; -import { notify } from 'plugin-api/beta/client/actions/notification'; const mapDispatchToProps = dispatch => bindActionCreators( { - notify, openFeaturedDialog, }, dispatch diff --git a/plugins/talk-plugin-featured-comments/client/containers/TabPane.js b/plugins/talk-plugin-featured-comments/client/containers/TabPane.js index 5bf92fb0a..297f5aedf 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/TabPane.js +++ b/plugins/talk-plugin-featured-comments/client/containers/TabPane.js @@ -4,7 +4,6 @@ import { compose, gql } from 'react-apollo'; import TabPane from '../components/TabPane'; import { withFragments, connect } from 'plugin-api/beta/client/hocs'; import Comment from '../containers/Comment'; -import { notify } from 'plugin-api/beta/client/actions/notification'; import { viewComment } from 'coral-embed-stream/src/actions/stream'; import { appendNewNodes, @@ -81,7 +80,6 @@ const mapDispatchToProps = dispatch => bindActionCreators( { viewComment, - notify, }, dispatch ); diff --git a/plugins/talk-plugin-moderation-actions/client/containers/ApproveCommentAction.js b/plugins/talk-plugin-moderation-actions/client/containers/ApproveCommentAction.js index 83402115b..1f7bed3bb 100644 --- a/plugins/talk-plugin-moderation-actions/client/containers/ApproveCommentAction.js +++ b/plugins/talk-plugin-moderation-actions/client/containers/ApproveCommentAction.js @@ -1,9 +1,7 @@ import React from 'react'; import { compose } from 'react-apollo'; -import { bindActionCreators } from 'redux'; -import { notify } from 'plugin-api/beta/client/actions/notification'; import ApproveCommentAction from '../components/ApproveCommentAction'; -import { connect, withSetCommentStatus } from 'plugin-api/beta/client/hocs'; +import { withSetCommentStatus } from 'plugin-api/beta/client/hocs'; class ApproveCommentActionContainer extends React.Component { approveComment = async () => { @@ -27,17 +25,6 @@ class ApproveCommentActionContainer extends React.Component { } } -const mapDispatchToProps = dispatch => - bindActionCreators( - { - notify, - }, - dispatch - ); - -const enhance = compose( - connect(null, mapDispatchToProps), - withSetCommentStatus -); +const enhance = compose(withSetCommentStatus); export default enhance(ApproveCommentActionContainer); diff --git a/plugins/talk-plugin-moderation-actions/client/containers/BanUserDialog.js b/plugins/talk-plugin-moderation-actions/client/containers/BanUserDialog.js index fc7117298..8dd3cce7d 100644 --- a/plugins/talk-plugin-moderation-actions/client/containers/BanUserDialog.js +++ b/plugins/talk-plugin-moderation-actions/client/containers/BanUserDialog.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import { compose } from 'react-apollo'; import { bindActionCreators } from 'redux'; import { closeBanDialog, closeMenu } from '../actions'; -import { notify } from 'plugin-api/beta/client/actions/notification'; import { connect, withSetCommentStatus, @@ -64,7 +63,6 @@ const mapStateToProps = ({ talkPluginModerationActions: state }) => ({ const mapDispatchToProps = dispatch => bindActionCreators( { - notify, closeBanDialog, closeMenu, }, diff --git a/plugins/talk-plugin-moderation-actions/client/containers/RejectCommentAction.js b/plugins/talk-plugin-moderation-actions/client/containers/RejectCommentAction.js index 498eae0f5..54ca0420d 100644 --- a/plugins/talk-plugin-moderation-actions/client/containers/RejectCommentAction.js +++ b/plugins/talk-plugin-moderation-actions/client/containers/RejectCommentAction.js @@ -1,9 +1,7 @@ import React from 'react'; import { compose } from 'react-apollo'; -import { bindActionCreators } from 'redux'; -import { notify } from 'plugin-api/beta/client/actions/notification'; import RejectCommentAction from '../components/RejectCommentAction'; -import { connect, withSetCommentStatus } from 'plugin-api/beta/client/hocs'; +import { withSetCommentStatus } from 'plugin-api/beta/client/hocs'; class RejectCommentActionContainer extends React.Component { rejectComment = async () => { @@ -22,17 +20,6 @@ class RejectCommentActionContainer extends React.Component { } } -const mapDispatchToProps = dispatch => - bindActionCreators( - { - notify, - }, - dispatch - ); - -const enhance = compose( - connect(null, mapDispatchToProps), - withSetCommentStatus -); +const enhance = compose(withSetCommentStatus); export default enhance(RejectCommentActionContainer);