From 791bc5e7ac5c33f6fa72202055cb18f6533c251c Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 22 Sep 2017 18:52:06 +0100 Subject: [PATCH 1/4] Create GroupSummaryStore for storing group summary stuff - Acts as a layer between GroupView and the group APIs that modify the summary individually. This allows for abstraction of getting the new summary once a successful API hit has been done. - The plan is to also control the avatar, topic, body of the summary via the same class --- src/components/structures/GroupView.js | 43 ++++++++++++---- src/i18n/strings/en_EN.json | 1 + src/stores/GroupSummaryStore.js | 71 ++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 src/stores/GroupSummaryStore.js diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 4f61bc4647..d3eb97180a 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -27,6 +27,8 @@ import AccessibleButton from '../views/elements/AccessibleButton'; import Modal from '../../Modal'; import classnames from 'classnames'; +import GroupSummaryStore from '../../stores/GroupSummaryStore'; + const RoomSummaryType = PropTypes.shape({ room_id: PropTypes.string.isRequired, profile: PropTypes.shape({ @@ -76,8 +78,8 @@ const CategoryRoomList = React.createClass({ if (!success) return; const errorList = []; Promise.all(addrs.map((addr) => { - return MatrixClientPeg.get() - .addRoomToGroupSummary(this.props.groupId, addr.address) + return this.context.groupSummaryStore + .addRoomToGroupSummary(addr.address) .catch(() => { errorList.push(addr.address); }) .reflect(); })).then(() => { @@ -153,8 +155,7 @@ const FeaturedRoom = React.createClass({ onDeleteClicked: function(e) { e.preventDefault(); e.stopPropagation(); - MatrixClientPeg.get().removeRoomFromGroupSummary( - this.props.groupId, + this.context.groupSummaryStore.removeRoomFromGroupSummary( this.props.summaryInfo.room_id, ).catch((err) => { console.error('Error whilst removing room from group summary', err); @@ -242,8 +243,8 @@ const RoleUserList = React.createClass({ if (!success) return; const errorList = []; Promise.all(addrs.map((addr) => { - return MatrixClientPeg.get() - .addUserToGroupSummary(this.props.groupId, addr.address) + return this.context.groupSummaryStore + .addUserToGroupSummary(addr.address) .catch(() => { errorList.push(addr.address); }) .reflect(); })).then(() => { @@ -317,8 +318,7 @@ const FeaturedUser = React.createClass({ onDeleteClicked: function(e) { e.preventDefault(); e.stopPropagation(); - MatrixClientPeg.get().removeUserFromGroupSummary( - this.props.groupId, + this.context.groupSummaryStore.removeUserFromGroupSummary( this.props.summaryInfo.user_id, ).catch((err) => { console.error('Error whilst removing user from group summary', err); @@ -364,6 +364,15 @@ const FeaturedUser = React.createClass({ }, }); +const GroupSummaryContext = { + groupSummaryStore: React.PropTypes.instanceOf(GroupSummaryStore).isRequired, +}; + +CategoryRoomList.contextTypes = GroupSummaryContext; +FeaturedRoom.contextTypes = GroupSummaryContext; +RoleUserList.contextTypes = GroupSummaryContext; +FeaturedUser.contextTypes = GroupSummaryContext; + export default React.createClass({ displayName: 'GroupView', @@ -371,6 +380,16 @@ export default React.createClass({ groupId: PropTypes.string.isRequired, }, + childContextTypes: { + groupSummaryStore: React.PropTypes.instanceOf(GroupSummaryStore), + }, + + getChildContext: function() { + return { + groupSummaryStore: this._groupSummaryStore, + }; + }, + getInitialState: function() { return { summary: null, @@ -411,12 +430,14 @@ export default React.createClass({ }, _loadGroupFromServer: function(groupId) { - MatrixClientPeg.get().getGroupSummary(groupId).done((res) => { + this._groupSummaryStore = new GroupSummaryStore(this.props.groupId); + this._groupSummaryStore.on('update', () => { this.setState({ - summary: res, + summary: this._groupSummaryStore.getSummary(), error: null, }); - }, (err) => { + }); + this._groupSummaryStore.on('error', (err) => { this.setState({ summary: null, error: err, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a0945d7f50..038d26ba4c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -876,6 +876,7 @@ "Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?", "Room name or alias": "Room name or alias", "You are an administrator of this group": "You are an administrator of this group", + "Failed to add the following rooms to the summary of %(groupId)s:": "Failed to add the following rooms to the summary of %(groupId)s:", "Failed to remove the room from the summary of %(groupId)s": "Failed to remove the room from the summary of %(groupId)s", "The room '%(roomName)' could not be removed from the summary.": "The room '%(roomName)' could not be removed from the summary.", "Failed to remove a user from the summary of %(groupId)s": "Failed to remove a user from the summary of %(groupId)s", diff --git a/src/stores/GroupSummaryStore.js b/src/stores/GroupSummaryStore.js new file mode 100644 index 0000000000..a26f0f2d61 --- /dev/null +++ b/src/stores/GroupSummaryStore.js @@ -0,0 +1,71 @@ +/* +Copyright 2017 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import EventEmitter from 'events'; +import MatrixClientPeg from '../MatrixClientPeg'; + +/** + * Stores the group summary for a room and provides an API to change it + */ +export default class GroupSummaryStore extends EventEmitter { + constructor(groupId) { + super(); + this._groupId = groupId; + this._summary = {}; + this._fetchSummary(); + } + + _fetchSummary() { + MatrixClientPeg.get().getGroupSummary(this._groupId).then((resp) => { + this._summary = resp; + this._notifyListeners(); + }).catch((err) => { + this.emit('error', err); + }); + } + + _notifyListeners() { + this.emit('update'); + } + + getSummary() { + return this._summary; + } + + addRoomToGroupSummary(roomId, categoryId) { + return MatrixClientPeg.get() + .addRoomToGroupSummary(this._groupId, roomId, categoryId) + .then(this._fetchSummary.bind(this)); + } + + addUserToGroupSummary(userId, roleId) { + return MatrixClientPeg.get() + .addUserToGroupSummary(this._groupId, userId, roleId) + .then(this._fetchSummary.bind(this)); + } + + removeRoomFromGroupSummary(roomId) { + return MatrixClientPeg.get() + .removeRoomFromGroupSummary(this._groupId, roomId) + .then(this._fetchSummary.bind(this)); + } + + removeUserFromGroupSummary(userId) { + return MatrixClientPeg.get() + .removeUserFromGroupSummary(this._groupId, userId) + .then(this._fetchSummary.bind(this)); + } +} From b8dca58f4f239edfc987ff472a6ce8cd3ece8872 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 25 Sep 2017 10:02:13 +0100 Subject: [PATCH 2/4] Pass matrixClient as an argument to GSS constructor --- src/components/structures/GroupView.js | 4 +++- src/stores/GroupSummaryStore.js | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index d3eb97180a..77034c3594 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -430,7 +430,9 @@ export default React.createClass({ }, _loadGroupFromServer: function(groupId) { - this._groupSummaryStore = new GroupSummaryStore(this.props.groupId); + this._groupSummaryStore = new GroupSummaryStore( + MatrixClientPeg.get(), this.props.groupId, + ); this._groupSummaryStore.on('update', () => { this.setState({ summary: this._groupSummaryStore.getSummary(), diff --git a/src/stores/GroupSummaryStore.js b/src/stores/GroupSummaryStore.js index a26f0f2d61..170a1ec11e 100644 --- a/src/stores/GroupSummaryStore.js +++ b/src/stores/GroupSummaryStore.js @@ -15,21 +15,21 @@ limitations under the License. */ import EventEmitter from 'events'; -import MatrixClientPeg from '../MatrixClientPeg'; /** * Stores the group summary for a room and provides an API to change it */ export default class GroupSummaryStore extends EventEmitter { - constructor(groupId) { + constructor(matrixClient, groupId) { super(); this._groupId = groupId; + this._matrixClient = matrixClient; this._summary = {}; this._fetchSummary(); } _fetchSummary() { - MatrixClientPeg.get().getGroupSummary(this._groupId).then((resp) => { + this._matrixClient.getGroupSummary(this._groupId).then((resp) => { this._summary = resp; this._notifyListeners(); }).catch((err) => { @@ -46,25 +46,25 @@ export default class GroupSummaryStore extends EventEmitter { } addRoomToGroupSummary(roomId, categoryId) { - return MatrixClientPeg.get() + return this._matrixClient .addRoomToGroupSummary(this._groupId, roomId, categoryId) .then(this._fetchSummary.bind(this)); } addUserToGroupSummary(userId, roleId) { - return MatrixClientPeg.get() + return this._matrixClient .addUserToGroupSummary(this._groupId, userId, roleId) .then(this._fetchSummary.bind(this)); } removeRoomFromGroupSummary(roomId) { - return MatrixClientPeg.get() + return this._matrixClient .removeRoomFromGroupSummary(this._groupId, roomId) .then(this._fetchSummary.bind(this)); } removeUserFromGroupSummary(userId) { - return MatrixClientPeg.get() + return this._matrixClient .removeUserFromGroupSummary(this._groupId, userId) .then(this._fetchSummary.bind(this)); } From 8e7d58797dbb0462ada9b5209e8e7a6239b8277c Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 25 Sep 2017 14:48:49 +0100 Subject: [PATCH 3/4] _loadGroupFromServer -> _initGroupSummaryStore --- src/components/structures/GroupView.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 77034c3594..969a58bf9f 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -403,7 +403,7 @@ export default React.createClass({ componentWillMount: function() { this._changeAvatarComponent = null; - this._loadGroupFromServer(this.props.groupId); + this._initGroupSummaryStore(this.props.groupId); MatrixClientPeg.get().on("Group.myMembership", this._onGroupMyMembership); }, @@ -418,7 +418,7 @@ export default React.createClass({ summary: null, error: null, }, () => { - this._loadGroupFromServer(newProps.groupId); + this._initGroupSummaryStore(newProps.groupId); }); } }, @@ -429,7 +429,7 @@ export default React.createClass({ this.setState({membershipBusy: false}); }, - _loadGroupFromServer: function(groupId) { + _initGroupSummaryStore: function(groupId) { this._groupSummaryStore = new GroupSummaryStore( MatrixClientPeg.get(), this.props.groupId, ); @@ -516,7 +516,7 @@ export default React.createClass({ editing: false, summary: null, }); - this._loadGroupFromServer(this.props.groupId); + this._initGroupSummaryStore(this.props.groupId); }).catch((e) => { this.setState({ saving: false, From 83e6218930baa64845dafbaa4d25455643af2cba Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 25 Sep 2017 14:49:12 +0100 Subject: [PATCH 4/4] Remove listeners from group summary store on unmount --- src/components/structures/GroupView.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 969a58bf9f..21ec733f3f 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -410,6 +410,7 @@ export default React.createClass({ componentWillUnmount: function() { MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership); + this._groupSummaryStore.removeAllListeners(); }, componentWillReceiveProps: function(newProps) {