topic invites work correctly now, UI fixes

This commit is contained in:
or-else
2017-09-07 19:10:50 -07:00
parent b718aa9513
commit 8ddfb93f7a
2 changed files with 130 additions and 36 deletions
+34 -1
View File
@@ -1161,7 +1161,7 @@ ul.tabbar li.active > a:after {
/* Miscellaneous */ /* Miscellaneous */
/* Badge with the number of unread messages */ /* Badge with the number of unread messages */
.badge { .unread {
display: inline-block; display: inline-block;
font-size: 0.75rem; font-size: 0.75rem;
font-weight: bolder; font-weight: bolder;
@@ -1176,6 +1176,39 @@ ul.tabbar li.active > a:after {
vertical-align: middle; vertical-align: middle;
} }
/* Badge with a label, like [you], [muted], etc */
.badge {
font-family: monospace;
font-size: 0.75rem;
border: 1px solid #666;
background-color: #eee;
color: #666;
padding: 0 0.15rem 0 0.15rem;
margin-left: 0.1rem;
margin-right: 0.1rem;
border-radius: 0.15rem;
display: inline-block;
align-self: flex-start;
}
.badge.green {
border-color: #383;
background-color: #efe;
color: #383;
}
.badge.yellow {
border-color: #660;
background-color: #ffe;
color: #660;
}
.badge.red {
border-color: #933;
background-color: #fee;
color: #933;
}
/* Letter tile base style, responsive square box */ /* Letter tile base style, responsive square box */
.lettertile { .lettertile {
width: 100%; width: 100%;
+95 -34
View File
@@ -131,8 +131,6 @@
// Function is used by context menu to set permissions. // Function is used by context menu to set permissions.
function topicPermissionSetter(mode, topicName, uid) { function topicPermissionSetter(mode, topicName, uid) {
console.log("topicPermissionSetter called with arguments:");
console.log(arguments);
var topic = Tinode.getTopic(topicName); var topic = Tinode.getTopic(topicName);
if (!topic) { if (!topic) {
console.log("Topic not found: " + topicName); console.log("Topic not found: " + topicName);
@@ -527,6 +525,7 @@
<div className="panel-form-column"> <div className="panel-form-column">
{this.props.userTitle ? {this.props.userTitle ?
<ul className="contact-box"><Contact <ul className="contact-box"><Contact
item={this.props.item}
title={this.props.userTitle} title={this.props.userTitle}
avatar={makeImageUrl(this.props.userAvatar ? this.props.userAvatar : null)} /></ul> : null} avatar={makeImageUrl(this.props.userAvatar ? this.props.userAvatar : null)} /></ul> : null}
<label className="small">Permissions</label> <label className="small">Permissions</label>
@@ -1210,6 +1209,19 @@
} }
var online = this.props.now ? "online" : "offline"; var online = this.props.now ? "online" : "offline";
var avatar = this.props.avatar ? this.props.avatar : true; var avatar = this.props.avatar ? this.props.avatar : true;
var badges = [];
if (this.props.badges && this.props.badges.length > 0) {
var count = 0;
this.props.badges.map(function(b) {
var style = "badge" + (b.color ? " " + b.color : "");
badges.push(<span className={style} key={count}>{b.name}</span>);
count ++;
});
}
if (this.props.mode) {
badges.push(<span className="badge" key="mode">{this.props.mode}</span>);
}
return ( return (
<li className={!this.props.showCheckmark && this.props.selected ? "selected" : null} <li className={!this.props.showCheckmark && this.props.selected ? "selected" : null}
onClick={this.handleClick}> onClick={this.handleClick}>
@@ -1224,9 +1236,10 @@
</div> </div>
<div className="text-box"> <div className="text-box">
<div><span className="contact-title">{title}</span> <div><span className="contact-title">{title}</span>
{this.props.showUnread && (this.props.unread > 0) ? {this.props.unread > 0 ? <Contact.Unread count={this.props.unread} /> : null}
<Contact.Unread count={this.props.unread} /> : null}</div> </div>
{this.props.comment ? <div className="contact-comment">{this.props.comment}</div> : null} {this.props.comment ? <div className="contact-comment">{this.props.comment}</div> : null}
<span>{badges}</span>
</div> </div>
{this.props.showContextMenu ? {this.props.showContextMenu ?
<span className="menuTrigger"> <span className="menuTrigger">
@@ -1245,12 +1258,29 @@
var showUnreadBadge = null; var showUnreadBadge = null;
if (this.props.count > 0) { if (this.props.count > 0) {
var count = this.props.count > 9 ? "9+" : this.props.count; var count = this.props.count > 9 ? "9+" : this.props.count;
showUnreadBadge = <span className="badge">{count}</span>; showUnreadBadge = <span className="unread">{count}</span>;
} }
return showUnreadBadge; return showUnreadBadge;
} }
}); });
/* Contact's labels: [you], [muted], [blocked], etc */
Contact.Badges = React.createClass({
render: function() {
var badges = null;
if (this.props.badges && this.props.badges.length > 0) {
var count = 0;
badges = [];
this.props.badges.map(function(b) {
var style = "badge" + (b.color ? " " + b.color : "");
badges.push(<span className={style} key={count}>{b.name}</span>);
count ++;
});
}
return badges;
}
});
/* ContactsView holds all contacts-related stuff */ /* ContactsView holds all contacts-related stuff */
var ContactsView = React.createClass({ var ContactsView = React.createClass({
getInitialState: function() { getInitialState: function() {
@@ -1261,7 +1291,6 @@
componentWillMount: function() { componentWillMount: function() {
var me = Tinode.getMeTopic(); var me = Tinode.getMeTopic();
me.onContactUpdate = this.tnMeContactUpdate; me.onContactUpdate = this.tnMeContactUpdate;
me.onData = this.tnInvite;
me.onSubsUpdated = this.tnMeSubsUpdated; me.onSubsUpdated = this.tnMeSubsUpdated;
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
@@ -1301,12 +1330,6 @@
} }
}, },
tnInvite: function(invite) {
// TODO(gene): implement invite handling
console.log("Got invite:");
console.log(invite);
},
tnMeSubsUpdated: function(names) { tnMeSubsUpdated: function(names) {
this.resetContactList(); this.resetContactList();
}, },
@@ -1314,10 +1337,7 @@
prepareContactList: function() { prepareContactList: function() {
var contacts = []; var contacts = [];
Tinode.getMeTopic().contacts(function(c) { Tinode.getMeTopic().contacts(function(c) {
c.unread = c.seq; c.unread = c.seq - (c.read > 0 ? c.read : 0);
if (c.read > 0) {
c.unread -= c.read;
}
contacts.push(c); contacts.push(c);
}, this); }, this);
@@ -1347,6 +1367,7 @@
* such as a list of group members in a group chat */ * such as a list of group members in a group chat */
var ContactList = React.createClass({ var ContactList = React.createClass({
render: function() { render: function() {
var me = Tinode.getCurrentUserID();
var contactNodes = []; var contactNodes = [];
var instance = this; var instance = this;
var showCheckmark = Array.isArray(this.props.topicSelected); var showCheckmark = Array.isArray(this.props.topicSelected);
@@ -1354,7 +1375,6 @@
if (this.props.contacts && this.props.contacts.length > 0) { if (this.props.contacts && this.props.contacts.length > 0) {
this.props.contacts.map(function(c) { this.props.contacts.map(function(c) {
var key = c.topic ? c.topic : c.user; var key = c.topic ? c.topic : c.user;
// If filter function is provided, filter out the items // If filter function is provided, filter out the items
// which don't satisfy the condition. // which don't satisfy the condition.
if (instance.props.filterFunc && instance.props.filter) { if (instance.props.filterFunc && instance.props.filter) {
@@ -1374,16 +1394,24 @@
(this.props.topicSelected.indexOf(key) > -1) : (this.props.topicSelected.indexOf(key) > -1) :
(this.props.topicSelected === key); (this.props.topicSelected === key);
var mode = this.props.showMode && c.acs ? c.acs.getMode() : null;
var badges = (key === me ? [{name:'you',color:'green'}] : null);
var comment = Array.isArray(c.private) ? c.private.join(", ") : c.private;
contactNodes.push( contactNodes.push(
<Contact <Contact
title={c.public ? c.public.fn : null} title={c.public ? c.public.fn : null}
avatar={makeImageUrl(c.public ? c.public.photo : null)} avatar={makeImageUrl(c.public ? c.public.photo : null)}
comment={c.private} comment={comment}
unread={c.unread} now={c.online} unread={this.props.showUnread ? c.unread : 0}
now={c.online}
mode={mode}
badges={badges}
showCheckmark={showCheckmark} showCheckmark={showCheckmark}
selected={selected} selected={selected}
showOnline={this.props.showOnline} showOnline={this.props.showOnline}
showUnread={this.props.showUnread}
onSelected={this.props.onTopicSelected} onSelected={this.props.onTopicSelected}
showContextMenu={this.props.showContextMenu} showContextMenu={this.props.showContextMenu}
item={key} item={key}
@@ -1414,7 +1442,6 @@
getInitialState: function() { getInitialState: function() {
return { return {
members: this.props.members, members: this.props.members,
contacts: this.props.contacts,
index: this.indexMembers(this.props.members), index: this.indexMembers(this.props.members),
contactFilter: '', contactFilter: '',
noContactsMessage: 'You have no contacts :-(', noContactsMessage: 'You have no contacts :-(',
@@ -1586,14 +1613,14 @@
handleContactSelected: function(sel) { handleContactSelected: function(sel) {
if (this.state.tabSelected === "p2p") { if (this.state.tabSelected === "p2p") {
this.props.onCreateTopic(sel, undefined); this.props.onCreateTopic(sel, undefined);
} else {
// TODO(gene): implement handling of group invites
console.log("handle group invite " + sel);
} }
}, },
handleGroupSubmit: function(name, dataUrl) { handleGroupSubmit: function(name, dataUrl) {
this.props.onCreateTopic(undefined, vcard(name, dataUrl)); this.props.onCreateTopic(undefined, vcard(name, dataUrl));
}, },
handleGroupSubscribe: function(topicName) {
this.props.onCreateTopic(topicName);
},
render: function() { render: function() {
return ( return (
<div className="flex-column"> <div className="flex-column">
@@ -1604,9 +1631,14 @@
<li className={this.state.tabSelected === "grp" ? "active" : null}> <li className={this.state.tabSelected === "grp" ? "active" : null}>
<a href="#" data-id="grp" onClick={this.handleTabClick}>group</a> <a href="#" data-id="grp" onClick={this.handleTabClick}>group</a>
</li> </li>
<li className={this.state.tabSelected === "byId" ? "active" : null}>
<a href="#" data-id="byId" onClick={this.handleTabClick}>by id</a>
</li>
</ul> </ul>
{this.state.tabSelected === "grp" ? {this.state.tabSelected === "grp" ?
<NewTopicView.Group onSubmit={this.handleGroupSubmit} /> : <NewTopicView.Group onSubmit={this.handleGroupSubmit} /> :
this.state.tabSelected === "byId" ?
<NewTopicView.ById onSubmit={this.handleGroupSubscribe} /> :
<div className="flex-column"> <div className="flex-column">
<NewTopicView.SearchContacts type="p2p" <NewTopicView.SearchContacts type="p2p"
searchQuery={this.state.searchQuery} searchQuery={this.state.searchQuery}
@@ -1716,6 +1748,42 @@
); );
} }
}); });
NewTopicView.ById = React.createClass({
getInitialState: function() {
return {
groupId: '',
};
},
handleChange: function(e) {
this.setState({groupId: e.target.value});
},
handleKeyPress: function(e) {
if (e.key === 'Enter') {
this.handleSubmit(e);
}
},
handleSubmit: function(e) {
e.preventDefault();
if (this.state.groupId && this.state.groupId.trim()) {
this.props.onSubmit(this.state.groupId.trim());
}
},
render: function() {
return (
<div className="panel-form">
<div className="panel-form-row">
<input type="text" placeholder="Group ID"
value={this.state.groupId} onChange={this.handleChange}
onKeyPress={this.handleKeyPress} required />
</div>
<div className="dialog-buttons">
<button className="blue" onClick={this.handleSubmit}>Subscribe</button>
</div>
</div>
);
}
});
/* END Create new topic and invite users or send an invite */ /* END Create new topic and invite users or send an invite */
/* BEGIN InfoView: panel with topic/user info */ /* BEGIN InfoView: panel with topic/user info */
@@ -1881,9 +1949,6 @@
}, },
handleLaunchPermissionsEditor: function(which, uid) { handleLaunchPermissionsEditor: function(which, uid) {
console.log("handleLaunchPermissionsEditor called with arguments");
console.log(arguments);
var toEdit, toCompare, toSkip, titleEdit, titleCompare, userTitle, userAvatar var toEdit, toCompare, toSkip, titleEdit, titleCompare, userTitle, userAvatar
switch (which) { switch (which) {
case 'mode': case 'mode':
@@ -1976,9 +2041,6 @@
}, },
handleContextMenu: function(item, x, y) { handleContextMenu: function(item, x, y) {
console.log("handleContextMenu called with agruments");
console.log(arguments);
var instance = this; var instance = this;
var topic = Tinode.getTopic(this.props.topic); var topic = Tinode.getTopic(this.props.topic);
if (!topic) { if (!topic) {
@@ -2025,6 +2087,7 @@
modeTitle={this.state.editedPermissionsTitle} modeTitle={this.state.editedPermissionsTitle}
compareTitle={this.state.immutablePermissionsTitle} compareTitle={this.state.immutablePermissionsTitle}
userTitle={this.state.userPermissionsTitle} userTitle={this.state.userPermissionsTitle}
item={this.state.userPermissionsEdited}
userAvatar={this.state.userPermissionsAvatar} userAvatar={this.state.userPermissionsAvatar}
skip={this.state.editedPermissionsSkipped} skip={this.state.editedPermissionsSkipped}
onSubmit={this.handlePermissionsChanged} onSubmit={this.handlePermissionsChanged}
@@ -2139,6 +2202,7 @@
topicSelected={this.state.selectedContact} topicSelected={this.state.selectedContact}
showOnline={false} showOnline={false}
showUnread={false} showUnread={false}
showMode={true}
noScroll={true} noScroll={true}
onTopicSelected={this.handleMemberSelected} onTopicSelected={this.handleMemberSelected}
showContextMenu={this.state.admin ? this.handleContextMenu : false} showContextMenu={this.state.admin ? this.handleContextMenu : false}
@@ -2927,9 +2991,6 @@
}, },
handleShowContextMenu: function(topicName, y, x, uid, menuItems) { handleShowContextMenu: function(topicName, y, x, uid, menuItems) {
console.log("handleShowContextMenu called with arguments");
console.log(arguments);
this.setState({ this.setState({
contextMenuVisible: true, contextMenuVisible: true,
contextMenuClickAt: {x: x, y: y}, contextMenuClickAt: {x: x, y: y},
@@ -2989,7 +3050,7 @@
if (added && added.length > 0) { if (added && added.length > 0) {
added.map(function(uid) { added.map(function(uid) {
topic.invite(uid, null, "Join my group!"); topic.invite(uid, null);
}); });
} }