diff --git a/src/Entities.js b/src/Entities.js
index ee0d3e9d1b..712f7b4dde 100644
--- a/src/Entities.js
+++ b/src/Entities.js
@@ -63,7 +63,8 @@ class UserEntity extends Entity {
}
matches(queryString) {
- return this.model.displayName.toLowerCase().indexOf(queryString.toLowerCase()) === 0;
+ var name = this.model.displayName || this.model.userId;
+ return name.toLowerCase().indexOf(queryString.toLowerCase()) === 0;
}
}
diff --git a/src/component-index.js b/src/component-index.js
index cbecbf7d2e..94f313a83c 100644
--- a/src/component-index.js
+++ b/src/component-index.js
@@ -73,6 +73,7 @@ module.exports.components['views.rooms.RoomTile'] = require('./components/views/
module.exports.components['views.rooms.SearchableEntityList'] = require('./components/views/rooms/SearchableEntityList');
module.exports.components['views.rooms.SearchResultTile'] = require('./components/views/rooms/SearchResultTile');
module.exports.components['views.rooms.TabCompleteBar'] = require('./components/views/rooms/TabCompleteBar');
+module.exports.components['views.rooms.UserTile'] = require('./components/views/rooms/UserTile');
module.exports.components['views.settings.ChangeAvatar'] = require('./components/views/settings/ChangeAvatar');
module.exports.components['views.settings.ChangeDisplayName'] = require('./components/views/settings/ChangeDisplayName');
module.exports.components['views.settings.ChangePassword'] = require('./components/views/settings/ChangePassword');
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js
index f5fc5b9f82..625a35e2fa 100644
--- a/src/components/views/rooms/MemberList.js
+++ b/src/components/views/rooms/MemberList.js
@@ -275,14 +275,24 @@ module.exports = React.createClass({
);
} else {
- var SearchableEntityList = sdk.getComponent("rooms.SearchableEntityList");
+ // TODO: Cache this calculation
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
+ var allUsers = MatrixClientPeg.get().getUsers();
+ // only add Users if they don't exist in the member list
+ allUsers = allUsers.filter(function(u) {
+ return room.getMember(u.userId) === null;
+ });
+
+ var SearchableEntityList = sdk.getComponent("rooms.SearchableEntityList");
+
return (
);
diff --git a/src/components/views/rooms/UserTile.js b/src/components/views/rooms/UserTile.js
new file mode 100644
index 0000000000..4a06dc9bc3
--- /dev/null
+++ b/src/components/views/rooms/UserTile.js
@@ -0,0 +1,127 @@
+/*
+Copyright 2015, 2016 OpenMarket 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.
+*/
+
+'use strict';
+
+var React = require('react');
+
+var MatrixClientPeg = require('../../../MatrixClientPeg');
+var sdk = require('../../../index');
+var dis = require('../../../dispatcher');
+var Modal = require("../../../Modal");
+
+module.exports = React.createClass({
+ displayName: 'UserTile',
+
+ propTypes: {
+ user: React.PropTypes.any.isRequired, // User
+ onInviteClick: React.PropTypes.func, //onInviteClick(User)
+ showInvite: React.PropTypes.bool,
+ onClick: React.PropTypes.func
+ },
+
+ getInitialState: function() {
+ return {};
+ },
+
+ getDefaultProps: function() {
+ return {
+ onClick: function() {},
+ onInviteClick: function() {},
+ showInvite: false
+ };
+ },
+
+ shouldComponentUpdate: function(nextProps, nextState) {
+ if (this.state.hover !== nextState.hover) return true;
+ return false;
+ },
+
+ mouseEnter: function(e) {
+ this.setState({ 'hover': true });
+ },
+
+ mouseLeave: function(e) {
+ this.setState({ 'hover': false });
+ },
+
+ render: function() {
+ var user = this.props.user;
+ var name = user.displayName || user.userId;
+ var isMyUser = MatrixClientPeg.get().credentials.userId == user.userId;
+ var active = -1;
+ var presenceClass = "mx_MemberTile_offline";
+
+ this.user_last_modified_time = user.getLastModifiedTime();
+
+ // FIXME: make presence data update whenever User.presence changes...
+ active = (
+ (Date.now() - (user.lastPresenceTs - user.lastActiveAgo)) || -1
+ );
+
+ if (user.presence === "online") {
+ presenceClass = "mx_MemberTile_online";
+ }
+ else if (user.presence === "unavailable") {
+ presenceClass = "mx_MemberTile_unavailable";
+ }
+
+
+ var mainClassName = "mx_MemberTile ";
+ mainClassName += presenceClass;
+ if (this.state.hover) {
+ mainClassName += " mx_MemberTile_hover";
+ }
+
+ var nameEl;
+ if (this.state.hover) {
+ var PresenceLabel = sdk.getComponent("rooms.PresenceLabel");
+ nameEl = (
+
+

+
{ name }
+
+
+ );
+ }
+ else {
+ nameEl = (
+
+ { name }
+
+ );
+ }
+
+ var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
+
+ if (this.props.showInvite) {
+ // TODO
+ }
+
+ return (
+
+ );
+ }
+});