diff --git a/src/webapp.jsx b/src/webapp.jsx
index 2377cbe5..01ccbce5 100644
--- a/src/webapp.jsx
+++ b/src/webapp.jsx
@@ -1893,7 +1893,10 @@ class TagManager extends React.Component {
}
static getDerivedStateFromProps(nextProps, prevState) {
- return {tags: nextProps.tags};
+ if (!arrayEqual(nextProps.tags, prevState.tags) && !prevState.activated) {
+ return {tags: nextProps.tags};
+ }
+ return null;
}
handleShowTagManager() {
@@ -1917,10 +1920,9 @@ class TagManager extends React.Component {
handleAddTag(tag) {
tag = tag.trim();
if (tag.length > 0) {
- var tags = this.state.tags.slice(0);
+ let tags = this.state.tags.slice(0);
tags.push(tag);
this.setState({tags: tags, tagInput: ''});
-
if (this.props.onTagsChanged) {
this.props.onTagsChanged(tags);
}
@@ -1937,8 +1939,8 @@ class TagManager extends React.Component {
}
handleSubmit() {
- var tags = this.state.tags.slice(0);
- var inp = this.state.tagInput.trim();
+ let tags = this.state.tags.slice(0);
+ let inp = this.state.tagInput.trim();
if (inp.length > 0) {
tags.push(inp);
if (this.props.onTagsChanged) {
@@ -1976,7 +1978,7 @@ class TagManager extends React.Component {
{this.state.activated ?
-
+
:
-
+
}
);
@@ -3533,6 +3535,7 @@ class Attachment extends React.Component {
);
}
};
+const NOT_FOUND_TOPIC_TITLE = "Not found";
class MessagesView extends React.Component {
constructor(props) {
@@ -3607,12 +3610,17 @@ class MessagesView extends React.Component {
return;
}
- var tryToResubscribe = !this.props.connected && props.connected;
+ let topic = this.props.tinode.getTopic(props.topic);
+ if (!topic) {
+ return;
+ }
+
+ let newGroupTopic = Tinode.isNewGroupTopicName(props.topic);
+ let tryToResubscribe = !this.props.connected && props.connected;
- var topic = this.props.tinode.getTopic(props.topic);
if (props.topic != this.state.topic) {
- var msgs = [];
- var subs = [];
+ let msgs = [];
+ let subs = [];
// Bind the new topic to component.
topic.onData = this.handleNewMessage;
@@ -3657,21 +3665,26 @@ class MessagesView extends React.Component {
});
if (!topic.isSubscribed() && tryToResubscribe) {
- var getQuery = topic.startMetaQuery()
+ let getQuery = topic.startMetaQuery()
.withLaterDesc()
.withLaterSub()
.withLaterData(MESSAGES_PAGE)
.withLaterDel();
+ let setQuery = newGroupTopic ? props.newGroupTopicParams : undefined;
// Don't request the tags. They are useless unless the user
// is the owner and is editing the topic.
// getQuery = topic.getType() == 'grp' ? getQuery.withTags() : getQuery;
// Show "loading" spinner.
this.setState({ fetchingMessages: true });
- topic.subscribe(getQuery.build())
+ topic.subscribe(getQuery.build(), setQuery)
+ .then((ctrl) => {
+ this.setState({topic: ctrl.topic});
+ this.props.onNewTopicCreated(props.topic, ctrl.topic);
+ })
.catch((err) => {
this.props.onError(err.message, "err");
this.setState({
- title: "Not found",
+ title: NOT_FOUND_TOPIC_TITLE,
avatar: null,
readOnly: true,
writeOnly: true,
@@ -3683,20 +3696,24 @@ class MessagesView extends React.Component {
leave() {
if (this.state.topic) {
- var oldTopic = this.props.tinode.getTopic(this.state.topic);
+ let oldTopic = this.props.tinode.getTopic(this.state.topic);
if (oldTopic) {
if (oldTopic.isSubscribed()) {
- oldTopic.leave(false).catch(function(err) {
- // do nothing
- console.log(err);
- });
+ oldTopic.leave(false)
+ .then((ctrl) => {
+ this.setState({fetchingMessages: false});
+ oldTopic.onData = undefined;
+ oldTopic.onAllMessagesReceived = undefined;
+ oldTopic.onInfo = undefined;
+ oldTopic.onMetaDesc = undefined;
+ oldTopic.onSubsUpdated = undefined;
+ oldTopic.onPres = undefined;
+ })
+ .catch((err) => {
+ // do nothing
+ console.log(err);
+ });
}
- oldTopic.onData = undefined;
- oldTopic.onAllMessagesReceived = undefined;
- oldTopic.onInfo = undefined;
- oldTopic.onMetaDesc = undefined;
- oldTopic.onSubsUpdated = undefined;
- oldTopic.onPres = undefined;
}
}
}
@@ -3734,6 +3751,11 @@ class MessagesView extends React.Component {
title: desc.public.fn,
avatar: makeImageUrl(desc.public.photo)
});
+ } else {
+ this.setState({
+ title: NOT_FOUND_TOPIC_TITLE,
+ avatar: null
+ });
}
if (desc.acs) {
this.setState({
@@ -4288,6 +4310,7 @@ class TinodeWeb extends React.Component {
this.handleSidepanelCancel = this.handleSidepanelCancel.bind(this);
this.handleNewTopic = this.handleNewTopic.bind(this);
this.handleNewTopicRequest = this.handleNewTopicRequest.bind(this);
+ this.handleNewTopicCreated = this.handleNewTopicCreated.bind(this);
this.handleTopicUpdateRequest = this.handleTopicUpdateRequest.bind(this);
this.handleChangePermissions = this.handleChangePermissions.bind(this);
this.handleTagsUpdated = this.handleTagsUpdated.bind(this);
@@ -4332,6 +4355,7 @@ class TinodeWeb extends React.Component {
topicSelected: '',
topicSelectedOnline: false,
topicSelectedAcs: null,
+ newGroupTopicParams: null,
loginDisabled: false,
displayMobile: (window.innerWidth <= MEDIA_BREAKPOINT),
showInfoPanel: false,
@@ -4420,30 +4444,24 @@ class TinodeWeb extends React.Component {
// Handle for hashchange event: display appropriate panels.
handleHashRoute() {
var hash = parseUrlHash(window.location.hash);
- // Left-side panel selector.
if (hash.path && hash.path.length > 0) {
+ // Left-side panel selector.
if (['register','settings','edit','cred','newtpk','contacts',''].includes(hash.path[0])) {
this.setState({sidePanelSelected: hash.path[0]});
} else {
console.log("Unknown sidepanel view", hash.path[0]);
}
+
+ // Topic for MessagesView selector.
+ if (hash.path.length > 1 && hash.path[1] != this.state.topicSelected) {
+ this.setState({
+ topicSelected: Tinode.topicType(hash.path[1]) ? hash.path[1] : null
+ });
+ }
} else {
// Empty hashpath
this.setState({sidePanelSelected: ''});
}
- // Topic for MessagesView selector.
- if (hash.path.length > 1 && hash.path[1] != this.state.topicSelected) {
- var tp = Tinode.topicType(hash.path[1]);
- if (tp) {
- this.setState({
- topicSelected: hash.path[1],
- topicSelectedOnline: false,
- topicSelectedAcs: null
- });
- } else {
- this.setState({topicSelected: null});
- }
- }
// Save validation credentials, if available.
if (hash.params.method) {
@@ -4771,13 +4789,7 @@ class TinodeWeb extends React.Component {
// User clicked on a contact in the side panel or deleted a contact.
handleTopicSelected(topicName, unused_index, online, acs) {
- console.log("handleTopicSelected", topicName, online, acs);
-
if (topicName) {
- // Contact selected
- if (this.state.topicSelected != topicName) {
- navigateTo(setUrlTopic(window.location.hash, topicName));
- }
this.setState({
errorText: '',
errorLevel: null,
@@ -4786,10 +4798,11 @@ class TinodeWeb extends React.Component {
topicSelectedAcs: acs,
showInfoPanel: false
});
- } else {
- if (this.state.topicSelected) {
- navigateTo(setUrlTopic(window.location.hash, null));
+ // Contact selected
+ if (this.state.topicSelected != topicName) {
+ navigateTo(setUrlTopic("", topicName));
}
+ } else {
// Currently selected contact deleted
this.setState({
errorText: '',
@@ -4799,6 +4812,9 @@ class TinodeWeb extends React.Component {
topicSelectedAcs: null,
showInfoPanel: false
});
+ if (this.state.topicSelected) {
+ navigateTo(setUrlTopic("", null));
+ }
}
}
@@ -4926,24 +4942,29 @@ class TinodeWeb extends React.Component {
navigateTo(setUrlSidePanel(window.location.hash, 'newtpk'));
}
- // Create a new topic. New P2P topic requires peer's name.
+ // Request to start a new topic. New P2P topic requires peer's name.
handleNewTopicRequest(peerName, pub, priv, tags) {
- var topic = peerName ? this.state.tinode.newTopicWith(peerName) : this.state.tinode.newTopic();
- var query = topic.startMetaQuery().withDesc().withSub().withData();
- var setParams;
+ var topicName = peerName || this.state.tinode.newGroupTopicName();
if (!peerName) {
- // Creator is the owner, has access to tags.
- // Fetch default group topic tags, if any.
- query = query.withTags();
- setParams = {desc: {public: pub, private: priv}, tags: tags};
+ this.setState(
+ {newGroupTopicParams: {desc: {public: pub, private: priv}, tags: tags}},
+ () => {this.handleTopicSelected(topicName)}
+ );
+ } else {
+ this.handleTopicSelected(topicName);
+ }
+ }
+
+ // New topic was creted, here is the new topic name.
+ handleNewTopicCreated(oldName, newName) {
+ console.log("handleNewTopicCreated", oldName, newName);
+
+ if (this.state.topicSelected == oldName && oldName != newName) {
+ // If the current URl contains the old topic name, replace it with new.
+ // Update the name of the selected topic first so the navigator doen't clear
+ // the state.
+ this.setState({topicSelected: newName}, () => { navigateTo(setUrlTopic("", newName)); });
}
- topic.subscribe(query.build(), setParams).then(() => {
- navigateTo(setUrlSidePanel(window.location.hash, 'contacts'));
- this.handleTopicSelected(topic.name, undefined,
- this.state.tinode.isTopicOnline(topic.name), topic.getAccessMode());
- }).catch((err) => {
- this.handleError(err.message, "err");
- });
}
handleTopicUpdateRequest(topicName, pub, priv, permissions) {
@@ -5179,10 +5200,12 @@ class TinodeWeb extends React.Component {
serverAddress={this.state.serverAddress}
errorText={this.state.errorText}
errorLevel={this.state.errorLevel}
+ newGroupTopicParams={this.state.newGroupTopicParams}
onHideMessagesView={this.handleHideMessagesView}
onData={this.tnData}
onError={this.handleError}
+ onNewTopicCreated={this.handleNewTopicCreated}
readTimerHandler={this.handleReadTimer}
showContextMenu={this.handleShowContextMenu}
sendMessage={this.handleSendMessage} />