diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 0a8bfaee38..6a30c1ce41 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, @@ -385,13 +404,14 @@ 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); }, componentWillUnmount: function() { MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership); + this._groupSummaryStore.removeAllListeners(); }, componentWillReceiveProps: function(newProps) { @@ -400,7 +420,7 @@ export default React.createClass({ summary: null, error: null, }, () => { - this._loadGroupFromServer(newProps.groupId); + this._initGroupSummaryStore(newProps.groupId); }); } }, @@ -411,13 +431,17 @@ export default React.createClass({ this.setState({membershipBusy: false}); }, - _loadGroupFromServer: function(groupId) { - MatrixClientPeg.get().getGroupSummary(groupId).done((res) => { + _initGroupSummaryStore: function(groupId) { + this._groupSummaryStore = new GroupSummaryStore( + MatrixClientPeg.get(), 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, @@ -494,7 +518,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, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index f77b26fff1..9dd479c789 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)s' could not be removed from the summary.": "The room '%(roomName)s' 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..170a1ec11e --- /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'; + +/** + * Stores the group summary for a room and provides an API to change it + */ +export default class GroupSummaryStore extends EventEmitter { + constructor(matrixClient, groupId) { + super(); + this._groupId = groupId; + this._matrixClient = matrixClient; + this._summary = {}; + this._fetchSummary(); + } + + _fetchSummary() { + this._matrixClient.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 this._matrixClient + .addRoomToGroupSummary(this._groupId, roomId, categoryId) + .then(this._fetchSummary.bind(this)); + } + + addUserToGroupSummary(userId, roleId) { + return this._matrixClient + .addUserToGroupSummary(this._groupId, userId, roleId) + .then(this._fetchSummary.bind(this)); + } + + removeRoomFromGroupSummary(roomId) { + return this._matrixClient + .removeRoomFromGroupSummary(this._groupId, roomId) + .then(this._fetchSummary.bind(this)); + } + + removeUserFromGroupSummary(userId) { + return this._matrixClient + .removeUserFromGroupSummary(this._groupId, userId) + .then(this._fetchSummary.bind(this)); + } +}