diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js
index 2c24c398e0..1b4b5cb809 100644
--- a/src/components/structures/GroupView.js
+++ b/src/components/structures/GroupView.js
@@ -17,6 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
+import Promise from 'bluebird';
import MatrixClientPeg from '../../MatrixClientPeg';
import sdk from '../../index';
import dis from '../../dispatcher';
@@ -38,6 +39,9 @@ const RoomSummaryType = PropTypes.shape({
const UserSummaryType = PropTypes.shape({
summaryInfo: PropTypes.shape({
user_id: PropTypes.string.isRequired,
+ role_id: PropTypes.string,
+ avatar_url: PropTypes.string,
+ displayname: PropTypes.string,
}).isRequired,
});
@@ -51,20 +55,32 @@ const CategoryRoomList = React.createClass({
name: PropTypes.string,
}).isRequired,
}),
+
+ // Whether the list should be editable
+ editing: PropTypes.bool.isRequired,
},
render: function() {
const roomNodes = this.props.rooms.map((r) => {
return ;
});
+
let catHeader = null;
if (this.props.category && this.props.category.profile) {
catHeader =
+ return
{catHeader}
{roomNodes}
;
+ // TODO: Modify UserPickerDialog to allow picking of rooms, and then use it here
+ // const TintableSvg = sdk.getComponent("elements.TintableSvg");
+ //
+ //
+ //
+ // {_t('Add a Room')}
+ //
+ //
},
});
@@ -122,9 +138,59 @@ const RoleUserList = React.createClass({
name: PropTypes.string,
}).isRequired,
}),
+ groupId: PropTypes.string.isRequired,
+
+ // Whether the list should be editable
+ editing: PropTypes.bool.isRequired,
+ },
+
+ onAddUsersClicked: function(ev) {
+ ev.preventDefault();
+ const UserPickerDialog = sdk.getComponent("dialogs.UserPickerDialog");
+ Modal.createTrackedDialog('Add Users to Group Summary', '', UserPickerDialog, {
+ title: _t('Add users to the group summary'),
+ description: _t("Who would you like to add to this summary?"),
+ placeholder: _t("Name or matrix ID"),
+ button: _t("Add to summary"),
+ validAddressTypes: ['mx'],
+ groupId: this.props.groupId,
+ onFinished: (success, addrs) => {
+ if (!success) return;
+ const errorList = [];
+ Promise.all(addrs.map((addr) => {
+ return MatrixClientPeg.get()
+ .addUserToGroupSummary(this.props.groupId, addr.address)
+ .catch(() => { errorList.push(addr.address); })
+ .reflect();
+ })).then(() => {
+ if (errorList.length === 0) {
+ return;
+ }
+ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+ Modal.createTrackedDialog(
+ 'Failed to add the following users to the group summary',
+ '', ErrorDialog,
+ {
+ title: _t(
+ "Failed to add the following users to the summary of %(groupId)s:",
+ {groupId: this.props.groupId},
+ ),
+ description: errorList.join(", "),
+ });
+ });
+ },
+ });
},
render: function() {
+ const TintableSvg = sdk.getComponent("elements.TintableSvg");
+ const addButton = this.props.editing ?
+ (
+
+
+ {_t('Add a User')}
+
+ ) : null;
const userNodes = this.props.users.map((u) => {
return
;
});
@@ -132,9 +198,10 @@ const RoleUserList = React.createClass({
if (this.props.role && this.props.role.profile) {
roleHeader =
{this.props.role.profile.name}
;
}
- return
+ return
{roleHeader}
{userNodes}
+ {addButton}
;
},
});
@@ -158,13 +225,16 @@ const FeaturedUser = React.createClass({
},
render: function() {
- // Add avatar once we get profile info inline in the summary response
- //const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
+ const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
+ const name = this.props.summaryInfo.displayname || this.props.summaryInfo.user_id;
const permalink = 'https://matrix.to/#/' + this.props.summaryInfo.user_id;
- const userNameNode =
{this.props.summaryInfo.user_id};
+ const userNameNode =
{name};
+ const httpUrl = MatrixClientPeg.get()
+ .mxcUrlToHttp(this.props.summaryInfo.avatar_url, 64, 64);
return
+
{userNameNode}
;
},
@@ -369,8 +439,6 @@ export default React.createClass({
_getFeaturedRoomsNode() {
const summary = this.state.summary;
- if (summary.rooms_section.rooms.length == 0) return null;
-
const defaultCategoryRooms = [];
const categoryRooms = {};
summary.rooms_section.rooms.forEach((r) => {
@@ -386,13 +454,16 @@ export default React.createClass({
}
});
- let defaultCategoryNode = null;
- if (defaultCategoryRooms.length > 0) {
- defaultCategoryNode =
;
- }
+ const defaultCategoryNode =
;
const categoryRoomNodes = Object.keys(categoryRooms).map((catId) => {
const cat = summary.rooms_section.categories[catId];
- return ;
+ return ;
});
return
@@ -407,8 +478,6 @@ export default React.createClass({
_getFeaturedUsersNode() {
const summary = this.state.summary;
- if (summary.users_section.users.length == 0) return null;
-
const noRoleUsers = [];
const roleUsers = {};
summary.users_section.users.forEach((u) => {
@@ -424,13 +493,18 @@ export default React.createClass({
}
});
- let noRoleNode = null;
- if (noRoleUsers.length > 0) {
- noRoleNode =
;
- }
+ const noRoleNode =
;
const roleUserNodes = Object.keys(roleUsers).map((roleId) => {
const role = summary.users_section.roles[roleId];
- return ;
+ return ;
});
return
@@ -561,6 +635,8 @@ export default React.createClass({
onChange={this._onLongDescChange}
tabIndex="3"
/>
+ {this._getFeaturedRoomsNode()}
+ {this._getFeaturedUsersNode()}
;
} else {
const groupAvatarUrl = summary.profile ? summary.profile.avatar_url : null;
diff --git a/src/components/views/dialogs/UserPickerDialog.js b/src/components/views/dialogs/UserPickerDialog.js
index b2fdd7035d..415a3d910e 100644
--- a/src/components/views/dialogs/UserPickerDialog.js
+++ b/src/components/views/dialogs/UserPickerDialog.js
@@ -40,6 +40,7 @@ module.exports = React.createClass({
focus: PropTypes.bool,
validAddressTypes: PropTypes.arrayOf(PropTypes.oneOf(addressTypes)),
onFinished: PropTypes.func.isRequired,
+ groupId: PropTypes.string,
},
getDefaultProps: function() {
@@ -140,7 +141,9 @@ module.exports = React.createClass({
// Only do search if there is something to search
if (query.length > 0 && query != '@' && query.length >= 2) {
this.queryChangedDebouncer = setTimeout(() => {
- if (this.state.serverSupportsUserDirectory) {
+ if (this.props.groupId) {
+ this._doNaiveGroupSearch(query);
+ } else if (this.state.serverSupportsUserDirectory) {
this._doUserDirectorySearch(query);
} else {
this._doLocalSearch(query);
@@ -185,6 +188,40 @@ module.exports = React.createClass({
if (this._cancelThreepidLookup) this._cancelThreepidLookup();
},
+ _doNaiveGroupSearch: function(query) {
+ const lowerCaseQuery = query.toLowerCase();
+ this.setState({
+ busy: true,
+ query,
+ searchError: null,
+ });
+ MatrixClientPeg.get().getGroupUsers(this.props.groupId).then((resp) => {
+ const results = [];
+ resp.chunk.forEach((u) => {
+ const userIdMatch = u.user_id.toLowerCase().includes(lowerCaseQuery);
+ const displayNameMatch = (u.displayname || '').toLowerCase().includes(lowerCaseQuery);
+ if (!(userIdMatch || displayNameMatch)) {
+ return;
+ }
+ results.push({
+ user_id: u.user_id,
+ avatar_url: u.avatar_url,
+ display_name: u.displayname,
+ });
+ });
+ this._processResults(results, query);
+ }).catch((err) => {
+ console.error('Error whilst searching group users: ', err);
+ this.setState({
+ searchError: err.errcode ? err.message : _t('Something went wrong!'),
+ });
+ }).done(() => {
+ this.setState({
+ busy: false,
+ });
+ });
+ },
+
_doUserDirectorySearch: function(query) {
this.setState({
busy: true,
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 464ab63683..d759547e66 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -886,5 +886,11 @@
"Leave %(groupName)s?": "Leave %(groupName)s?",
"%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s",
"Robot check is currently unavailable on desktop - please use a web browser": "Robot check is currently unavailable on desktop - please use a web browser",
- "Flair": "Flair"
+ "Flair": "Flair",
+ "Add a Room": "Add a Room",
+ "Add a User": "Add a User",
+ "Add users to the group summary": "Add users to the group summary",
+ "Who would you like to add to this summary?": "Who would you like to add to this summary?",
+ "Add to summary": "Add to summary",
+ "Failed to add the following users to the summary of %(groupId)s:": "Failed to add the following users to the summary of %(groupId)s:"
}