mirror of
https://github.com/element-hq/element-web
synced 2024-11-25 10:45:51 +03:00
Implement simple GroupRoomInfo
which replaces the "X" on the GroupRoomTile with "Remove from community" under Admin Tools.
This commit is contained in:
parent
0dcd52d88f
commit
64a369216a
3 changed files with 178 additions and 71 deletions
170
src/components/views/groups/GroupRoomInfo.js
Normal file
170
src/components/views/groups/GroupRoomInfo.js
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
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 PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { MatrixClient } from 'matrix-js-sdk';
|
||||||
|
import dis from '../../../dispatcher';
|
||||||
|
import Modal from '../../../Modal';
|
||||||
|
import sdk from '../../../index';
|
||||||
|
import { _t } from '../../../languageHandler';
|
||||||
|
import { GroupRoomType } from '../../../groups';
|
||||||
|
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
||||||
|
import GeminiScrollbar from 'react-gemini-scrollbar';
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: 'GroupRoomInfo',
|
||||||
|
|
||||||
|
contextTypes: {
|
||||||
|
matrixClient: PropTypes.instanceOf(MatrixClient),
|
||||||
|
},
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
groupId: PropTypes.string,
|
||||||
|
groupRoom: GroupRoomType,
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
removingRoom: false,
|
||||||
|
isUserPrivilegedInGroup: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillMount: function() {
|
||||||
|
this._initGroupStore(this.props.groupId);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps(newProps) {
|
||||||
|
if (newProps.groupId !== this.props.groupId) {
|
||||||
|
this._unregisterGroupStore();
|
||||||
|
this._initGroupStore(newProps.groupId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_initGroupStore(groupId) {
|
||||||
|
this._groupStore = GroupStoreCache.getGroupStore(
|
||||||
|
this.context.matrixClient, this.props.groupId,
|
||||||
|
);
|
||||||
|
this._groupStore.registerListener(this.onGroupStoreUpdated);
|
||||||
|
},
|
||||||
|
|
||||||
|
_unregisterGroupStore() {
|
||||||
|
if (this._groupStore) {
|
||||||
|
this._groupStore.unregisterListener(this.onGroupStoreUpdated);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onGroupStoreUpdated: function() {
|
||||||
|
this.setState({
|
||||||
|
isUserPrivilegedInGroup: this._groupStore.isUserPrivileged(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_onRemove: function(e) {
|
||||||
|
const groupId = this.props.groupId;
|
||||||
|
const roomName = this.props.groupRoom.displayname;
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||||
|
Modal.createTrackedDialog('Confirm removal of group from room', '', QuestionDialog, {
|
||||||
|
title: _t("Are you sure you want to remove '%(roomName)s' from %(groupId)s?", {roomName, groupId}),
|
||||||
|
description: _t("Removing a room from the community will also remove it from the community page."),
|
||||||
|
button: _t("Remove"),
|
||||||
|
onFinished: (proceed) => {
|
||||||
|
if (!proceed) return;
|
||||||
|
this.setState({removingRoom: true});
|
||||||
|
const groupId = this.props.groupId;
|
||||||
|
const roomId = this.props.groupRoom.roomId;
|
||||||
|
this._groupStore.removeRoomFromGroup(roomId).then(() => {
|
||||||
|
dis.dispatch({
|
||||||
|
action: "view_group_room_list",
|
||||||
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error(`Error whilst removing ${roomId} from ${groupId}`, err);
|
||||||
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
Modal.createTrackedDialog('Failed to remove room from group', '', ErrorDialog, {
|
||||||
|
title: _t("Failed to remove room from community"),
|
||||||
|
description: _t(
|
||||||
|
"Failed to remove '%(roomName)s' from %(groupId)s", {groupId, roomName},
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}).finally(() => {
|
||||||
|
this.setState({removingRoom: false});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCancel: function(e) {
|
||||||
|
dis.dispatch({
|
||||||
|
action: "view_group_room_list",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||||
|
const EmojiText = sdk.getComponent('elements.EmojiText');
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
if (this.state.removingRoom) {
|
||||||
|
const Spinner = sdk.getComponent("elements.Spinner");
|
||||||
|
return <Spinner />;
|
||||||
|
}
|
||||||
|
|
||||||
|
let adminTools;
|
||||||
|
if (this.state.isUserPrivilegedInGroup) {
|
||||||
|
adminTools =
|
||||||
|
<div className="mx_MemberInfo_adminTools">
|
||||||
|
<h3>{ _t("Admin Tools") }</h3>
|
||||||
|
<div className="mx_MemberInfo_buttons">
|
||||||
|
<AccessibleButton className="mx_MemberInfo_field" onClick={this._onRemove}>
|
||||||
|
{ _t('Remove from community') }
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const avatarUrl = this.context.matrixClient.mxcUrlToHttp(
|
||||||
|
this.props.groupRoom.avatarUrl,
|
||||||
|
36, 36, 'crop',
|
||||||
|
);
|
||||||
|
|
||||||
|
const groupRoomName = this.props.groupRoom.displayname;
|
||||||
|
const avatar = <BaseAvatar name={groupRoomName} width={36} height={36} url={avatarUrl} />;
|
||||||
|
return (
|
||||||
|
<div className="mx_MemberInfo">
|
||||||
|
<GeminiScrollbar autoshow={true}>
|
||||||
|
<AccessibleButton className="mx_MemberInfo_cancel"onClick={this._onCancel}>
|
||||||
|
<img src="img/cancel.svg" width="18" height="18" className="mx_filterFlipColor" />
|
||||||
|
</AccessibleButton>
|
||||||
|
<div className="mx_MemberInfo_avatar">
|
||||||
|
{ avatar }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<EmojiText element="h2">{ groupRoomName }</EmojiText>
|
||||||
|
|
||||||
|
<div className="mx_MemberInfo_profile">
|
||||||
|
<div className="mx_MemberInfo_profileField">
|
||||||
|
{ this.props.groupRoom.canonical_alias }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{ adminTools }
|
||||||
|
</GeminiScrollbar>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
|
@ -16,13 +16,10 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {MatrixClient} from 'matrix-js-sdk';
|
import {MatrixClient} from 'matrix-js-sdk';
|
||||||
import { _t } from '../../../languageHandler';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import dis from '../../../dispatcher';
|
import dis from '../../../dispatcher';
|
||||||
import { GroupRoomType } from '../../../groups';
|
import { GroupRoomType } from '../../../groups';
|
||||||
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
|
||||||
import Modal from '../../../Modal';
|
|
||||||
|
|
||||||
const GroupRoomTile = React.createClass({
|
const GroupRoomTile = React.createClass({
|
||||||
displayName: 'GroupRoomTile',
|
displayName: 'GroupRoomTile',
|
||||||
|
@ -32,68 +29,11 @@ const GroupRoomTile = React.createClass({
|
||||||
groupRoom: GroupRoomType.isRequired,
|
groupRoom: GroupRoomType.isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
|
||||||
return {
|
|
||||||
name: this.calculateRoomName(this.props.groupRoom),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillReceiveProps: function(newProps) {
|
|
||||||
this.setState({
|
|
||||||
name: this.calculateRoomName(newProps.groupRoom),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
calculateRoomName: function(groupRoom) {
|
|
||||||
return groupRoom.name || groupRoom.canonicalAlias || _t("Unnamed Room");
|
|
||||||
},
|
|
||||||
|
|
||||||
removeRoomFromGroup: function() {
|
|
||||||
const groupId = this.props.groupId;
|
|
||||||
const groupStore = GroupStoreCache.getGroupStore(this.context.matrixClient, groupId);
|
|
||||||
const roomName = this.state.name;
|
|
||||||
const roomId = this.props.groupRoom.roomId;
|
|
||||||
groupStore.removeRoomFromGroup(roomId)
|
|
||||||
.catch((err) => {
|
|
||||||
console.error(`Error whilst removing ${roomId} from ${groupId}`, err);
|
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
Modal.createTrackedDialog('Failed to remove room from group', '', ErrorDialog, {
|
|
||||||
title: _t("Failed to remove room from community"),
|
|
||||||
description: _t("Failed to remove '%(roomName)s' from %(groupId)s", {groupId, roomName}),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function(e) {
|
onClick: function(e) {
|
||||||
let roomId;
|
|
||||||
let roomAlias;
|
|
||||||
if (this.props.groupRoom.canonicalAlias) {
|
|
||||||
roomAlias = this.props.groupRoom.canonicalAlias;
|
|
||||||
} else {
|
|
||||||
roomId = this.props.groupRoom.roomId;
|
|
||||||
}
|
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_room',
|
action: 'view_group_room',
|
||||||
room_id: roomId,
|
groupId: this.props.groupId,
|
||||||
room_alias: roomAlias,
|
groupRoom: this.props.groupRoom,
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onDeleteClick: function(e) {
|
|
||||||
const groupId = this.props.groupId;
|
|
||||||
const roomName = this.state.name;
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
|
||||||
Modal.createTrackedDialog('Confirm removal of group from room', '', QuestionDialog, {
|
|
||||||
title: _t("Are you sure you want to remove '%(roomName)s' from %(groupId)s?", {roomName, groupId}),
|
|
||||||
description: _t("Removing a room from the community will also remove it from the community page."),
|
|
||||||
button: _t("Remove"),
|
|
||||||
onFinished: (success) => {
|
|
||||||
if (success) {
|
|
||||||
this.removeRoomFromGroup();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -106,7 +46,7 @@ const GroupRoomTile = React.createClass({
|
||||||
);
|
);
|
||||||
|
|
||||||
const av = (
|
const av = (
|
||||||
<BaseAvatar name={this.state.name}
|
<BaseAvatar name={this.props.groupRoom.displayname}
|
||||||
width={36} height={36}
|
width={36} height={36}
|
||||||
url={avatarUrl}
|
url={avatarUrl}
|
||||||
/>
|
/>
|
||||||
|
@ -118,14 +58,8 @@ const GroupRoomTile = React.createClass({
|
||||||
{ av }
|
{ av }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_GroupRoomTile_name">
|
<div className="mx_GroupRoomTile_name">
|
||||||
{ this.state.name }
|
{ this.props.groupRoom.displayname }
|
||||||
</div>
|
</div>
|
||||||
<AccessibleButton className="mx_GroupRoomTile_delete"
|
|
||||||
onClick={this.onDeleteClick}
|
|
||||||
tooltip={_t("Remove this room from the community")}
|
|
||||||
>
|
|
||||||
<img src="img/cancel.svg" width="15" height="15" className="mx_filterFlipColor" />
|
|
||||||
</AccessibleButton>
|
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { _t } from './languageHandler.js';
|
||||||
|
|
||||||
export const GroupMemberType = PropTypes.shape({
|
export const GroupMemberType = PropTypes.shape({
|
||||||
userId: PropTypes.string.isRequired,
|
userId: PropTypes.string.isRequired,
|
||||||
|
@ -23,6 +24,7 @@ export const GroupMemberType = PropTypes.shape({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GroupRoomType = PropTypes.shape({
|
export const GroupRoomType = PropTypes.shape({
|
||||||
|
displayname: PropTypes.string,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
roomId: PropTypes.string.isRequired,
|
roomId: PropTypes.string.isRequired,
|
||||||
canonicalAlias: PropTypes.string,
|
canonicalAlias: PropTypes.string,
|
||||||
|
@ -39,6 +41,7 @@ export function groupMemberFromApiObject(apiObject) {
|
||||||
|
|
||||||
export function groupRoomFromApiObject(apiObject) {
|
export function groupRoomFromApiObject(apiObject) {
|
||||||
return {
|
return {
|
||||||
|
displayname: apiObject.name || apiObject.canonical_alias || _t("Unnamed Room"),
|
||||||
name: apiObject.name,
|
name: apiObject.name,
|
||||||
roomId: apiObject.room_id,
|
roomId: apiObject.room_id,
|
||||||
canonicalAlias: apiObject.canonical_alias,
|
canonicalAlias: apiObject.canonical_alias,
|
||||||
|
|
Loading…
Reference in a new issue