Merge pull request #1196 from matrix-org/dbkr/groups_better_groupview
Add more features to Group View
This commit is contained in:
commit
af3b6484cd
4 changed files with 259 additions and 9 deletions
|
@ -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 <FeaturedRoom key={r.room_id} summaryInfo={r} />;
|
||||
});
|
||||
let catHeader = null;
|
||||
if (this.props.category && this.props.category.profile) {
|
||||
catHeader = <div className="mx_GroupView_featuredThings_category">{this.props.category.profile.name}</div>;
|
||||
}
|
||||
return <div>
|
||||
{catHeader}
|
||||
{roomNodes}
|
||||
</div>;
|
||||
},
|
||||
});
|
||||
|
||||
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 = <a href={permalink} onClick={this.onClick} >{this.props.summaryInfo.profile.name}</a>;
|
||||
} else {
|
||||
roomNameNode = <span>{this.props.summaryInfo.profile.name}</span>;
|
||||
}
|
||||
|
||||
return <AccessibleButton className="mx_GroupView_featuredThing" onClick={this.onClick}>
|
||||
<RoomAvatar oobData={oobData} width={64} height={64} />
|
||||
<div className="mx_GroupView_featuredThing_name">{roomNameNode}</div>
|
||||
</AccessibleButton>;
|
||||
},
|
||||
});
|
||||
|
||||
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 <FeaturedUser key={u.user_id} summaryInfo={u} />;
|
||||
});
|
||||
let roleHeader = null;
|
||||
if (this.props.role && this.props.role.profile) {
|
||||
roleHeader = <div className="mx_GroupView_featuredThings_category">{this.props.role.profile.name}</div>;
|
||||
}
|
||||
return <div>
|
||||
{roleHeader}
|
||||
{userNodes}
|
||||
</div>;
|
||||
},
|
||||
});
|
||||
|
||||
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 = <a href={permalink} onClick={this.onClick} >{this.props.summaryInfo.user_id}</a>;
|
||||
|
||||
return <AccessibleButton className="mx_GroupView_featuredThing" onClick={this.onClick}>
|
||||
<div className="mx_GroupView_featuredThing_name">{userNameNode}</div>
|
||||
</AccessibleButton>;
|
||||
},
|
||||
});
|
||||
|
||||
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 = <CategoryRoomList rooms={defaultCategoryRooms} />;
|
||||
}
|
||||
const categoryRoomNodes = Object.keys(categoryRooms).map((catId) => {
|
||||
const cat = summary.rooms_section.categories[catId];
|
||||
return <CategoryRoomList key={catId} rooms={categoryRooms[catId]} category={cat} />;
|
||||
});
|
||||
|
||||
return <div className="mx_GroupView_featuredThings">
|
||||
<div className="mx_GroupView_featuredThings_header">
|
||||
{_t('Featured Rooms:')}
|
||||
</div>
|
||||
{defaultCategoryNode}
|
||||
{categoryRoomNodes}
|
||||
</div>;
|
||||
},
|
||||
|
||||
_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 = <RoleUserList users={noRoleUsers} />;
|
||||
}
|
||||
const roleUserNodes = Object.keys(roleUsers).map((roleId) => {
|
||||
const role = summary.users_section.roles[roleId];
|
||||
return <RoleUserList key={roleId} users={roleUsers[roleId]} role={role} />;
|
||||
});
|
||||
|
||||
return <div className="mx_GroupView_featuredThings">
|
||||
<div className="mx_GroupView_featuredThings_header">
|
||||
{_t('Featured Users:')}
|
||||
</div>
|
||||
{noRoleNode}
|
||||
{roleUserNodes}
|
||||
</div>;
|
||||
},
|
||||
|
||||
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 <Loader />;
|
||||
} else if (this.state.editing) {
|
||||
return <div />;
|
||||
} 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 = <div>
|
||||
<div className="mx_GroupView_groupDesc">{description}</div>
|
||||
{this._getFeaturedRoomsNode()}
|
||||
{this._getFeaturedUsersNode()}
|
||||
</div>;
|
||||
|
||||
let nameNode;
|
||||
if (summary.profile && summary.profile.name) {
|
||||
nameNode = <div className="mx_RoomHeader_name">
|
||||
|
@ -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 (
|
||||
<div className="mx_GroupView">
|
||||
<div className="mx_RoomHeader">
|
||||
|
@ -111,9 +347,12 @@ export default React.createClass({
|
|||
{summary.profile.short_description}
|
||||
</div>
|
||||
</div>
|
||||
<AccessibleButton className="mx_RoomHeader_button" onClick={this._onSettingsClick} title={_t("Settings")} style={{display: 'none'}}>
|
||||
<TintableSvg src="img/icons-settings-room.svg" width="16" height="16"/>
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
</div>
|
||||
{description}
|
||||
{roomBody}
|
||||
</div>
|
||||
);
|
||||
} else if (this.state.error) {
|
||||
|
|
|
@ -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' });
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 <i>+example:matrix.org</i>.": "To join an exisitng group you'll have to know its group identifier; this will look something like <i>+example:matrix.org</i>.",
|
||||
"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:"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue