Merge pull request #1006 from matrix-org/luke/new-guest-access-user-action-chat
Implement /user/@userid:domain?action=chatpull/21833/head
commit
953a573f81
|
@ -378,6 +378,11 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
this.notifyNewScreen('forgot_password');
|
this.notifyNewScreen('forgot_password');
|
||||||
break;
|
break;
|
||||||
|
case 'start_chat':
|
||||||
|
createRoom({
|
||||||
|
dmUserId: payload.user_id,
|
||||||
|
});
|
||||||
|
break;
|
||||||
case 'leave_room':
|
case 'leave_room':
|
||||||
this._leaveRoom(payload.room_id);
|
this._leaveRoom(payload.room_id);
|
||||||
break;
|
break;
|
||||||
|
@ -474,6 +479,9 @@ module.exports = React.createClass({
|
||||||
case 'view_set_mxid':
|
case 'view_set_mxid':
|
||||||
this._setMxId();
|
this._setMxId();
|
||||||
break;
|
break;
|
||||||
|
case 'view_start_chat_or_reuse':
|
||||||
|
this._chatCreateOrReuse(payload.user_id);
|
||||||
|
break;
|
||||||
case 'view_create_chat':
|
case 'view_create_chat':
|
||||||
this._createChat();
|
this._createChat();
|
||||||
break;
|
break;
|
||||||
|
@ -707,6 +715,51 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_chatCreateOrReuse: function(userId) {
|
||||||
|
const ChatCreateOrReuseDialog = sdk.getComponent(
|
||||||
|
'views.dialogs.ChatCreateOrReuseDialog',
|
||||||
|
);
|
||||||
|
// Use a deferred action to reshow the dialog once the user has registered
|
||||||
|
if (MatrixClientPeg.get().isGuest()) {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'do_after_sync_prepared',
|
||||||
|
deferred_action: {
|
||||||
|
action: 'view_start_chat_or_reuse',
|
||||||
|
user_id: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_set_mxid',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const close = Modal.createDialog(ChatCreateOrReuseDialog, {
|
||||||
|
userId: userId,
|
||||||
|
onFinished: (success) => {
|
||||||
|
if (!success) {
|
||||||
|
// Dialog cancelled, default to home
|
||||||
|
dis.dispatch({ action: 'view_home_page' });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onNewDMClick: () => {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'start_chat',
|
||||||
|
user_id: userId,
|
||||||
|
});
|
||||||
|
// Close the dialog, indicate success (calls onFinished(true))
|
||||||
|
close(true);
|
||||||
|
},
|
||||||
|
onExistingRoomSelected: (roomId) => {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
room_id: roomId,
|
||||||
|
});
|
||||||
|
close(true);
|
||||||
|
},
|
||||||
|
}).close;
|
||||||
|
},
|
||||||
|
|
||||||
_invite: function(roomId) {
|
_invite: function(roomId) {
|
||||||
const ChatInviteDialog = sdk.getComponent("dialogs.ChatInviteDialog");
|
const ChatInviteDialog = sdk.getComponent("dialogs.ChatInviteDialog");
|
||||||
Modal.createDialog(ChatInviteDialog, {
|
Modal.createDialog(ChatInviteDialog, {
|
||||||
|
@ -1043,6 +1096,12 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
} else if (screen.indexOf('user/') == 0) {
|
} else if (screen.indexOf('user/') == 0) {
|
||||||
const userId = screen.substring(5);
|
const userId = screen.substring(5);
|
||||||
|
|
||||||
|
if (params.action === 'chat') {
|
||||||
|
this._chatCreateOrReuse(userId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({ viewUserId: userId });
|
this.setState({ viewUserId: userId });
|
||||||
this._setPage(PageTypes.UserView);
|
this._setPage(PageTypes.UserView);
|
||||||
this.notifyNewScreen('user/' + userId);
|
this.notifyNewScreen('user/' + userId);
|
||||||
|
|
|
@ -32,6 +32,7 @@ module.exports = React.createClass({
|
||||||
urls: React.PropTypes.array, // [highest_priority, ... , lowest_priority]
|
urls: React.PropTypes.array, // [highest_priority, ... , lowest_priority]
|
||||||
width: React.PropTypes.number,
|
width: React.PropTypes.number,
|
||||||
height: React.PropTypes.number,
|
height: React.PropTypes.number,
|
||||||
|
// XXX resizeMethod not actually used.
|
||||||
resizeMethod: React.PropTypes.string,
|
resizeMethod: React.PropTypes.string,
|
||||||
defaultToInitialLetter: React.PropTypes.bool // true to add default url
|
defaultToInitialLetter: React.PropTypes.bool // true to add default url
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,34 +18,31 @@ import React from 'react';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import dis from '../../../dispatcher';
|
import dis from '../../../dispatcher';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
|
import { _t } from '../../../languageHandler';
|
||||||
import DMRoomMap from '../../../utils/DMRoomMap';
|
import DMRoomMap from '../../../utils/DMRoomMap';
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
import Unread from '../../../Unread';
|
import Unread from '../../../Unread';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import createRoom from '../../../createRoom';
|
import createRoom from '../../../createRoom';
|
||||||
|
import { RoomMember } from "matrix-js-sdk";
|
||||||
|
|
||||||
export default class ChatCreateOrReuseDialog extends React.Component {
|
export default class ChatCreateOrReuseDialog extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.onNewDMClick = this.onNewDMClick.bind(this);
|
|
||||||
this.onRoomTileClick = this.onRoomTileClick.bind(this);
|
this.onRoomTileClick = this.onRoomTileClick.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
tiles: [],
|
||||||
|
profile: {
|
||||||
|
displayName: null,
|
||||||
|
avatarUrl: null,
|
||||||
|
},
|
||||||
|
profileError: null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewDMClick() {
|
componentWillMount() {
|
||||||
createRoom({dmUserId: this.props.userId});
|
|
||||||
this.props.onFinished(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
onRoomTileClick(roomId) {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'view_room',
|
|
||||||
room_id: roomId,
|
|
||||||
});
|
|
||||||
this.props.onFinished(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
|
||||||
const dmRoomMap = new DMRoomMap(client);
|
const dmRoomMap = new DMRoomMap(client);
|
||||||
|
@ -70,40 +67,123 @@ export default class ChatCreateOrReuseDialog extends React.Component {
|
||||||
highlight={highlight}
|
highlight={highlight}
|
||||||
isInvite={me.membership == "invite"}
|
isInvite={me.membership == "invite"}
|
||||||
onClick={this.onRoomTileClick}
|
onClick={this.onRoomTileClick}
|
||||||
/>
|
/>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const labelClasses = classNames({
|
this.setState({
|
||||||
mx_MemberInfo_createRoom_label: true,
|
tiles: tiles,
|
||||||
mx_RoomTile_name: true,
|
|
||||||
});
|
});
|
||||||
const startNewChat = <AccessibleButton
|
|
||||||
className="mx_MemberInfo_createRoom"
|
if (tiles.length === 0) {
|
||||||
onClick={this.onNewDMClick}
|
this.setState({
|
||||||
>
|
busyProfile: true,
|
||||||
<div className="mx_RoomTile_avatar">
|
});
|
||||||
<img src="img/create-big.svg" width="26" height="26" />
|
MatrixClientPeg.get().getProfileInfo(this.props.userId).done((resp) => {
|
||||||
</div>
|
const profile = {
|
||||||
<div className={labelClasses}><i>{_("Start new chat")}</i></div>
|
displayName: resp.displayname,
|
||||||
</AccessibleButton>;
|
avatarUrl: null,
|
||||||
|
};
|
||||||
|
if (resp.avatar_url) {
|
||||||
|
profile.avatarUrl = MatrixClientPeg.get().mxcUrlToHttp(
|
||||||
|
resp.avatar_url, 48, 48, "crop",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
busyProfile: false,
|
||||||
|
profile: profile,
|
||||||
|
});
|
||||||
|
}, (err) => {
|
||||||
|
console.error(
|
||||||
|
'Unable to get profile for user ' + this.props.userId + ':',
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
this.setState({
|
||||||
|
busyProfile: false,
|
||||||
|
profileError: err,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRoomTileClick(roomId) {
|
||||||
|
this.props.onExistingRoomSelected(roomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let title = '';
|
||||||
|
let content = null;
|
||||||
|
if (this.state.tiles.length > 0) {
|
||||||
|
// Show the existing rooms with a "+" to add a new dm
|
||||||
|
title = _t('Create a new chat or reuse an existing one');
|
||||||
|
const labelClasses = classNames({
|
||||||
|
mx_MemberInfo_createRoom_label: true,
|
||||||
|
mx_RoomTile_name: true,
|
||||||
|
});
|
||||||
|
const startNewChat = <AccessibleButton
|
||||||
|
className="mx_MemberInfo_createRoom"
|
||||||
|
onClick={this.props.onNewDMClick}
|
||||||
|
>
|
||||||
|
<div className="mx_RoomTile_avatar">
|
||||||
|
<img src="img/create-big.svg" width="26" height="26" />
|
||||||
|
</div>
|
||||||
|
<div className={labelClasses}><i>{ _t("Start new chat") }</i></div>
|
||||||
|
</AccessibleButton>;
|
||||||
|
content = <div className="mx_Dialog_content">
|
||||||
|
{ _t('You already have existing direct chats with this user:') }
|
||||||
|
<div className="mx_ChatCreateOrReuseDialog_tiles">
|
||||||
|
{ this.state.tiles }
|
||||||
|
{ startNewChat }
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
} else {
|
||||||
|
// Show the avatar, name and a button to confirm that a new chat is requested
|
||||||
|
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||||
|
const Spinner = sdk.getComponent('elements.Spinner');
|
||||||
|
title = _t('Start chatting');
|
||||||
|
|
||||||
|
let profile = null;
|
||||||
|
if (this.state.busyProfile) {
|
||||||
|
profile = <Spinner />;
|
||||||
|
} else if (this.state.profileError) {
|
||||||
|
profile = <div className="error">
|
||||||
|
Unable to load profile information for { this.props.userId }
|
||||||
|
</div>;
|
||||||
|
} else {
|
||||||
|
profile = <div className="mx_ChatCreateOrReuseDialog_profile">
|
||||||
|
<BaseAvatar
|
||||||
|
name={this.state.profile.displayName || this.props.userId}
|
||||||
|
url={this.state.profile.avatarUrl}
|
||||||
|
width={48} height={48}
|
||||||
|
/>
|
||||||
|
<div className="mx_ChatCreateOrReuseDialog_profile_name">
|
||||||
|
{this.state.profile.displayName || this.props.userId}
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
content = <div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<p>
|
||||||
|
{ _t('Click on the button below to start chatting!') }
|
||||||
|
</p>
|
||||||
|
{ profile }
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button className="mx_Dialog_primary" onClick={this.props.onNewDMClick}>
|
||||||
|
{ _t('Start Chatting') }
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
return (
|
return (
|
||||||
<BaseDialog className='mx_ChatCreateOrReuseDialog'
|
<BaseDialog className='mx_ChatCreateOrReuseDialog'
|
||||||
onFinished={() => {
|
onFinished={ this.props.onFinished.bind(false) }
|
||||||
this.props.onFinished(false)
|
title={title}
|
||||||
}}
|
|
||||||
title='Create a new chat or reuse an existing one'
|
|
||||||
>
|
>
|
||||||
<div className="mx_Dialog_content">
|
{ content }
|
||||||
You already have existing direct chats with this user:
|
|
||||||
<div className="mx_ChatCreateOrReuseDialog_tiles">
|
|
||||||
{tiles}
|
|
||||||
{startNewChat}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -111,5 +191,8 @@ export default class ChatCreateOrReuseDialog extends React.Component {
|
||||||
|
|
||||||
ChatCreateOrReuseDialog.propTyps = {
|
ChatCreateOrReuseDialog.propTyps = {
|
||||||
userId: React.PropTypes.string.isRequired,
|
userId: React.PropTypes.string.isRequired,
|
||||||
|
// Called when clicking outside of the dialog
|
||||||
onFinished: React.PropTypes.func.isRequired,
|
onFinished: React.PropTypes.func.isRequired,
|
||||||
|
onNewDMClick: React.PropTypes.func.isRequired,
|
||||||
|
onExistingRoomSelected: React.PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
|
@ -95,16 +95,25 @@ module.exports = React.createClass({
|
||||||
// A Direct Message room already exists for this user, so select a
|
// A Direct Message room already exists for this user, so select a
|
||||||
// room from a list that is similar to the one in MemberInfo panel
|
// room from a list that is similar to the one in MemberInfo panel
|
||||||
const ChatCreateOrReuseDialog = sdk.getComponent(
|
const ChatCreateOrReuseDialog = sdk.getComponent(
|
||||||
"views.dialogs.ChatCreateOrReuseDialog"
|
"views.dialogs.ChatCreateOrReuseDialog",
|
||||||
);
|
);
|
||||||
Modal.createDialog(ChatCreateOrReuseDialog, {
|
Modal.createDialog(ChatCreateOrReuseDialog, {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
onFinished: (success) => {
|
onFinished: (success) => {
|
||||||
if (success) {
|
this.props.onFinished(success);
|
||||||
this.props.onFinished(true, inviteList[0]);
|
},
|
||||||
}
|
onNewDMClick: () => {
|
||||||
// else show this ChatInviteDialog again
|
dis.dispatch({
|
||||||
}
|
action: 'start_chat',
|
||||||
|
user_id: userId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onExistingRoomSelected: (roomId) => {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
user_id: roomId,
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._startChat(inviteList);
|
this._startChat(inviteList);
|
||||||
|
|
|
@ -771,5 +771,11 @@
|
||||||
"Idle": "Idle",
|
"Idle": "Idle",
|
||||||
"Offline": "Offline",
|
"Offline": "Offline",
|
||||||
"disabled": "disabled",
|
"disabled": "disabled",
|
||||||
"enabled": "enabled"
|
"enabled": "enabled",
|
||||||
|
"Start chatting": "Start chatting",
|
||||||
|
"Start Chatting": "Start Chatting",
|
||||||
|
"Click on the button below to start chatting!": "Click on the button below to start chatting!",
|
||||||
|
"Create a new chat or reuse an existing one": "Create a new chat or reuse an existing one",
|
||||||
|
"You already have existing direct chats with this user:": "You already have existing direct chats with this user:",
|
||||||
|
"Start new chat": "Start new chat"
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ class LifecycleStore extends Store {
|
||||||
__onDispatch(payload) {
|
__onDispatch(payload) {
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
case 'do_after_sync_prepared':
|
case 'do_after_sync_prepared':
|
||||||
|
console.info('Will do after sync', payload.deferred_action);
|
||||||
this._setState({
|
this._setState({
|
||||||
deferred_action: payload.deferred_action,
|
deferred_action: payload.deferred_action,
|
||||||
});
|
});
|
||||||
|
@ -49,6 +50,7 @@ class LifecycleStore extends Store {
|
||||||
if (payload.state !== 'PREPARED') {
|
if (payload.state !== 'PREPARED') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
console.info('Doing', payload.deferred_action);
|
||||||
if (!this._state.deferred_action) break;
|
if (!this._state.deferred_action) break;
|
||||||
const deferredAction = Object.assign({}, this._state.deferred_action);
|
const deferredAction = Object.assign({}, this._state.deferred_action);
|
||||||
this._setState({
|
this._setState({
|
||||||
|
|
Loading…
Reference in New Issue