Add confirmation dialog to kick/ban buttons

Add a specific dialog used for confirming member actions.

Also remove onFinished from MemberInfo which did absolutely
nothing.
This commit is contained in:
David Baker 2017-02-14 13:40:19 +00:00
parent 17b08aedfc
commit 8001c0b16b
3 changed files with 145 additions and 64 deletions

View file

@ -77,6 +77,8 @@ import views$dialogs$BaseDialog from './components/views/dialogs/BaseDialog';
views$dialogs$BaseDialog && (module.exports.components['views.dialogs.BaseDialog'] = views$dialogs$BaseDialog); views$dialogs$BaseDialog && (module.exports.components['views.dialogs.BaseDialog'] = views$dialogs$BaseDialog);
import views$dialogs$ChatInviteDialog from './components/views/dialogs/ChatInviteDialog'; import views$dialogs$ChatInviteDialog from './components/views/dialogs/ChatInviteDialog';
views$dialogs$ChatInviteDialog && (module.exports.components['views.dialogs.ChatInviteDialog'] = views$dialogs$ChatInviteDialog); views$dialogs$ChatInviteDialog && (module.exports.components['views.dialogs.ChatInviteDialog'] = views$dialogs$ChatInviteDialog);
import views$dialogs$ConfirmUserActionDialog from './components/views/dialogs/ConfirmUserActionDialog';
views$dialogs$ConfirmUserActionDialog && (module.exports.components['views.dialogs.ConfirmUserActionDialog'] = views$dialogs$ConfirmUserActionDialog);
import views$dialogs$DeactivateAccountDialog from './components/views/dialogs/DeactivateAccountDialog'; import views$dialogs$DeactivateAccountDialog from './components/views/dialogs/DeactivateAccountDialog';
views$dialogs$DeactivateAccountDialog && (module.exports.components['views.dialogs.DeactivateAccountDialog'] = views$dialogs$DeactivateAccountDialog); views$dialogs$DeactivateAccountDialog && (module.exports.components['views.dialogs.DeactivateAccountDialog'] = views$dialogs$DeactivateAccountDialog);
import views$dialogs$ErrorDialog from './components/views/dialogs/ErrorDialog'; import views$dialogs$ErrorDialog from './components/views/dialogs/ErrorDialog';

View file

@ -0,0 +1,83 @@
/*
Copyright 2017 Vector Creations 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 React from 'react';
import sdk from '../../../index';
import classnames from 'classnames';
/*
* A dialog for confirming an operation on another user.
* Takes a user ID and a verb, displays the target user prominently
* such that it should be easy to confirm that tne operation is being
* performed on the right person, and displays the operation prominently
* to make it obvious what is going to happen.
* Also tweaks the style for 'dangerous' actions (albeit only with colour)
*/
export default React.createClass({
displayName: 'ConfirmUserActionDialog',
propTypes: {
member: React.PropTypes.object.isRequired, // member object
action: React.PropTypes.string.isRequired, // eg. 'Ban'
danger: React.PropTypes.bool,
onFinished: React.PropTypes.func.isRequired,
},
defaultProps: {
danger: false,
},
onOk: function() {
this.props.onFinished(true);
},
onCancel: function() {
this.props.onFinished(false);
},
render: function() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const MemberAvatar = sdk.getComponent("views.avatars.MemberAvatar");
const title = this.props.action + " this person?";
const confirmButtonClass = classnames({
'mx_Dialog_primary': true,
'danger': this.props.danger,
});
return (
<BaseDialog className="mx_UserActionConfirmDialog" onFinished={this.props.onFinished}
onEnterPressed={ this.onOk }
title={title}
>
<div className="mx_Dialog_content">
<div className="mx_ConfirmUserActionDialog_avatar">
<MemberAvatar member={this.props.member} width={72} height={72} />
</div>
<div className="mx_ConfirmUserActionDialog_name">{this.props.member.name}</div>
<div className="mx_ConfirmUserActionDialog_userId">{this.props.member.userId}</div>
</div>
<div className="mx_Dialog_buttons">
<button className={confirmButtonClass} onClick={this.onOk} autoFocus={true}>
{this.props.action}
</button>
<button onClick={this.onCancel}>
Cancel
</button>
</div>
</BaseDialog>
);
},
});

View file

