Merge pull request #297 from matrix-org/matthew/new-3pid-invite

implement new UX for 3pid invites
This commit is contained in:
Matthew Hodgson 2016-06-02 11:24:21 +01:00
commit 0ef0120227
4 changed files with 39 additions and 9 deletions

View File

@ -26,6 +26,7 @@ module.exports = React.createClass({
propTypes: { propTypes: {
roomId: React.PropTypes.string.isRequired, roomId: React.PropTypes.string.isRequired,
onInvite: React.PropTypes.func.isRequired, // fn(inputText) onInvite: React.PropTypes.func.isRequired, // fn(inputText)
onThirdPartyInvite: React.PropTypes.func.isRequired, // fn(inputText)
onSearchQueryChanged: React.PropTypes.func // fn(inputText) onSearchQueryChanged: React.PropTypes.func // fn(inputText)
}, },
@ -49,10 +50,19 @@ module.exports = React.createClass({
} }
}, },
componentDidMount: function() {
// initialise the email tile
this.onSearchQueryChanged('');
},
onInvite: function(ev) { onInvite: function(ev) {
this.props.onInvite(this._input); this.props.onInvite(this._input);
}, },
onThirdPartyInvite: function(ev) {
this.props.onThirdPartyInvite(this._input);
},
onSearchQueryChanged: function(input) { onSearchQueryChanged: function(input) {
this._input = input; this._input = input;
var EntityTile = sdk.getComponent("rooms.EntityTile"); var EntityTile = sdk.getComponent("rooms.EntityTile");
@ -68,9 +78,10 @@ module.exports = React.createClass({
this._emailEntity = new Entities.newEntity( this._emailEntity = new Entities.newEntity(
<EntityTile key="dynamic_invite_tile" suppressOnHover={true} showInviteButton={true} <EntityTile key="dynamic_invite_tile" suppressOnHover={true} showInviteButton={true}
avatarJsx={ <BaseAvatar name="@" width={36} height={36} /> } avatarJsx={ <BaseAvatar name="@" width={36} height={36} /> }
className="mx_EntityTile_invitePlaceholder" className="mx_EntityTile_invitePlaceholder"
presenceState="online" onClick={this.onInvite} name={label} />, presenceState="online" onClick={this.onThirdPartyInvite} name={"Invite by email"}
/>,
function(query) { function(query) {
return true; // always show this return true; // always show this
} }

View File

@ -368,7 +368,7 @@ module.exports = React.createClass({
action: 'leave_room', action: 'leave_room',
room_id: this.props.member.roomId, room_id: this.props.member.roomId,
}); });
this.props.onFinished(); this.props.onFinished();
}, },
getInitialState: function() { getInitialState: function() {

View File

@ -166,6 +166,21 @@ module.exports = React.createClass({
}); });
}, 500), }, 500),
onThirdPartyInvite: function(inputText) {
var TextInputDialog = sdk.getComponent("dialogs.TextInputDialog");
Modal.createDialog(TextInputDialog, {
title: "Invite members by email",
description: "Please enter the email addresses to be invited (comma separated)",
value: inputText,
button: "Invite",
onFinished: (should_invite, addresses)=>{
if (should_invite) {
this.onInvite(addresses);
}
}
});
},
onInvite: function(inputText) { onInvite: function(inputText) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog"); var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
@ -514,6 +529,7 @@ module.exports = React.createClass({
inviteMemberListSection = ( inviteMemberListSection = (
<InviteMemberList roomId={this.props.roomId} <InviteMemberList roomId={this.props.roomId}
onSearchQueryChanged={this.onSearchQueryChanged} onSearchQueryChanged={this.onSearchQueryChanged}
onThirdPartyInvite={this.onThirdPartyInvite}
onInvite={this.onInvite} /> onInvite={this.onInvite} />
); );
} }

View File

@ -48,6 +48,7 @@ var SearchableEntityList = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
query: "", query: "",
focused: false,
truncateAt: this.props.truncateAt, truncateAt: this.props.truncateAt,
results: this.getSearchResults("", this.props.entities) results: this.getSearchResults("", this.props.entities)
}; };
@ -101,7 +102,7 @@ var SearchableEntityList = React.createClass({
getSearchResults: function(query, entities) { getSearchResults: function(query, entities) {
if (!query || query.length === 0) { if (!query || query.length === 0) {
return this.props.emptyQueryShowsAll ? entities : [] return this.props.emptyQueryShowsAll ? entities : [ entities[0] ]
} }
return entities.filter(function(e) { return entities.filter(function(e) {
return e.matches(query); return e.matches(query);
@ -128,19 +129,21 @@ var SearchableEntityList = React.createClass({
render: function() { render: function() {
var inputBox; var inputBox;
if (this.props.showInputBox) { if (this.props.showInputBox) {
inputBox = ( inputBox = (
<form onSubmit={this.onQuerySubmit} autoComplete="off"> <form onSubmit={this.onQuerySubmit} autoComplete="off">
<input className="mx_SearchableEntityList_query" id="mx_SearchableEntityList_query" type="text" <input className="mx_SearchableEntityList_query" id="mx_SearchableEntityList_query" type="text"
onChange={this.onQueryChanged} value={this.state.query} onChange={this.onQueryChanged} value={this.state.query}
onFocus={ ()=>{ this.setState({ focused: true }) } }
onBlur={ ()=>{ this.setState({ focused: false }) } }
placeholder={this.props.searchPlaceholderText} /> placeholder={this.props.searchPlaceholderText} />
</form> </form>
); );
} }
var list; var list;
if (this.state.results.length) { if (this.state.results.length > 1 || this.state.focused) {
if (this.props.truncateAt) { // caller wants list truncated if (this.props.truncateAt) { // caller wants list truncated
var TruncatedList = sdk.getComponent("elements.TruncatedList"); var TruncatedList = sdk.getComponent("elements.TruncatedList");
list = ( list = (
@ -172,10 +175,10 @@ var SearchableEntityList = React.createClass({
} }
return ( return (
<div className={ "mx_SearchableEntityList " + (this.state.query.length ? "mx_SearchableEntityList_expanded" : "") }> <div className={ "mx_SearchableEntityList " + (list ? "mx_SearchableEntityList_expanded" : "") }>
{ inputBox } { inputBox }
{ list } { list }
{ this.state.query.length ? <div className="mx_SearchableEntityList_hrWrapper"><hr/></div> : '' } { list ? <div className="mx_SearchableEntityList_hrWrapper"><hr/></div> : '' }
</div> </div>
); );
} }