diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 3f321d453d..30d67202e7 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -18,9 +18,154 @@ import React from 'react'; import PropTypes from 'prop-types'; import MatrixClientPeg from '../../MatrixClientPeg'; import sdk from '../../index'; +import dis from '../../dispatcher'; import { sanitizedHtmlNode } from '../../HtmlUtils'; import { _t } from '../../languageHandler'; +import AccessibleButton from '../views/elements/AccessibleButton'; +const RoomSummaryType = PropTypes.shape({ + room_id: PropTypes.string.isRequired, + profile: PropTypes.shape({ + name: PropTypes.string, + avatar_url: PropTypes.string, + canonical_alias: PropTypes.string, + }).isRequired, +}); + +const UserSummaryType = PropTypes.shape({ + summaryInfo: PropTypes.shape({ + user_id: PropTypes.string.isRequired, + }).isRequired, +}); + +const CategoryRoomList = React.createClass({ + displayName: 'CategoryRoomList', + + props: { + rooms: PropTypes.arrayOf(RoomSummaryType).isRequired, + category: PropTypes.shape({ + profile: PropTypes.shape({ + name: PropTypes.string, + }).isRequired, + }), + }, + + render: function() { + const roomNodes = this.props.rooms.map((r) => { + return ; + }); + let catHeader = null; + if (this.props.category && this.props.category.profile) { + catHeader =
{this.props.category.profile.name}
; + } + return
+ {catHeader} + {roomNodes} +
; + }, +}); + +const FeaturedRoom = React.createClass({ + displayName: 'FeaturedRoom', + + props: { + summaryInfo: RoomSummaryType.isRequired, + }, + + onClick: function(e) { + e.preventDefault(); + e.stopPropagation(); + + dis.dispatch({ + action: 'view_room', + room_alias: this.props.summaryInfo.profile.canonical_alias, + room_id: this.props.summaryInfo.room_id, + }); + }, + + render: function() { + const RoomAvatar = sdk.getComponent("avatars.RoomAvatar"); + + const oobData = { + roomId: this.props.summaryInfo.room_id, + avatarUrl: this.props.summaryInfo.profile.avatar_url, + name: this.props.summaryInfo.profile.name, + }; + let permalink = null; + if (this.props.summaryInfo.profile && this.props.summaryInfo.profile.canonical_alias) { + permalink = 'https://matrix.to/#/' + this.props.summaryInfo.profile.canonical_alias; + } + let roomNameNode = null; + if (permalink) { + roomNameNode = {this.props.summaryInfo.profile.name}; + } else { + roomNameNode = {this.props.summaryInfo.profile.name}; + } + + return + +
{roomNameNode}
+
; + }, +}); + +const RoleUserList = React.createClass({ + displayName: 'RoleUserList', + + props: { + users: PropTypes.arrayOf(UserSummaryType).isRequired, + role: PropTypes.shape({ + profile: PropTypes.shape({ + name: PropTypes.string, + }).isRequired, + }), + }, + + render: function() { + const userNodes = this.props.users.map((u) => { + return ; + }); + let roleHeader = null; + if (this.props.role && this.props.role.profile) { + roleHeader =
{this.props.role.profile.name}
; + } + return
+ {roleHeader} + {userNodes} +
; + }, +}); + +const FeaturedUser = React.createClass({ + displayName: 'FeaturedUser', + + props: { + summaryInfo: UserSummaryType.isRequired, + }, + + onClick: function(e) { + e.preventDefault(); + e.stopPropagation(); + + dis.dispatch({ + action: 'view_start_chat_or_reuse', + user_id: this.props.summaryInfo.user_id, + go_home_on_cancel: false, + }); + }, + + render: function() { + // Add avatar once we get profile info inline in the summary response + //const BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); + + const permalink = 'https://matrix.to/#/' + this.props.summaryInfo.user_id; + const userNameNode = {this.props.summaryInfo.user_id}; + + return +
{userNameNode}
+
; + }, +}); export default React.createClass({ displayName: 'GroupView', @@ -33,6 +178,7 @@ export default React.createClass({ return { summary: null, error: null, + editing: false, }; }, @@ -65,12 +211,95 @@ export default React.createClass({ }); }, + _onSettingsClick: function() { + this.setState({editing: true}); + }, + + _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) => { + if (r.category_id === null) { + defaultCategoryRooms.push(r); + } else { + let list = categoryRooms[r.category_id]; + if (list === undefined) { + list = []; + categoryRooms[r.category_id] = list; + } + list.push(r); + } + }); + + let defaultCategoryNode = null; + if (defaultCategoryRooms.length > 0) { + defaultCategoryNode = ; + } + const categoryRoomNodes = Object.keys(categoryRooms).map((catId) => { + const cat = summary.rooms_section.categories[catId]; + return ; + }); + + return
+
+ {_t('Featured Rooms:')} +
+ {defaultCategoryNode} + {categoryRoomNodes} +
; + }, + + _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) => { + if (u.role_id === null) { + noRoleUsers.push(u); + } else { + let list = roleUsers[u.role_id]; + if (list === undefined) { + list = []; + roleUsers[u.role_id] = list; + } + list.push(u); + } + }); + + let noRoleNode = null; + if (noRoleUsers.length > 0) { + noRoleNode = ; + } + const roleUserNodes = Object.keys(roleUsers).map((roleId) => { + const role = summary.users_section.roles[roleId]; + return ; + }); + + return
+
+ {_t('Featured Users:')} +
+ {noRoleNode} + {roleUserNodes} +
; + }, + render: function() { const GroupAvatar = sdk.getComponent("avatars.GroupAvatar"); const Loader = sdk.getComponent("elements.Spinner"); + const TintableSvg = sdk.getComponent("elements.TintableSvg"); if (this.state.summary === null && this.state.error === null) { return ; + } else if (this.state.editing) { + return
; } else if (this.state.summary) { const summary = this.state.summary; let description = null; @@ -78,6 +307,12 @@ export default React.createClass({ description = sanitizedHtmlNode(summary.profile.long_description); } + const roomBody =
+
{description}
+ {this._getFeaturedRoomsNode()} + {this._getFeaturedUsersNode()} +
; + let nameNode; if (summary.profile && summary.profile.name) { nameNode =
@@ -94,6 +329,7 @@ export default React.createClass({ const groupAvatarUrl = summary.profile ? summary.profile.avatar_url : null; + // settings button is display: none until settings is wired up return (
@@ -111,9 +347,12 @@ export default React.createClass({ {summary.profile.short_description}
+ + +
- {description} + {roomBody} ); } else if (this.state.error) { diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index f0337fdd8e..75a15d71ee 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -506,7 +506,7 @@ module.exports = React.createClass({ this._setMxId(payload); break; case 'view_start_chat_or_reuse': - this._chatCreateOrReuse(payload.user_id); + this._chatCreateOrReuse(payload.user_id, payload.go_home_on_cancel); break; case 'view_create_chat': this._createChat(); @@ -801,7 +801,9 @@ module.exports = React.createClass({ }); }, - _chatCreateOrReuse: function(userId) { + _chatCreateOrReuse: function(userId, goHomeOnCancel) { + if (goHomeOnCancel === undefined) goHomeOnCancel = true; + const ChatCreateOrReuseDialog = sdk.getComponent( 'views.dialogs.ChatCreateOrReuseDialog', ); @@ -832,7 +834,7 @@ module.exports = React.createClass({ const close = Modal.createDialog(ChatCreateOrReuseDialog, { userId: userId, onFinished: (success) => { - if (!success) { + if (!success && goHomeOnCancel) { // Dialog cancelled, default to home dis.dispatch({ action: 'view_home_page' }); } diff --git a/src/components/views/avatars/RoomAvatar.js b/src/components/views/avatars/RoomAvatar.js index 8041fd5cd7..a18a52b3c0 100644 --- a/src/components/views/avatars/RoomAvatar.js +++ b/src/components/views/avatars/RoomAvatar.js @@ -72,7 +72,7 @@ module.exports = React.createClass({ }, getRoomAvatarUrl: function(props) { - if (!this.props.room) return null; + if (!props.room) return null; return props.room.getAvatarUrl( MatrixClientPeg.get().getHomeserverUrl(), @@ -84,7 +84,7 @@ module.exports = React.createClass({ }, getOneToOneAvatar: function(props) { - if (!this.props.room) return null; + if (!props.room) return null; var mlist = props.room.currentState.members; var userIds = []; @@ -126,9 +126,16 @@ module.exports = React.createClass({ }, getFallbackAvatar: function(props) { - if (!this.props.room) return null; + let roomId = null; + if (props.oobData && props.oobData.roomId) { + roomId = this.props.oobData.roomId; + } else if (props.room) { + roomId = props.room.roomId; + } else { + return null; + } - return Avatar.defaultAvatarUrlForString(props.room.roomId); + return Avatar.defaultAvatarUrlForString(roomId); }, render: function() { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d68d517302..812059ed1f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -954,5 +954,7 @@ "Create a group to represent your community! Define a set of rooms and your own custom homepage to mark out your space in the Matrix universe.": "Create a group to represent your community! Define a set of rooms and your own custom homepage to mark out your space in the Matrix universe.", "Join an existing group": "Join an existing group", "To join an exisitng group you'll have to know its group identifier; this will look something like +example:matrix.org.": "To join an exisitng group you'll have to know its group identifier; this will look something like +example:matrix.org.", - "Error whilst fetching joined groups": "Error whilst fetching joined groups" + "Featured Rooms:": "Featured Rooms:", + "Error whilst fetching joined groups": "Error whilst fetching joined groups", + "Featured Users:": "Featured Users:" }