diff --git a/src/components/App.jsx b/src/components/App.jsx
index 2443d32..627ec2f 100644
--- a/src/components/App.jsx
+++ b/src/components/App.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import skygearChat from 'skygear-chat';
-import ManagedConversationList from '../utils/ManagedConversationList.jsx';
+import ManagedUserConversationList from '../utils/ManagedConversationList.jsx';
import Conversation from './Conversation.jsx';
import ConversationPreview from './ConversationPreview.jsx';
@@ -30,23 +30,15 @@ export default class App extends React.Component {
this.state = {
unreadCount: 0, // user's total unread message count (int)
currentModal: null, // currently displayed modal dialog name (or null)
- currentConversation: null // currently selected Conversion Record (or null)
+ activeID: null // currently selected UserConversion ID (or null)
};
- this.conversationList = new ManagedConversationList();
+ this.userConversationList = new ManagedUserConversationList();
}
componentDidMount() {
// subscribe conversation change
- this.conversationList.subscribe(() => {
- const {currentConversation} = this.state;
- const {conversationList} = this;
- if (currentConversation) {
- this.setState({
- currentConversation: conversationList.get(currentConversation._id)
- });
- } else {
- this.forceUpdate();
- }
+ this.userConversationList.subscribe(() => {
+ this.forceUpdate();
});
skygearChat.getUnreadCount().then(result => {
this.setState({unreadCount: result.message});
@@ -58,10 +50,11 @@ export default class App extends React.Component {
state: {
unreadCount,
currentModal,
- currentConversation
+ activeID
},
- conversationList
+ userConversationList
} = this;
+ const activeUC = userConversationList.get(activeID);
return (
{
- conversationList
- .map((c) => {
+ userConversationList
+ .map((uc) => {
return this.setState({currentConversation: c})}/>
+ uc.id === activeID}
+ userConversation={uc}
+ conversation={uc.$transient.conversation}
+ onClick={() => this.setState({activeID: uc._id})}/>
})
}
- {currentConversation &&
+ {activeID &&
this.setState({currentModal: 'details'})}/>
}
{(modal => {
@@ -111,13 +105,13 @@ export default class App extends React.Component {
case 'createGroup':
return (
conversationList.add(c)}
+ addConversationDelegate={c => userConversationList.addConversation(c)}
onClose={() => this.setState({currentModal: null})}/>
);
case 'createChat':
return (
conversationList.add(c)}
+ addConversationDelegate={c => userConversationList.addConversation(c)}
onClose={() => this.setState({currentModal: null})}/>
);
case 'settings':
@@ -128,11 +122,10 @@ export default class App extends React.Component {
case 'details':
return (
conversationList.update(c)}
- removeConversationDelegate={id => conversationList.remove(id)}
+ key={'DetailsModal-' + activeID.id}
+ conversation={activeUC.$transient.conversation}
+ updateConversationDelegate={c => userConversationList.updateConversation(c)}
+ removeConversationDelegate={c => userConversationList.removeConversation(c)}
onClose={() => this.setState({currentModal: null})}/>
);
default:
diff --git a/src/components/ConversationPreview.jsx b/src/components/ConversationPreview.jsx
index fe02f1e..f05a887 100644
--- a/src/components/ConversationPreview.jsx
+++ b/src/components/ConversationPreview.jsx
@@ -8,7 +8,7 @@ export default class ConversationPreview extends React.Component {
super(props);
const {title} = props.conversation;
this.state = {
- title: title || 'loading...', // conversation title (either group name or participant names)
+ title: title || 'loading...', // conversation title (either group name or participant names)
imageURL: 'img/loading.svg' // conversation image URL
};
}
@@ -43,23 +43,17 @@ export default class ConversationPreview extends React.Component {
}
render() {
const {
- props: {
- selected,
- onClick,
- conversation: {
- unread_count,
- $transient: {
- last_message: {
- body: lastMessage
- } = {}
- }
- }
- },
- state: {
- title,
- imageURL
- }
- } = this;
+ selected,
+ onClick,
+ } = this.props;
+ const {
+ unread_count
+ } = this.props.userConversation;
+ const {
+ title,
+ imageURL
+ } = this.state;
+ const lastMessage = this.props.conversation.$transient.last_message;
return (
- { lastMessage.length > 23 ?
- lastMessage.substring(0, 20) + '...' : lastMessage }
+ { lastMessage.body.length > 23 ?
+ lastMessage.body.substring(0, 20) + '...' : lastMessage.body }
}
diff --git a/src/components/DetailsModal.jsx b/src/components/DetailsModal.jsx
index c754522..e13d51a 100644
--- a/src/components/DetailsModal.jsx
+++ b/src/components/DetailsModal.jsx
@@ -77,7 +77,7 @@ export default class DetailsModal extends React.Component {
).then(() => {
// close modal after leaving
onClose();
- removeConversationDelegate(conversation._id);
+ removeConversationDelegate(conversation);
});
}
discoverAndAddUser(username) {
diff --git a/src/utils/ManagedConversationList.jsx b/src/utils/ManagedConversationList.jsx
index a103ade..6a514f9 100644
--- a/src/utils/ManagedConversationList.jsx
+++ b/src/utils/ManagedConversationList.jsx
@@ -50,10 +50,10 @@ export class ConversationSorting {
}
/**
- * A managed list of conversations for the current user.
- * Note: You must be logged in to use this.
+ * A managed list of user conversations for the current user.
+ * Note: You must be logged in at skygear to use this.
*/
-export default class ManagedConversationList {
+export default class ManagedUserConversationList {
/**
* @param {object} [options={}]
* @param {boolean} [options.initialFetch=true]
@@ -73,8 +73,10 @@ export default class ManagedConversationList {
this._compare = sortBy;
// conversation IDs in order (without type prefix)
this._orderedIDs = [];
- // map of conversaton ID => conversation object
- this._conversations = {};
+ // map of user conversaton ID => user conversation object
+ this._userConversations = {};
+ // map of conversaton ID => user conversation object
+ this._ucByCId = {};
// map of subscription ID => event handler
this._updateHandlers = {};
@@ -100,13 +102,13 @@ export default class ManagedConversationList {
console.log('[conversation event]', event);
switch (event.event_type) {
case 'create':
- this.add(event.record);
+ this.addConversation(event.record);
break;
case 'update':
- this.update(event.record);
+ this.updateConversation(event.record);
break;
case 'delete':
- this.remove(event.record._id);
+ this.removeConversation(event.record);
break;
}
}
@@ -114,10 +116,10 @@ export default class ManagedConversationList {
/**
* @private
*/
- _conversationsUpdated() {
- const {_conversations, _compare, _updateHandlers} = this;
- this._orderedIDs = Object.keys(_conversations)
- .map(id => _conversations[id])
+ _userConversationsUpdated() {
+ const {_userConversations, _compare, _updateHandlers} = this;
+ this._orderedIDs = Object.keys(_userConversations)
+ .map(id => _userConversations[id])
.sort(_compare)
.map(conversation => conversation._id);
Object.keys(_updateHandlers)
@@ -125,19 +127,20 @@ export default class ManagedConversationList {
.forEach(handler => handler(this));
}
/**
- * Fetches list of conversations from the server.
- * @return {Promise}
+ * Fetches list of user conversations from the server.
+ * @return {Promise}
* Promise of this object, resolves if the fetch is successful.
*/
fetch() {
return skygearChat
- .getConversations()
+ .getUserConversations()
.then(results => {
- console.log('[fetched conversations]', results);
- results.forEach(conversation => {
- this._conversations[conversation._id] = conversation;
+ console.log('[fetched user conversations]', results);
+ results.forEach((uc) => {
+ this._userConversations[uc._id] = uc;
+ this._ucByCId[uc.$transient.conversation._id] = uc;
});
- this._conversationsUpdated();
+ this._userConversationsUpdated();
return this;
});
}
@@ -149,17 +152,17 @@ export default class ManagedConversationList {
return this._orderedIDs.length;
}
/**
- * Get a Conversation
+ * Get a User Conversation
* @param {number|string} indexOrID
* Either the list index (number) or conversation ID (string) without type prefix.
* @return {Conversation}
*/
get(indexOrID) {
- const {_conversations, _orderedIDs} = this;
+ const {_userConversations, _orderedIDs} = this;
if (typeof indexOrID === 'number') {
- return _conversations[_orderedIDs[indexOrID]];
+ return _userConversations[_orderedIDs[indexOrID]];
} else {
- return _conversations[indexOrID];
+ return _userConversations[indexOrID];
}
}
/**
@@ -169,7 +172,7 @@ export default class ManagedConversationList {
*/
map(mappingFunction) {
return this._orderedIDs
- .map(id => this._conversations[id])
+ .map(id => this._userConversations[id])
.map(mappingFunction);
}
/**
@@ -179,51 +182,68 @@ export default class ManagedConversationList {
*/
filter(predicate) {
return this._orderedIDs
- .map(id => this._conversations[id])
+ .map(id => this._userConversations[id])
.filter(predicate);
}
/**
* Add a conversation, no-op if the conversation already exists.
* @param {Conversation} conversation
- * @return {ManagedConversationList}
+ * @return {ManagedUserConversationList}
*/
- add(conversation) {
- const {_conversations} = this;
- if (!_conversations.hasOwnProperty(conversation._id)) {
- _conversations[conversation._id] = conversation;
- this._conversationsUpdated();
+ addConversation(conversation) {
+ const {
+ _userConversations,
+ _ucByCId
+ } = this;
+ if (_ucByCId.hasOwnProperty(conversation._id)) {
+ return this;
}
+ skygearChat
+ .getUserConversation(conversation)
+ .then((uc) => {
+ _userConversations[uc._id] = uc;
+ _ucByCId[conversation._id] = uc;
+ this._userConversationsUpdated();
+ });
return this;
}
/**
* Update a conversation, no-op if the conversation updatedAt date is older than existing.
* Conversation will be added if it's not in the list.
* @param {Conversation} conversation
- * @return {ManagedConversationList}
+ * @return {ManagedUserConversationList}
*/
- update(conversation) {
- const {_conversations} = this;
- if (
- _conversations.hasOwnProperty(conversation._id) &&
- conversation.updatedAt >= _conversations[conversation._id].updatedAt
- ) {
- _conversations[conversation._id] = conversation;
- this._conversationsUpdated();
+ updateConversation(conversation) {
+ const {_ucByCId} = this;
+ if (_ucByCId.hasOwnProperty(conversation._id)) {
+ const uc = _ucByCId[conversation._id];
+ const c = uc.$transient.conversation;
+ if (conversation.updatedAt <= c.updatedAt) {
+ return this
+ }
+ uc.$transient.conversation = conversation;
+ this._userConversationsUpdated();
} else {
- this.add(conversation);
+ this.addConversation(conversation);
}
return this;
}
/**
* Remove a conversation, no-op if the conversation doesn't exist.
- * @param {string} conversationID Conversation ID without type prefix.
- * @return {ManagedConversationList}
+ * @param {conversation} conversation Conversation without type prefix.
+ * @return {ManagedUserConversationList}
*/
- remove(conversationID) {
- const {_conversations} = this;
- if (_conversations.hasOwnProperty(conversationID)) {
- delete _conversations[conversationID];
- this._conversationsUpdated();
+ removeConversation(conversation) {
+ const {
+ _userConversations,
+ _ucByCId
+ } = this;
+ const conversationID = conversation._id;
+ if (_ucById.hasOwnProperty(conversationID)) {
+ const uc = _ucByCId[conversationID]
+ delete _userConversations[uc._id];
+ delete _ucById[conversationID];
+ this._userConversationsUpdated();
}
return this;
}