@chatscope/use-chat
Version:
React hook for state management in chat applications
339 lines • 11.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BasicStorage = void 0;
const MessageGroup_1 = require("./MessageGroup");
const _1 = require("./");
class BasicStorage {
/**
* Constructor
* @param messageIdGenerator
* @param groupIdGenerator
*/
constructor({ groupIdGenerator, messageIdGenerator }) {
// TODO: Users by Id
this.users = [];
// TODO: Conversations By Id (Dedicated conversations collection)
this.conversations = [];
this.messages = {};
this.currentMessage = "";
this._groupIdGenerator = groupIdGenerator;
this._messageIdGenerator = messageIdGenerator;
}
get groupIdGenerator() {
return this._groupIdGenerator;
}
get messageIdGenerator() {
return this._messageIdGenerator;
}
getMessageWithId(message, generateId) {
if (generateId) {
if (!this.messageIdGenerator) {
throw "Id generator is not defined";
}
else {
return Object.assign(Object.assign({}, message), { id: this.messageIdGenerator(message) });
}
}
else {
return message;
}
}
/**
* Check if user exists in users collection
* @param userId
*/
userExists(userId) {
return this.users.findIndex((u) => u.id === userId) !== -1;
}
/**
* Sets current (logged in) user object
* @param user
*/
setCurrentUser(user) {
this.currentUser = user;
}
/**
* Add user to collection of users.
* User will be added only when item with its id not exists in the collection.
* @param user
*/
addUser(user) {
const notExists = !this.userExists(user.id);
if (notExists) {
this.users = this.users.concat(user);
}
return notExists;
}
/**
* Remove user from users collection.
* If the participant existed and has been removed, it returns true, otherwise it returns false
* @param userId
*/
removeUser(userId) {
const idx = this.users.findIndex((u) => u.id === userId);
if (idx !== -1) {
this.users = this.users.slice(0, idx).concat(this.users.slice(idx + 1));
return true;
}
return false;
}
/**
* Get user by id
* @param userId
* @return [User, number]|[undefined,undefined]
*/
getUser(userId) {
const idx = this.users.findIndex((u) => u.id === userId);
if (idx !== -1) {
return [this.users[idx], idx];
}
return [undefined, undefined];
}
/**
* Checks if conversation exists
* @param conversationId
*/
conversationExists(conversationId) {
return this.conversations.findIndex((c) => c.id === conversationId) !== -1;
}
/**
* Get conversation
* @param conversationId
* @return [Conversation, number]|[undefined, undefined]
*/
getConversation(conversationId) {
const idx = this.conversations.findIndex((c) => c.id === conversationId);
if (idx !== -1) {
return [this.conversations[idx], idx];
}
return [undefined, undefined];
}
/**
* Add conversation to collection of conversations.
* Conversation will be added only when item with its id not exists in the collection.
* @param conversation
*/
addConversation(conversation) {
const notExists = !this.conversationExists(conversation.id);
if (notExists) {
this.conversations = this.conversations.concat(conversation);
}
return notExists;
}
/**
* Set unread messages for conversation
* @param conversationId
* @param count
*/
setUnread(conversationId, count) {
const [conversation] = this.getConversation(conversationId);
if (conversation) {
conversation.unreadCounter = count;
}
}
/**
* Remove conversation from conversations collection.
* If the conversation existed and has been removed, it returns true, otherwise it returns false
* @param conversationId
* @param removeMessages
*/
removeConversation(conversationId, removeMessages = true) {
const idx = this.conversations.findIndex((c) => c.id === conversationId);
if (idx !== -1) {
this.conversations = this.conversations
.slice(0, idx)
.concat(this.conversations.slice(idx + 1));
if (removeMessages) {
delete this.messages[conversationId];
}
return true;
}
return false;
}
/**
* Replace the conversation in the collection with the new one specified in the parameter
* @param conversation
*/
updateConversation(conversation) {
const [con, idx] = this.getConversation(conversation.id);
if (con) {
this.replaceConversation(conversation, idx);
}
}
replaceConversation(conversation, idx) {
this.conversations = this.conversations
.slice(0, idx)
.concat(new _1.Conversation({
id: conversation.id,
participants: conversation.participants,
typingUsers: conversation.typingUsers,
unreadCounter: conversation.unreadCounter,
draft: conversation.draft,
description: conversation.description,
readonly: conversation.readonly,
data: conversation.data,
}))
.concat(this.conversations.slice(idx + 1));
}
replaceUser(user, idx) {
this.users = this.users
.slice(0, idx)
.concat(user)
.concat(this.users.slice(idx + 1));
}
/**
* Add participant to the conversation only if not already added and conversation exists.
* Returns true if participant has been added, otherwise returns false.
* @param conversationId
* @param participant
* @return boolean
*/
addParticipant(conversationId, participant) {
const [conversation, idx] = this.getConversation(conversationId);
if (conversation) {
if (conversation.addParticipant(participant)) {
this.replaceConversation(conversation, idx);
}
}
return false;
}
/**
* Remove participant from conversation.
* If the participant existed and has been removed, it returns true, otherwise it returns false
* @param conversationId
* @param participantId
*/
removeParticipant(conversationId, participantId) {
const [conversation, idx] = this.getConversation(conversationId);
if (conversation) {
conversation.removeParticipant(participantId);
this.replaceConversation(conversation, idx);
return true;
}
return false;
}
addMessage(message, conversationId, generateId = false) {
if (conversationId in this.messages) {
const groups = this.messages[conversationId];
const lastGroup = groups[groups.length - 1];
if (lastGroup.senderId === message.senderId) {
// Add message to group
const newMessage = this.getMessageWithId(message, generateId);
lastGroup.addMessage(newMessage);
return newMessage;
}
}
const group = new MessageGroup_1.MessageGroup({
id: this.groupIdGenerator(),
senderId: message.senderId,
direction: message.direction,
});
const newMessage = this.getMessageWithId(message, generateId);
group.addMessage(newMessage);
this.messages[conversationId] =
conversationId in this.messages
? this.messages[conversationId].concat(group)
: [group];
return newMessage;
}
// TODO: Refactoring - it's not very optimal :)
/**
* Update message
* @param message
*/
updateMessage(message) {
for (const conversationId in this.messages) {
const groups = this.messages[conversationId];
const l = groups.length;
for (let i = 0; i < l; i++) {
const group = groups[i];
const [currentMessage, idx] = group.getMessage(message.id);
if (currentMessage) {
group.replaceMessage(message, idx);
}
}
}
}
/**
* Set user presence
* @param userId
* @param presence
*/
setPresence(userId, presence) {
const [user, idx] = this.getUser(userId);
if (user) {
user.presence = presence;
this.replaceUser(user, idx);
}
}
/**
* Set draft of message in current conversation
* @param {String} draft
*/
setDraft(draft) {
if (this.activeConversationId) {
const [activeConversation, idx] = this.getConversation(this.activeConversationId);
if (activeConversation) {
activeConversation.draft = draft;
this.replaceConversation(activeConversation, idx);
}
}
}
clearState() { }
getState() {
return {
currentUser: this.currentUser,
users: this.users,
conversations: this.conversations,
// TODO: Implement sth like collection referencing by id (map with guaranteed order like in immutablejs) because searching every time in the array does not make sense
activeConversation: this.activeConversationId
? this.conversations.find((c) => c.id === this.activeConversationId)
: undefined,
currentMessages: this.activeConversationId && this.activeConversationId in this.messages
? this.messages[this.activeConversationId]
: [],
messages: this.messages,
currentMessage: this.currentMessage,
};
}
resetState() {
this.currentUser = undefined;
this.users = [];
this.conversations = [];
this.activeConversationId = undefined;
this.messages = {};
}
/**
* Set active conversation and reset unread counter of this conversation if second parameter is set.
* Why active conversation is kept here in storage?
* Because it's easy to persist whole storage and recreate from persistent state.
* @param conversationId
* @param resetUnreadCounter
*/
setActiveConversation(conversationId, resetUnreadCounter = true) {
this.activeConversationId = conversationId;
if (resetUnreadCounter && conversationId) {
const [conversation, idx] = this.getConversation(conversationId);
if (conversation) {
conversation.unreadCounter = 0;
this.replaceConversation(conversation, idx);
}
}
}
/**
* Set current message input value
* @param message
*/
setCurrentMessage(message) {
this.currentMessage = message;
}
/**
* Remove all the messages from the conversation
* @param conversationId
*/
removeMessagesFromConversation(conversationId) {
delete this.messages[conversationId];
}
}
exports.BasicStorage = BasicStorage;
//# sourceMappingURL=BasicStorage.js.map