@ -25,16 +25,16 @@ limitations under the License.
* 'muted': boolean, * 'muted': boolean,
* 'isTargetMod': boolean * 'isTargetMod': boolean
*/ */
var React = require('react'); import React from 'react';
var classNames = require('classnames'); import classNames from 'classnames';
var dis = require("../../../dispatcher"); import dis from '../../../dispatcher';
var Modal = require("../../../Modal"); import Modal from '../../../Modal';
var sdk = require('../../../index'); import sdk from '../../../index';
var createRoom = require('../../../createRoom'); import createRoom from '../../../createRoom';
var DMRoomMap = require('../../../utils/DMRoomMap'); import DMRoomMap from '../../../utils/DMRoomMap';
var Unread = require('../../../Unread'); import Unread from '../../../Unread';
var Receipt = require('../../../utils/Receipt'); import Receipt from '../../../utils/Receipt';
var WithMatrixClient = require('../../../wrappers/WithMatrixClient'); import WithMatrixClient from '../../../wrappers/WithMatrixClient';
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
module.exports = WithMatrixClient(React.createClass({ module.exports = WithMatrixClient(React.createClass({
@ -43,13 +43,6 @@ module.exports = WithMatrixClient(React.createClass({
propTypes: { propTypes: {
matrixClient: React.PropTypes.object.isRequired, matrixClient: React.PropTypes.object.isRequired,
member: React.PropTypes.object.isRequired, member: React.PropTypes.object.isRequired,
onFinished: React.PropTypes.func,
},
getDefaultProps: function() {
return {
onFinished: function() {}
};
}, },
getInitialState: function() { getInitialState: function() {
@ -224,46 +217,64 @@ module.exports = WithMatrixClient(React.createClass({
}, },
onKick: function() { onKick: function() {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog");
var roomId = this.props.member.roomId; Modal.createDialog(ConfirmUserActionDialog, {
var target = this.props.member.userId; member: this.props.member,
this.setState({ updating: this.state.updating + 1 }); action: 'Kick',
this.props.matrixClient.kick(roomId, target).then(function() { danger: true,
// NO-OP; rely on the m.room.member event coming down else we could onFinished: (proceed) => {
// get out of sync if we force setState here! if (!proceed) return;
console.log("Kick success");
}, function(err) { this.setState({ updating: this.state.updating + 1 });
Modal.createDialog(ErrorDialog, { this.props.matrixClient.kick(
title: "Kick error", this.props.member.roomId, this.props.member.userId,
description: err.message ).then(function() {
// NO-OP; rely on the m.room.member event coming down else we could
// get out of sync if we force setState here!
console.log("Kick success");
}, function(err) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Kick error",
description: err.message
});
}
).finally(()=>{
this.setState({ updating: this.state.updating - 1 });
}); });
} }
).finally(()=>{
this.setState({ updating: this.state.updating - 1 });
}); });
this.props.onFinished();
}, },
onBan: function() { onBan: function() {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog");
var roomId = this.props.member.roomId; Modal.createDialog(ConfirmUserActionDialog, {
var target = this.props.member.userId; member: this.props.member,
this.setState({ updating: this.state.updating + 1 }); action: 'Ban',
this.props.matrixClient.ban(roomId, target).then( danger: true,
function() { onFinished: (proceed) => {
// NO-OP; rely on the m.room.member event coming down else we could if (!proceed) return;
// get out of sync if we force setState here!
console.log("Ban success"); this.setState({ updating: this.state.updating + 1 });
}, function(err) { this.props.matrixClient.ban(
Modal.createDialog(ErrorDialog, { this.props.member.roomId, this.props.member.userId,
title: "Ban error", ).then(
description: err.message function() {
// NO-OP; rely on the m.room.member event coming down else we could
// get out of sync if we force setState here!
console.log("Ban success");
}, function(err) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Ban error",
description: err.message,
});
}
).finally(()=>{
this.setState({ updating: this.state.updating - 1 });
}); });
} },
).finally(()=>{
this.setState({ updating: this.state.updating - 1 });
}); });
this.props.onFinished();
}, },
onMuteToggle: function() { onMuteToggle: function() {
@ -272,14 +283,12 @@ module.exports = WithMatrixClient(React.createClass({
var target = this.props.member.userId; var target = this.props.member.userId;
var room = this.props.matrixClient.getRoom(roomId); var room = this.props.matrixClient.getRoom(roomId);
if (!room) { if (!room) {
this.props.onFinished();
return; return;
} }
var powerLevelEvent = room.currentState.getStateEvents( var powerLevelEvent = room.currentState.getStateEvents(
"m.room.power_levels", "" "m.room.power_levels", ""
); );
if (!powerLevelEvent) { if (!powerLevelEvent) {
this.props.onFinished();
return; return;
} }
var isMuted = this.state.muted; var isMuted = this.state.muted;
@ -314,7 +323,6 @@ module.exports = WithMatrixClient(React.createClass({
this.setState({ updating: this.state.updating - 1 }); this.setState({ updating: this.state.updating - 1 });
}); });
} }
this.props.onFinished();
}, },
onModToggle: function() { onModToggle: function() {
@ -323,19 +331,16 @@ module.exports = WithMatrixClient(React.createClass({
var target = this.props.member.userId; var target = this.props.member.userId;
var room = this.props.matrixClient.getRoom(roomId); var room = this.props.matrixClient.getRoom(roomId);
if (!room) { if (!room) {
this.props.onFinished();
return; return;
} }
var powerLevelEvent = room.currentState.getStateEvents( var powerLevelEvent = room.currentState.getStateEvents(
"m.room.power_levels", "" "m.room.power_levels", ""
); );
if (!powerLevelEvent) { if (!powerLevelEvent) {
this.props.onFinished();
return; return;
} }
var me = room.getMember(this.props.matrixClient.credentials.userId); var me = room.getMember(this.props.matrixClient.credentials.userId);
if (!me) { if (!me) {
this.props.onFinished();
return; return;
} }
var defaultLevel = powerLevelEvent.getContent().users_default; var defaultLevel = powerLevelEvent.getContent().users_default;
@ -366,7 +371,6 @@ module.exports = WithMatrixClient(React.createClass({
).finally(()=>{ ).finally(()=>{
this.setState({ updating: this.state.updating - 1 }); this.setState({ updating: this.state.updating - 1 });
}); });
this.props.onFinished();
}, },
_applyPowerChange: function(roomId, target, powerLevel, powerLevelEvent) { _applyPowerChange: function(roomId, target, powerLevel, powerLevelEvent) {
@ -386,7 +390,6 @@ module.exports = WithMatrixClient(React.createClass({
).finally(()=>{ ).finally(()=>{
this.setState({ updating: this.state.updating - 1 }); this.setState({ updating: this.state.updating - 1 });
}).done(); }).done();
this.props.onFinished();
}, },
onPowerChange: function(powerLevel) { onPowerChange: function(powerLevel) {
@ -396,14 +399,12 @@ module.exports = WithMatrixClient(React.createClass({
var room = this.props.matrixClient.getRoom(roomId); var room = this.props.matrixClient.getRoom(roomId);
var self = this; var self = this;
if (!room) { if (!room) {
this.props.onFinished();
return; return;
} }
var powerLevelEvent = room.currentState.getStateEvents( var powerLevelEvent = room.currentState.getStateEvents(
"m.room.power_levels", "" "m.room.power_levels", ""
); );
if (!powerLevelEvent) { if (!powerLevelEvent) {
this.props.onFinished();
return; return;
} }
if (powerLevelEvent.getContent().users) { if (powerLevelEvent.getContent().users) {
@ -422,9 +423,6 @@ module.exports = WithMatrixClient(React.createClass({
if (confirmed) { if (confirmed) {
self._applyPowerChange(roomId, target, powerLevel, powerLevelEvent); self._applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
} }
else {
self.props.onFinished();
}
}, },
}); });
} }
@ -440,7 +438,6 @@ module.exports = WithMatrixClient(React.createClass({
onNewDMClick: function() { onNewDMClick: function() {
this.setState({ updating: this.state.updating + 1 }); this.setState({ updating: this.state.updating + 1 });
createRoom({dmUserId: this.props.member.userId}).finally(() => { createRoom({dmUserId: this.props.member.userId}).finally(() => {
this.props.onFinished();
this.setState({ updating: this.state.updating - 1 }); this.setState({ updating: this.state.updating - 1 });
}).done(); }).done();
}, },
@ -450,7 +447,6 @@ module.exports = WithMatrixClient(React.createClass({
action: 'leave_room', action: 'leave_room',
room_id: this.props.member.roomId, room_id: this.props.member.roomId,
}); });
this.props.onFinished();
}, },
_calculateOpsPermissions: function(member) { _calculateOpsPermissions: function(member) {