lots of refactoring to support read/received counts
This commit is contained in:
+88
-80
@@ -278,7 +278,7 @@
|
|||||||
this.setState({showErrorText: false});
|
this.setState({showErrorText: false});
|
||||||
},
|
},
|
||||||
handleLoginRequested: function(login, password) {
|
handleLoginRequested: function(login, password) {
|
||||||
this.props.onLogin(login, password);
|
this.props.onLoginRequest(login, password);
|
||||||
this.setState({showErrorText: true});
|
this.setState({showErrorText: true});
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
@@ -401,7 +401,7 @@
|
|||||||
<span>{showUnreadBadge}</span>
|
<span>{showUnreadBadge}</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
/* Online/offline indicator */
|
/* Online/offline indicator */
|
||||||
Contact.Online = React.createClass({
|
Contact.Online = React.createClass({
|
||||||
@@ -421,58 +421,66 @@
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
/* List of contacts/topics */
|
/* ContactsView holds all contacts-related stuff */
|
||||||
var ContactList = React.createClass({
|
var ContactsView = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {selected: false};
|
return {subscriptions: []};
|
||||||
|
},
|
||||||
|
componentWillMount: function() {
|
||||||
|
var me = Tinode.getMeTopic();
|
||||||
|
me.onContactUpdate = this.tnMeContactUpdate;
|
||||||
|
me.onData = this.tnInvite;
|
||||||
|
me.onSubsUpdated = this.tnMeSubsUpdated;
|
||||||
|
},
|
||||||
|
tnMeContactUpdate: function(what, cont) {
|
||||||
|
console.log("changed: " + what + " in " + cont.topic);
|
||||||
|
this.forceUpdate();
|
||||||
|
},
|
||||||
|
tnInvite: function(invite) {
|
||||||
|
console.log(invite);
|
||||||
|
},
|
||||||
|
tnMeSubsUpdated: function(names) {
|
||||||
|
/*var subs = [];
|
||||||
|
Tinode.getMeTopic().contacts(function(cont) {
|
||||||
|
subs.push(cont);
|
||||||
|
});
|
||||||
|
this.setState({subscriptions: subs});
|
||||||
|
*/
|
||||||
|
this.forceUpdate();
|
||||||
},
|
},
|
||||||
onSelectionChange: function(sel) {
|
onSelectionChange: function(sel) {
|
||||||
console.log("ContactList.onSelectionChange: " + sel);
|
|
||||||
this.props.onTopicSelected(sel);
|
this.props.onTopicSelected(sel);
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var contactNodes = null;
|
var contactNodes = [];
|
||||||
if (this.props.data) {
|
Tinode.getMeTopic().contacts(function(c) {
|
||||||
contactNodes = Object.keys(this.props.data).map(function(key) {
|
var online = false;
|
||||||
var c = this.props.data[key];
|
var lastSeen = null;
|
||||||
var online = false;
|
if (c.seen) {
|
||||||
var lastSeen = null;
|
lastSeen = shortDateFormat(new Date(c.seen.when));
|
||||||
if (c.seen) {
|
// TODO(gene): also handle user agent in c.seen.ua
|
||||||
lastSeen = shortDateFormat(new Date(c.seen.when));
|
}
|
||||||
// TODO(gene): also handle user agent in c.seen.ua
|
var unread = c.seq;
|
||||||
}
|
if (c.read > 0) {
|
||||||
var unread = c.seq;
|
unread -= c.read;
|
||||||
if (c.read > 0) {
|
}
|
||||||
unread -= c.read;
|
contactNodes.push(
|
||||||
}
|
<Contact public={c.public} comment={c.private} unread={unread} now={online} when={lastSeen}
|
||||||
|
onSelected={this.onSelectionChange} topic={c.topic} key={c.topic} />
|
||||||
|
);
|
||||||
|
}, this);
|
||||||
|
|
||||||
return (
|
|
||||||
<Contact public={c.public} comment={c.private} unread={unread} now={online} when={lastSeen}
|
|
||||||
onSelected={this.onSelectionChange} topic={c.topic} key={c.topic} />
|
|
||||||
);
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="contactList">
|
|
||||||
<ul className="media-list">
|
|
||||||
{contactNodes}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* The panel holds all contacts-related stuff */
|
|
||||||
var ContactsView = React.createClass({
|
|
||||||
render: function() {
|
|
||||||
return (
|
return (
|
||||||
<div className="contactBox">
|
<div className="contactBox">
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
<NewTopic />
|
<NewTopic />
|
||||||
<ContactList data={this.props.data}
|
<div className="contactList">
|
||||||
onTopicSelected={this.props.onTopicSelected} />
|
<ul className="media-list">
|
||||||
|
{contactNodes}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -616,10 +624,12 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
|
|||||||
},
|
},
|
||||||
// Scroll last message into view on component update e.g. on message received.
|
// Scroll last message into view on component update e.g. on message received.
|
||||||
componentDidUpdate: function() {
|
componentDidUpdate: function() {
|
||||||
var node = ReactDOM.findDOMNode(this);
|
//var node = ReactDOM.findDOMNode(this);
|
||||||
if (node) {
|
//if (node) {
|
||||||
node.scrollTop = node.scrollHeight;
|
// node.scrollTop = node.scrollHeight;
|
||||||
}
|
//}
|
||||||
|
var node = this.refs.messagesPanel;
|
||||||
|
node.scrollTop = node.scrollHeight;
|
||||||
},
|
},
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
this.propsChange(this.props);
|
this.propsChange(this.props);
|
||||||
@@ -652,7 +662,8 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
|
|||||||
topic.subscribe({get: "info sub data"});
|
topic.subscribe({get: "info sub data"});
|
||||||
}
|
}
|
||||||
|
|
||||||
// The user switched a topic before the timer has triggered, kill it.
|
// The user switched to the new topic before the timer for
|
||||||
|
// the previous topic has triggered, kill it.
|
||||||
clearTimeout(this.readTimer);
|
clearTimeout(this.readTimer);
|
||||||
|
|
||||||
this.setState({messages: msgs, topic: props.topicSelected});
|
this.setState({messages: msgs, topic: props.topicSelected});
|
||||||
@@ -695,7 +706,7 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<div className="panel panel-default fullViewPort" id="messagesPanel">
|
<div className="panel panel-default fullViewPort" id="messagesPanel" ref="messagesPanel">
|
||||||
<div className="panel-heading" id="chatTitle">
|
<div className="panel-heading" id="chatTitle">
|
||||||
<h3 className="panel-title">{this.state.title}</h3>
|
<h3 className="panel-title">{this.state.title}</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -732,8 +743,8 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
|
|||||||
var AppView = React.createClass({
|
var AppView = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
sidePanel: 'login',
|
sidePanelSelected: 'login',
|
||||||
sideTitle: 'not set',
|
sidePanelTitle: 'not set',
|
||||||
loggedIn: false,
|
loggedIn: false,
|
||||||
errorText: '',
|
errorText: '',
|
||||||
topicSelected: '',
|
topicSelected: '',
|
||||||
@@ -743,40 +754,34 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
|
|||||||
},
|
},
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
Tinode.enableLogging(true);
|
Tinode.enableLogging(true);
|
||||||
|
Tinode.onDisconnect = this.handleDicsonnect;
|
||||||
// Setup with the default transport, usually websocket.
|
// Setup with the default transport, usually websocket.
|
||||||
Tinode.setup(HOST, API_KEY);
|
Tinode.setup(HOST, API_KEY);
|
||||||
},
|
},
|
||||||
handleLogin: function(login, password) {
|
handleDicsonnect: function() {
|
||||||
|
console.log("DISCONNECTED!");
|
||||||
|
},
|
||||||
|
// User clicked Login button in the side panel.
|
||||||
|
handleLoginRequest: function(login, password) {
|
||||||
var instance = this;
|
var instance = this;
|
||||||
this.setState({loginDisabled: true, errorText: ''});
|
this.setState({loginDisabled: true, errorText: ''});
|
||||||
Tinode.connect().then(function() {
|
Tinode.connect().then(function() {
|
||||||
// Login
|
// Login
|
||||||
return Tinode.loginBasic(login, password);
|
return Tinode.loginBasic(login, password);
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
// Subscribe to me, fetch current user's info and a list of
|
// Logged in fine, subscribe to 'me' attaching callbacks from the contacts view.
|
||||||
// topic subscriptions (contact list).
|
|
||||||
instance.setState({loggedIn: true});
|
|
||||||
var me = Tinode.getMeTopic();
|
var me = Tinode.getMeTopic();
|
||||||
me.onMetaInfo = instance.tnMeInfoChange;
|
me.onMetaInfo = instance.tnMeMetaInfo;
|
||||||
me.onMetaSub = instance.tnMeSubsChange;
|
instance.setState({sidePanelSelected: "contacts", loggedIn: true});
|
||||||
// Subscribe, fetch topic info and the list of subscriptions.
|
// Subscribe, fetch topic info and the list of subscriptions.
|
||||||
return me.subscribe({get: "info sub"});
|
me.subscribe({get: "info sub data"});
|
||||||
}).then(function() {
|
|
||||||
// Success! Hide Login panel, show contact list.
|
|
||||||
instance.setState({sidePanel: "contacts"});
|
|
||||||
}).catch(function(err) {
|
}).catch(function(err) {
|
||||||
|
// Login failed, report error
|
||||||
instance.setState({loginDisabled: false, errorText: err.message});
|
instance.setState({loginDisabled: false, errorText: err.message});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
tnMeInfoChange: function(info) {
|
tnMeMetaInfo: function(info) {
|
||||||
this.setState({sideTitle: info.public});
|
this.setState({sidePanelTitle: info.public});
|
||||||
},
|
|
||||||
tnMeSubsChange: function(sub) {
|
|
||||||
var subs = this.state.subscriptions;
|
|
||||||
var topic = Tinode.getTopic(sub.topic);
|
|
||||||
topic.onPres = this.tnPresence;
|
|
||||||
subs[sub.topic] = sub;
|
|
||||||
this.setState({subscriptions: subs});
|
|
||||||
},
|
},
|
||||||
// Sending "received" notifications
|
// Sending "received" notifications
|
||||||
tnData: function(data) {
|
tnData: function(data) {
|
||||||
@@ -786,9 +791,7 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
|
|||||||
Tinode.getTopic(data.topic).noteRecv(data.seq);
|
Tinode.getTopic(data.topic).noteRecv(data.seq);
|
||||||
}, RECEIVED_DELAY);
|
}, RECEIVED_DELAY);
|
||||||
},
|
},
|
||||||
tnPresence: function(pres) {
|
// Registration of a new account.
|
||||||
console.log(pres);
|
|
||||||
},
|
|
||||||
handleNewAccount: function(login_, password_, public_, private_) {
|
handleNewAccount: function(login_, password_, public_, private_) {
|
||||||
var instance = this;
|
var instance = this;
|
||||||
Tinode.connect().then(function(){
|
Tinode.connect().then(function(){
|
||||||
@@ -798,24 +801,29 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
|
|||||||
instance.setState({errorText: err.message});
|
instance.setState({errorText: err.message});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// User clicked on a contact in the side panel.
|
||||||
handleTopicSelected: function(topicName) {
|
handleTopicSelected: function(topicName) {
|
||||||
this.setState({topicSelected: topicName});
|
this.setState({topicSelected: topicName});
|
||||||
},
|
},
|
||||||
|
// User clicked on a message send button.
|
||||||
handleSendMessage: function(msg) {
|
handleSendMessage: function(msg) {
|
||||||
var topic = Tinode.getTopic(this.state.topicSelected);
|
var topic = Tinode.getTopic(this.state.topicSelected);
|
||||||
topic.publish(msg);
|
topic.publish(msg);
|
||||||
},
|
},
|
||||||
|
// User chose a Sign Up menu item.
|
||||||
handleSignUp: function() {
|
handleSignUp: function() {
|
||||||
this.setState({sidePanel: 'register'});
|
this.setState({sidePanelSelected: 'register'});
|
||||||
},
|
},
|
||||||
|
// User chose Settings menu item.
|
||||||
handleSettings: function() {
|
handleSettings: function() {
|
||||||
this.setState({sidePanel: 'settings'});
|
this.setState({sidePanelSelected: 'settings'});
|
||||||
},
|
},
|
||||||
|
// User clicked Cancel button in Setting or Sign Up panel.
|
||||||
handleSidepanelCancel: function() {
|
handleSidepanelCancel: function() {
|
||||||
if (this.state.loggedIn) {
|
if (this.state.loggedIn) {
|
||||||
this.setState({sidePanel: 'contacts'});
|
this.setState({sidePanelSelected: 'contacts'});
|
||||||
} else {
|
} else {
|
||||||
this.setState({sidePanel: 'login'});
|
this.setState({sidePanelSelected: 'login'});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
@@ -824,14 +832,14 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
|
|||||||
|
|
||||||
<div id="sidepanel-wrapper">
|
<div id="sidepanel-wrapper">
|
||||||
<SidepanelView
|
<SidepanelView
|
||||||
state={this.state.sidePanel}
|
state={this.state.sidePanelSelected}
|
||||||
title={this.state.sideTitle}
|
title={this.state.sidePanelTitle}
|
||||||
subscriptions={this.state.subscriptions}
|
subscriptions={this.state.subscriptions}
|
||||||
loginDisabled={this.state.loginDisabled}
|
loginDisabled={this.state.loginDisabled}
|
||||||
errorText={this.state.errorText}
|
errorText={this.state.errorText}
|
||||||
onSignUp={this.handleSignUp}
|
onSignUp={this.handleSignUp}
|
||||||
onSettings={this.handleSettings}
|
onSettings={this.handleSettings}
|
||||||
onLogin={this.handleLogin}
|
onLoginRequest={this.handleLoginRequest}
|
||||||
onCreateAccount={this.handleNewAccount}
|
onCreateAccount={this.handleNewAccount}
|
||||||
onTopicSelected={this.handleTopicSelected}
|
onTopicSelected={this.handleTopicSelected}
|
||||||
onCancel={this.handleSidepanelCancel} />
|
onCancel={this.handleSidepanelCancel} />
|
||||||
|
|||||||
Reference in New Issue
Block a user