From 84f1003b2b959ed213bcc4e9ba7315560b3bcd99 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 13 Mar 2018 19:58:32 +0100 Subject: [PATCH] Get rid of `data` direct dependency in the plugins --- client/coral-framework/hocs/index.js | 4 +++ client/coral-framework/hocs/withFetchMore.js | 27 +++++++++++++++++++ client/coral-framework/hocs/withQuery.js | 22 ++++++++++++--- client/coral-framework/hocs/withRefetch.js | 23 ++++++++++++++++ .../hocs/withSubscribeToMore.js | 27 +++++++++++++++++++ client/coral-framework/hocs/withVariables.js | 26 ++++++++++++++++++ package.json | 1 + plugin-api/beta/client/hocs/index.js | 5 ++++ .../client/containers/AuthorName.js | 4 +-- .../client/components/Comment.js | 11 +++----- .../client/components/TabPane.js | 2 -- .../containers/ModIndicatorSubscription.js | 5 ++-- .../client/containers/ModSubscription.js | 17 +++++++++--- .../client/containers/TabPane.js | 17 ++++++++---- .../client/components/FlagDetails.js | 4 +-- .../client/components/ModerationActions.js | 3 --- .../client/containers/ModerationActions.js | 1 - .../client/containers/Settings.js | 2 -- .../client/containers/ViewingOptions.js | 3 +-- yarn.lock | 7 +++++ 20 files changed, 172 insertions(+), 39 deletions(-) create mode 100644 client/coral-framework/hocs/withFetchMore.js create mode 100644 client/coral-framework/hocs/withRefetch.js create mode 100644 client/coral-framework/hocs/withSubscribeToMore.js create mode 100644 client/coral-framework/hocs/withVariables.js diff --git a/client/coral-framework/hocs/index.js b/client/coral-framework/hocs/index.js index a0f0a3e9c..97bf910d9 100644 --- a/client/coral-framework/hocs/index.js +++ b/client/coral-framework/hocs/index.js @@ -14,6 +14,10 @@ export { default as withPopupAuthHandler } from './withPopupAuthHandler'; export { default as withEnumValues } from './withEnumValues'; export { default as withCombatPassthrough } from './withCombatPassthrough'; export { default as withSlotElements } from './withSlotElements'; +export { default as withVariables } from './withVariables'; +export { default as WithRefetch } from './withRefetch'; +export { default as withFetchMore } from './withFetchMore'; +export { default as withSubscribeToMore } from './withSubscribeToMore'; export { default as withResendEmailConfirmation, } from './withResendEmailConfirmation'; diff --git a/client/coral-framework/hocs/withFetchMore.js b/client/coral-framework/hocs/withFetchMore.js new file mode 100644 index 000000000..cc2106436 --- /dev/null +++ b/client/coral-framework/hocs/withFetchMore.js @@ -0,0 +1,27 @@ +import React from 'react'; +import hoistStatics from 'recompose/hoistStatics'; +import { Subscriber } from 'react-broadcast'; +import get from 'lodash/get'; + +/** + * WithFetchMore provides a property `fetchMore` to the wrapped component. + * Calling `fetchMore` is the same as calling `data.fetchMore` from the + * Apollo React API. + */ +export default hoistStatics(WrappedComponent => { + class WithFetchMore extends React.Component { + render() { + return ( + + {data => ( + + )} + + ); + } + } + return WithFetchMore; +}); diff --git a/client/coral-framework/hocs/withQuery.js b/client/coral-framework/hocs/withQuery.js index 2c941dc57..807989af5 100644 --- a/client/coral-framework/hocs/withQuery.js +++ b/client/coral-framework/hocs/withQuery.js @@ -11,6 +11,8 @@ import { getOperationName } from 'apollo-client/queries/getFromAST'; import throttle from 'lodash/throttle'; import get from 'lodash/get'; import { notify } from 'coral-framework/actions/notification'; +import { Broadcast } from 'react-broadcast'; +import { compose } from 'recompose'; const withSkipOnErrors = reducer => (prev, action, ...rest) => { if ( @@ -71,6 +73,15 @@ function networkStatusToString(networkStatus) { } } +// When wrapped broadcast all data changes to channel "queryData". +const withBroadcaster = WrappedComponent => props => ( + /* eslint-disable react/prop-types */ + + + + /* eslint-enable react/prop-types */ +); + const createHOC = (document, config, { notifyOnError = true }) => hoistStatics(WrappedComponent => { return class WithQuery extends React.Component { @@ -357,10 +368,13 @@ const createHOC = (document, config, { notifyOnError = true }) => if (!this.memoized) { this.resolvedDocument = this.resolveDocument(document); this.name = getDefinitionName(this.resolvedDocument); - this.memoized = graphql(this.resolvedDocument, { - ...this.wrappedConfig, - options: this.wrappedOptions, - })(WrappedComponent); + this.memoized = compose( + graphql(this.resolvedDocument, { + ...this.wrappedConfig, + options: this.wrappedOptions, + }), + withBroadcaster + )(WrappedComponent); } return this.memoized; }; diff --git a/client/coral-framework/hocs/withRefetch.js b/client/coral-framework/hocs/withRefetch.js new file mode 100644 index 000000000..04848fe11 --- /dev/null +++ b/client/coral-framework/hocs/withRefetch.js @@ -0,0 +1,23 @@ +import React from 'react'; +import hoistStatics from 'recompose/hoistStatics'; +import { Subscriber } from 'react-broadcast'; +import get from 'lodash/get'; + +/** + * WithRefetch provides a property `refetch` to the wrapped component. + * Calling refetch will perform a refetch of the parent Query. + */ +export default hoistStatics(WrappedComponent => { + class WithRefetch extends React.Component { + render() { + return ( + + {data => ( + + )} + + ); + } + } + return WithRefetch; +}); diff --git a/client/coral-framework/hocs/withSubscribeToMore.js b/client/coral-framework/hocs/withSubscribeToMore.js new file mode 100644 index 000000000..67ffe9ae2 --- /dev/null +++ b/client/coral-framework/hocs/withSubscribeToMore.js @@ -0,0 +1,27 @@ +import React from 'react'; +import hoistStatics from 'recompose/hoistStatics'; +import { Subscriber } from 'react-broadcast'; +import get from 'lodash/get'; + +/** + * WithSubscribeToMore provides a property `subscribeToMore` to the wrapped component. + * Calling `subscribeToMore` is the same as calling `data.subscribeToMore` from the + * Apollo React API. + */ +export default hoistStatics(WrappedComponent => { + class WithSubscribeToMore extends React.Component { + render() { + return ( + + {data => ( + + )} + + ); + } + } + return WithSubscribeToMore; +}); diff --git a/client/coral-framework/hocs/withVariables.js b/client/coral-framework/hocs/withVariables.js new file mode 100644 index 000000000..886742f36 --- /dev/null +++ b/client/coral-framework/hocs/withVariables.js @@ -0,0 +1,26 @@ +import React from 'react'; +import hoistStatics from 'recompose/hoistStatics'; +import { Subscriber } from 'react-broadcast'; +import get from 'lodash/get'; + +/** + * WithVariables provides a property `variables` to the wrapped component. + * These are the variables of the parent Query. + */ +export default hoistStatics(WrappedComponent => { + class WithVariables extends React.Component { + render() { + return ( + + {data => ( + + )} + + ); + } + } + return WithVariables; +}); diff --git a/package.json b/package.json index e54ad11d4..585eec6fb 100644 --- a/package.json +++ b/package.json @@ -159,6 +159,7 @@ "query-string": "^5.0.0", "react": "^15.4.2", "react-apollo": "^1.4.12", + "react-broadcast": "^0.6.2", "react-dom": "^15.4.2", "react-input-autosize": "^1.1.4", "react-mdl": "^1.11.0", diff --git a/plugin-api/beta/client/hocs/index.js b/plugin-api/beta/client/hocs/index.js index 35899a418..ff4523084 100644 --- a/plugin-api/beta/client/hocs/index.js +++ b/plugin-api/beta/client/hocs/index.js @@ -13,6 +13,10 @@ export { withResendEmailConfirmation, withSetUsername, withEnumValues, + withVariables, + withFetchMore, + withSubscribeToMore, + withRefetch, } from 'coral-framework/hocs'; export { withIgnoreUser, @@ -21,3 +25,4 @@ export { withStopIgnoringUser, withSetCommentStatus, } from 'coral-framework/graphql/mutations'; +export { compose } from 'recompose'; diff --git a/plugins/talk-plugin-author-menu/client/containers/AuthorName.js b/plugins/talk-plugin-author-menu/client/containers/AuthorName.js index 958610093..e385058c4 100644 --- a/plugins/talk-plugin-author-menu/client/containers/AuthorName.js +++ b/plugins/talk-plugin-author-menu/client/containers/AuthorName.js @@ -49,7 +49,6 @@ class AuthorNameContainer extends React.Component { render() { const { - data, root, asset, comment, @@ -57,7 +56,7 @@ class AuthorNameContainer extends React.Component { showMenuForComment, } = this.props; - const slotPassthrough = { data, root, asset, comment }; + const slotPassthrough = { root, asset, comment }; return ( - +
- this.props.data.subscribeToMore(config) + this.props.subscribeToMore(config) ); } @@ -60,4 +61,4 @@ const COMMENT_UNFEATURED_SUBSCRIPTION = gql` } `; -export default ModIndicatorSubscription; +export default compose(withSubscribeToMore)(ModIndicatorSubscription); diff --git a/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js b/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js index 6d0fdd811..d91d69304 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js +++ b/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js @@ -6,6 +6,11 @@ import { getDefinitionName } from 'coral-framework/utils'; import truncate from 'lodash/truncate'; import t from 'coral-framework/services/i18n'; import { subscriptionFields } from 'coral-admin/src/routes/Moderation/graphql'; +import { + compose, + withSubscribeToMore, + withVariables, +} from 'plugin-api/beta/client/hocs'; function prepareNotificationText(text) { return truncate(text, { length: 50 }).replace('\n', ' '); @@ -19,7 +24,7 @@ class ModSubscription extends React.Component { { document: COMMENT_FEATURED_SUBSCRIPTION, variables: { - assetId: this.props.data.variables.asset_id, + assetId: this.props.variables.asset_id, }, updateQuery: ( prev, @@ -39,7 +44,7 @@ class ModSubscription extends React.Component { { document: COMMENT_UNFEATURED_SUBSCRIPTION, variables: { - assetId: this.props.data.variables.asset_id, + assetId: this.props.variables.asset_id, }, updateQuery: ( prev, @@ -62,7 +67,7 @@ class ModSubscription extends React.Component { }, ]; this.subscriptions = configs.map(config => - this.props.data.subscribeToMore(config) + this.props.subscribeToMore(config) ); } @@ -111,4 +116,8 @@ const mapStateToProps = state => ({ user: state.auth.user, }); -export default connect(mapStateToProps, null)(ModSubscription); +export default compose( + connect(mapStateToProps, null), + withVariables, + withSubscribeToMore +)(ModSubscription); diff --git a/plugins/talk-plugin-featured-comments/client/containers/TabPane.js b/plugins/talk-plugin-featured-comments/client/containers/TabPane.js index 297f5aedf..b3f44b429 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/TabPane.js +++ b/plugins/talk-plugin-featured-comments/client/containers/TabPane.js @@ -2,7 +2,12 @@ import React from 'react'; import { bindActionCreators } from 'redux'; import { compose, gql } from 'react-apollo'; import TabPane from '../components/TabPane'; -import { withFragments, connect } from 'plugin-api/beta/client/hocs'; +import { + withFragments, + connect, + withFetchMore, + withVariables, +} from 'plugin-api/beta/client/hocs'; import Comment from '../containers/Comment'; import { viewComment } from 'coral-embed-stream/src/actions/stream'; import { @@ -13,15 +18,15 @@ import update from 'immutability-helper'; class TabPaneContainer extends React.Component { loadMore = () => { - return this.props.data.fetchMore({ + return this.props.fetchMore({ query: LOAD_MORE_QUERY, variables: { limit: 5, cursor: this.props.asset.featuredComments.endCursor, asset_id: this.props.asset.id, - sortOrder: this.props.data.variables.sortOrder, - sortBy: this.props.data.variables.sortBy, - excludeIgnored: this.props.data.variables.excludeIgnored, + sortOrder: this.props.variables.sortOrder, + sortBy: this.props.variables.sortBy, + excludeIgnored: this.props.variables.excludeIgnored, }, updateQuery: (previous, { fetchMoreResult: { comments } }) => { const updated = update(previous, { @@ -86,6 +91,8 @@ const mapDispatchToProps = dispatch => const enhance = compose( connect(null, mapDispatchToProps), + withFetchMore, + withVariables, withFragments({ root: gql` fragment TalkFeaturedComments_TabPane_root on RootQuery { diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js index 7197c0360..7900f5b50 100644 --- a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js @@ -10,7 +10,7 @@ import { class FlagDetails extends Component { render() { - const { comment: { actions }, more, data, root, comment } = this.props; + const { comment: { actions }, more, root, comment } = this.props; const flagActions = actions && actions.filter(a => a.__typename === 'FlagAction'); @@ -27,7 +27,6 @@ class FlagDetails extends Component { const reasons = Object.keys(summaries); const slotPassthrough = { - data, root, comment, }; @@ -68,7 +67,6 @@ class FlagDetails extends Component { FlagDetails.propTypes = { more: PropTypes.bool, - data: PropTypes.object, root: PropTypes.object, comment: PropTypes.shape({ actions: PropTypes.arrayOf( diff --git a/plugins/talk-plugin-moderation-actions/client/components/ModerationActions.js b/plugins/talk-plugin-moderation-actions/client/components/ModerationActions.js index 6cf2558c1..272202d9c 100644 --- a/plugins/talk-plugin-moderation-actions/client/components/ModerationActions.js +++ b/plugins/talk-plugin-moderation-actions/client/components/ModerationActions.js @@ -16,7 +16,6 @@ export default class ModerationActions extends React.Component { comment, root, asset, - data, menuVisible, toogleMenu, hideMenu, @@ -25,7 +24,6 @@ export default class ModerationActions extends React.Component { const slotPassthrough = { comment, asset, - data, }; return ( @@ -72,7 +70,6 @@ ModerationActions.propTypes = { comment: PropTypes.object, root: PropTypes.object, asset: PropTypes.object, - data: PropTypes.object, menuVisible: PropTypes.bool, toogleMenu: PropTypes.func, hideMenu: PropTypes.func, diff --git a/plugins/talk-plugin-moderation-actions/client/containers/ModerationActions.js b/plugins/talk-plugin-moderation-actions/client/containers/ModerationActions.js index 9e0edb9b3..891d248ce 100644 --- a/plugins/talk-plugin-moderation-actions/client/containers/ModerationActions.js +++ b/plugins/talk-plugin-moderation-actions/client/containers/ModerationActions.js @@ -42,7 +42,6 @@ class ModerationActionsContainer extends React.Component { render() { return ( ({ + mapProps(({ root, asset, ...rest }) => ({ slotPassthrough: { - data, root, asset, }, diff --git a/yarn.lock b/yarn.lock index 13f8f704f..0813f7023 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8677,6 +8677,13 @@ react-apollo@^1.4.12: object-assign "^4.0.1" prop-types "^15.5.8" +react-broadcast@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/react-broadcast/-/react-broadcast-0.6.2.tgz#9555c73b80ca5b2673830872e54f6bb3092cf8a9" + dependencies: + invariant "^2.2.1" + prop-types "^15.6.0" + react-dom@>=0.14.0: version "16.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044"