add backend for message reactions
This commit is contained in:
Vendored
+117
-1
@@ -603,6 +603,10 @@
|
|||||||
info: (id) => [...filePaths.chat.chatBase(id), "info"],
|
info: (id) => [...filePaths.chat.chatBase(id), "info"],
|
||||||
color: (id) => [...filePaths.chat.chatBase(id), "color"],
|
color: (id) => [...filePaths.chat.chatBase(id), "color"],
|
||||||
messages: (id) => [...filePaths.chat.chatBase(id), "messages"],
|
messages: (id) => [...filePaths.chat.chatBase(id), "messages"],
|
||||||
|
reactions: (id) => [
|
||||||
|
...filePaths.chat.chatBase(id),
|
||||||
|
"reactions"
|
||||||
|
],
|
||||||
lastUsedPage: (id) => [
|
lastUsedPage: (id) => [
|
||||||
...filePaths.chat.chatBase(id),
|
...filePaths.chat.chatBase(id),
|
||||||
"last-used-page"
|
"last-used-page"
|
||||||
@@ -1037,6 +1041,7 @@
|
|||||||
const didStore = this.storeFileContent(fileContent);
|
const didStore = this.storeFileContent(fileContent);
|
||||||
if (didStore == false) return;
|
if (didStore == false) return;
|
||||||
this.boardsAndTasksModel.handleFileContent(fileContent);
|
this.boardsAndTasksModel.handleFileContent(fileContent);
|
||||||
|
this.chatModel.handleReaction(fileContent);
|
||||||
};
|
};
|
||||||
// methods
|
// methods
|
||||||
this.addFileContentAndSend = (fileContent) => {
|
this.addFileContentAndSend = (fileContent) => {
|
||||||
@@ -1203,6 +1208,7 @@
|
|||||||
// init
|
// init
|
||||||
constructor(storageModel2, connectionModel2, settingsModel2, chatListModel2, chatId) {
|
constructor(storageModel2, connectionModel2, settingsModel2, chatListModel2, chatId) {
|
||||||
this.chatMessageHandlerManager = new HandlerManager();
|
this.chatMessageHandlerManager = new HandlerManager();
|
||||||
|
this.reactionHandlerManager = new HandlerManager();
|
||||||
// paths
|
// paths
|
||||||
this.getBasePath = () => {
|
this.getBasePath = () => {
|
||||||
return StorageModel.getPath(
|
return StorageModel.getPath(
|
||||||
@@ -1231,6 +1237,15 @@
|
|||||||
this.getMessagePath = (id) => {
|
this.getMessagePath = (id) => {
|
||||||
return [...this.getMessageDirPath(), id];
|
return [...this.getMessageDirPath(), id];
|
||||||
};
|
};
|
||||||
|
this.getReactionDirPath = () => {
|
||||||
|
return StorageModel.getPath(
|
||||||
|
"chat" /* Chat */,
|
||||||
|
filePaths.chat.reactions(this.id)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
this.getReactionPath = (id) => {
|
||||||
|
return [...this.getReactionDirPath(), id];
|
||||||
|
};
|
||||||
// handlers
|
// handlers
|
||||||
this.handleMessage = (body) => {
|
this.handleMessage = (body) => {
|
||||||
const chatMessage = parseValidObject(
|
const chatMessage = parseValidObject(
|
||||||
@@ -1242,6 +1257,10 @@
|
|||||||
this.addMessage(chatMessage);
|
this.addMessage(chatMessage);
|
||||||
this.setReadStatus(true);
|
this.setReadStatus(true);
|
||||||
};
|
};
|
||||||
|
this.handleReaction = (reaction) => {
|
||||||
|
if (!checkMatchesObjectStructure(reaction, ChatMessageReactionReference)) return;
|
||||||
|
this.addReaction(reaction);
|
||||||
|
};
|
||||||
this.handleMessageSent = (chatMessage) => {
|
this.handleMessageSent = (chatMessage) => {
|
||||||
chatMessage.status = "sent" /* Sent */;
|
chatMessage.status = "sent" /* Sent */;
|
||||||
this.addMessage(chatMessage);
|
this.addMessage(chatMessage);
|
||||||
@@ -1276,7 +1295,12 @@
|
|||||||
chatMessage.stringifiedFile
|
chatMessage.stringifiedFile
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
this.sendMessage = async (body, fileContent) => {
|
this.addReaction = async (reaction) => {
|
||||||
|
const reactionPath = this.getReactionPath(reaction.fileId);
|
||||||
|
this.storageModel.writeStringifiable(reactionPath, reaction);
|
||||||
|
this.reactionHandlerManager.trigger(reaction);
|
||||||
|
};
|
||||||
|
this.getNameAndChannel = () => {
|
||||||
const senderName = this.settingsModel.username;
|
const senderName = this.settingsModel.username;
|
||||||
if (senderName == "") return false;
|
if (senderName == "") return false;
|
||||||
const allChannels = [this.info.primaryChannel];
|
const allChannels = [this.info.primaryChannel];
|
||||||
@@ -1284,6 +1308,12 @@
|
|||||||
allChannels.push(secondaryChannel);
|
allChannels.push(secondaryChannel);
|
||||||
}
|
}
|
||||||
const combinedChannel = allChannels.join("/");
|
const combinedChannel = allChannels.join("/");
|
||||||
|
return [senderName, combinedChannel];
|
||||||
|
};
|
||||||
|
this.sendMessage = async (body, fileContent) => {
|
||||||
|
const nameAndChannel = this.getNameAndChannel();
|
||||||
|
if (nameAndChannel == false) return;
|
||||||
|
const [senderName, combinedChannel] = nameAndChannel;
|
||||||
const chatMessage = await _ChatModel.createChatMessage(
|
const chatMessage = await _ChatModel.createChatMessage(
|
||||||
combinedChannel,
|
combinedChannel,
|
||||||
senderName,
|
senderName,
|
||||||
@@ -1307,6 +1337,18 @@
|
|||||||
chatMessage.body = decryptedBody;
|
chatMessage.body = decryptedBody;
|
||||||
chatMessage.stringifiedFile = decryptedFile;
|
chatMessage.stringifiedFile = decryptedFile;
|
||||||
};
|
};
|
||||||
|
this.sendReaction = async (messageId, content) => {
|
||||||
|
const nameAndChannel = this.getNameAndChannel();
|
||||||
|
if (nameAndChannel == false) return;
|
||||||
|
const [senderName, combinedChannel] = nameAndChannel;
|
||||||
|
const reaction = _ChatModel.createMessageReaction(
|
||||||
|
messageId,
|
||||||
|
senderName,
|
||||||
|
content
|
||||||
|
);
|
||||||
|
this.sendMessage("", reaction);
|
||||||
|
this.addReaction(reaction);
|
||||||
|
};
|
||||||
this.subscribe = () => {
|
this.subscribe = () => {
|
||||||
this.connectionModel.addChannel(this.info.primaryChannel);
|
this.connectionModel.addChannel(this.info.primaryChannel);
|
||||||
};
|
};
|
||||||
@@ -1376,6 +1418,7 @@
|
|||||||
messagePath,
|
messagePath,
|
||||||
ChatMessageReference
|
ChatMessageReference
|
||||||
);
|
);
|
||||||
|
if (chatMessage == null) continue;
|
||||||
chatMessages.push(chatMessage);
|
chatMessages.push(chatMessage);
|
||||||
}
|
}
|
||||||
const sorted = chatMessages.sort(
|
const sorted = chatMessages.sort(
|
||||||
@@ -1383,6 +1426,23 @@
|
|||||||
);
|
);
|
||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
|
get reactions() {
|
||||||
|
const reactionIds = this.storageModel.list(
|
||||||
|
this.getReactionDirPath()
|
||||||
|
);
|
||||||
|
if (!Array.isArray(reactionIds)) return [];
|
||||||
|
const reactions = [];
|
||||||
|
for (const reactionId of reactionIds) {
|
||||||
|
const reactionPath = this.getReactionPath(reactionId);
|
||||||
|
const reaction = this.storageModel.readStringifiable(
|
||||||
|
reactionPath,
|
||||||
|
ChatMessageReactionReference
|
||||||
|
);
|
||||||
|
if (reaction == null) continue;
|
||||||
|
reactions.push(reaction);
|
||||||
|
}
|
||||||
|
return reactions;
|
||||||
|
}
|
||||||
// utility
|
// utility
|
||||||
static splitChannel(channelString) {
|
static splitChannel(channelString) {
|
||||||
return channelString.split("/");
|
return channelString.split("/");
|
||||||
@@ -1427,6 +1487,18 @@
|
|||||||
return chatMessage;
|
return chatMessage;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
static {
|
||||||
|
this.createMessageReaction = (messageId, sender, content) => {
|
||||||
|
const fileContent = FileModel2.createFileContent(v4_default(), "reaction");
|
||||||
|
const reaction = {
|
||||||
|
...fileContent,
|
||||||
|
messageId,
|
||||||
|
sender,
|
||||||
|
content
|
||||||
|
};
|
||||||
|
return reaction;
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
var ChatInfoReference = {
|
var ChatInfoReference = {
|
||||||
dataVersion: DATA_VERSION,
|
dataVersion: DATA_VERSION,
|
||||||
@@ -1445,6 +1517,16 @@
|
|||||||
status: "",
|
status: "",
|
||||||
stringifiedFile: ""
|
stringifiedFile: ""
|
||||||
};
|
};
|
||||||
|
var ChatMessageReactionReference = {
|
||||||
|
dataVersion: DATA_VERSION,
|
||||||
|
fileId: "",
|
||||||
|
fileContentId: "",
|
||||||
|
creationDate: "",
|
||||||
|
type: "reaction",
|
||||||
|
messageId: "",
|
||||||
|
sender: "",
|
||||||
|
content: ""
|
||||||
|
};
|
||||||
|
|
||||||
// src/Model/Chat/chatListModel.ts
|
// src/Model/Chat/chatListModel.ts
|
||||||
var ChatListModel = class {
|
var ChatListModel = class {
|
||||||
@@ -1923,6 +2005,11 @@
|
|||||||
this.status = new State(
|
this.status = new State(
|
||||||
void 0
|
void 0
|
||||||
);
|
);
|
||||||
|
this.reactionsThumbsUp = new MapState();
|
||||||
|
this.reactionsCheck = new MapState();
|
||||||
|
this.reactionsAttention = new MapState();
|
||||||
|
this.reactionsDoubleAttention = new MapState();
|
||||||
|
this.reactionsQuestion = new MapState();
|
||||||
// state
|
// state
|
||||||
this.isPresentingInfoModal = new State(false);
|
this.isPresentingInfoModal = new State(false);
|
||||||
// methods
|
// methods
|
||||||
@@ -1942,6 +2029,21 @@
|
|||||||
this.hideInfoModal = () => {
|
this.hideInfoModal = () => {
|
||||||
this.isPresentingInfoModal.value = false;
|
this.isPresentingInfoModal.value = false;
|
||||||
};
|
};
|
||||||
|
// reactions
|
||||||
|
this.addReaction = (reaction) => {
|
||||||
|
switch (reaction.content) {
|
||||||
|
case "\u{1F44D}":
|
||||||
|
return this.reactionsThumbsUp.set(reaction.fileId, reaction);
|
||||||
|
case "\u2705":
|
||||||
|
return this.reactionsCheck.set(reaction.fileId, reaction);
|
||||||
|
case "\u2757\uFE0F":
|
||||||
|
return this.reactionsAttention.set(reaction.fileId, reaction);
|
||||||
|
case "\u203C\uFE0F":
|
||||||
|
return this.reactionsDoubleAttention.set(reaction.fileId, reaction);
|
||||||
|
case "\u2753":
|
||||||
|
return this.reactionsQuestion.set(reaction.fileId, reaction);
|
||||||
|
}
|
||||||
|
};
|
||||||
// load
|
// load
|
||||||
this.loadData = () => {
|
this.loadData = () => {
|
||||||
this.channel = this.chatMessage.channel;
|
this.channel = this.chatMessage.channel;
|
||||||
@@ -1980,6 +2082,9 @@
|
|||||||
this.chatViewModel.chatModel.addMessage(chatMessage);
|
this.chatViewModel.chatModel.addMessage(chatMessage);
|
||||||
messageViewModel.loadData();
|
messageViewModel.loadData();
|
||||||
};
|
};
|
||||||
|
this.sendReaction = (messageId, content) => {
|
||||||
|
this.chatViewModel.chatModel.sendReaction(messageId, content);
|
||||||
|
};
|
||||||
// view
|
// view
|
||||||
this.showChatMessage = (chatMessage) => {
|
this.showChatMessage = (chatMessage) => {
|
||||||
const chatMessageViewModel = new ChatMessageViewModel(
|
const chatMessageViewModel = new ChatMessageViewModel(
|
||||||
@@ -1999,12 +2104,20 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
this.showReaction = (reaction) => {
|
||||||
|
const messageViewModel = this.chatMessageViewModels.value.get(reaction.messageId);
|
||||||
|
if (messageViewModel == void 0) return;
|
||||||
|
messageViewModel.addReaction(reaction);
|
||||||
|
};
|
||||||
// load
|
// load
|
||||||
this.loadData = () => {
|
this.loadData = () => {
|
||||||
this.chatMessageViewModels.clear();
|
this.chatMessageViewModels.clear();
|
||||||
for (const chatMessage of this.chatViewModel.chatModel.messages) {
|
for (const chatMessage of this.chatViewModel.chatModel.messages) {
|
||||||
this.showChatMessage(chatMessage);
|
this.showChatMessage(chatMessage);
|
||||||
}
|
}
|
||||||
|
for (const reaction of this.chatViewModel.chatModel.reactions) {
|
||||||
|
this.showReaction(reaction);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
this.chatViewModel = chatViewModel;
|
this.chatViewModel = chatViewModel;
|
||||||
this.cannotSendMessage = createProxyState(
|
this.cannotSendMessage = createProxyState(
|
||||||
@@ -3149,6 +3262,9 @@
|
|||||||
this.notificationViewModel.showNotification(chatMessage);
|
this.notificationViewModel.showNotification(chatMessage);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
chatModel.reactionHandlerManager.addHandler((reaction) => {
|
||||||
|
this.messagePageViewModel.showReaction(reaction);
|
||||||
|
});
|
||||||
this.loadPageSelection();
|
this.loadPageSelection();
|
||||||
this.resetColor();
|
this.resetColor();
|
||||||
this.loadInfo();
|
this.loadInfo();
|
||||||
|
|||||||
+124
-7
@@ -1,11 +1,16 @@
|
|||||||
// this file is responsible for managing chats.
|
// this file is responsible for managing chats.
|
||||||
|
|
||||||
import { DATA_VERSION, ValidObject } from "../Utility/typeSafety";
|
import {
|
||||||
|
checkMatchesObjectStructure,
|
||||||
|
DATA_VERSION,
|
||||||
|
ValidObject,
|
||||||
|
} from "../Utility/typeSafety";
|
||||||
import FileModel, { FileContent } from "../Files/fileModel";
|
import FileModel, { FileContent } from "../Files/fileModel";
|
||||||
import {
|
import {
|
||||||
HandlerManager,
|
HandlerManager,
|
||||||
createTimestamp,
|
createTimestamp,
|
||||||
localeCompare,
|
localeCompare,
|
||||||
|
parse,
|
||||||
parseValidObject,
|
parseValidObject,
|
||||||
stringify,
|
stringify,
|
||||||
} from "../Utility/utility";
|
} from "../Utility/utility";
|
||||||
@@ -36,6 +41,8 @@ export default class ChatModel {
|
|||||||
|
|
||||||
chatMessageHandlerManager: HandlerManager<ChatMessage> =
|
chatMessageHandlerManager: HandlerManager<ChatMessage> =
|
||||||
new HandlerManager();
|
new HandlerManager();
|
||||||
|
reactionHandlerManager: HandlerManager<ChatMessageReaction> =
|
||||||
|
new HandlerManager();
|
||||||
|
|
||||||
get secondaryChannels(): string[] {
|
get secondaryChannels(): string[] {
|
||||||
return this.info.secondaryChannels.sort(localeCompare);
|
return this.info.secondaryChannels.sort(localeCompare);
|
||||||
@@ -74,6 +81,17 @@ export default class ChatModel {
|
|||||||
return [...this.getMessageDirPath(), id];
|
return [...this.getMessageDirPath(), id];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getReactionDirPath = (): string[] => {
|
||||||
|
return StorageModel.getPath(
|
||||||
|
StorageModelSubPath.Chat,
|
||||||
|
filePaths.chat.reactions(this.id),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
getReactionPath = (id: string): string[] => {
|
||||||
|
return [...this.getReactionDirPath(), id];
|
||||||
|
};
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
handleMessage = (body: string): void => {
|
handleMessage = (body: string): void => {
|
||||||
const chatMessage: ChatMessage | null = parseValidObject(
|
const chatMessage: ChatMessage | null = parseValidObject(
|
||||||
@@ -83,11 +101,19 @@ export default class ChatModel {
|
|||||||
if (chatMessage == null) return;
|
if (chatMessage == null) return;
|
||||||
|
|
||||||
chatMessage.status = ChatMessageStatus.Received;
|
chatMessage.status = ChatMessageStatus.Received;
|
||||||
this.addMessage(chatMessage);
|
|
||||||
|
|
||||||
|
this.addMessage(chatMessage);
|
||||||
this.setReadStatus(true);
|
this.setReadStatus(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleReaction = (reaction: ChatMessageReaction | any): void => {
|
||||||
|
if (
|
||||||
|
!checkMatchesObjectStructure(reaction, ChatMessageReactionReference)
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
this.addReaction(reaction);
|
||||||
|
};
|
||||||
|
|
||||||
handleMessageSent = (chatMessage: ChatMessage): void => {
|
handleMessageSent = (chatMessage: ChatMessage): void => {
|
||||||
chatMessage.status = ChatMessageStatus.Sent;
|
chatMessage.status = ChatMessageStatus.Sent;
|
||||||
this.addMessage(chatMessage);
|
this.addMessage(chatMessage);
|
||||||
@@ -132,10 +158,13 @@ export default class ChatModel {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
sendMessage = async (
|
addReaction = async (reaction: ChatMessageReaction): Promise<void> => {
|
||||||
body: string,
|
const reactionPath: string[] = this.getReactionPath(reaction.fileId);
|
||||||
fileContent?: FileContent<string>,
|
this.storageModel.writeStringifiable(reactionPath, reaction);
|
||||||
): Promise<boolean> => {
|
this.reactionHandlerManager.trigger(reaction);
|
||||||
|
};
|
||||||
|
|
||||||
|
getNameAndChannel = (): [string, string] | false => {
|
||||||
const senderName = this.settingsModel.username;
|
const senderName = this.settingsModel.username;
|
||||||
if (senderName == "") return false;
|
if (senderName == "") return false;
|
||||||
|
|
||||||
@@ -146,6 +175,17 @@ export default class ChatModel {
|
|||||||
|
|
||||||
const combinedChannel: string = allChannels.join("/");
|
const combinedChannel: string = allChannels.join("/");
|
||||||
|
|
||||||
|
return [senderName, combinedChannel];
|
||||||
|
};
|
||||||
|
|
||||||
|
sendMessage = async (
|
||||||
|
body: string,
|
||||||
|
fileContent?: FileContent<string>,
|
||||||
|
): Promise<boolean> => {
|
||||||
|
const nameAndChannel = this.getNameAndChannel();
|
||||||
|
if (nameAndChannel == false) return;
|
||||||
|
const [senderName, combinedChannel] = nameAndChannel;
|
||||||
|
|
||||||
const chatMessage: ChatMessage = await ChatModel.createChatMessage(
|
const chatMessage: ChatMessage = await ChatModel.createChatMessage(
|
||||||
combinedChannel,
|
combinedChannel,
|
||||||
senderName,
|
senderName,
|
||||||
@@ -172,6 +212,23 @@ export default class ChatModel {
|
|||||||
chatMessage.stringifiedFile = decryptedFile;
|
chatMessage.stringifiedFile = decryptedFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sendReaction = async (
|
||||||
|
messageId: string,
|
||||||
|
content: ReactionSymbol,
|
||||||
|
): Promise<void> => {
|
||||||
|
const nameAndChannel = this.getNameAndChannel();
|
||||||
|
if (nameAndChannel == false) return;
|
||||||
|
const [senderName, combinedChannel] = nameAndChannel;
|
||||||
|
|
||||||
|
const reaction = ChatModel.createMessageReaction(
|
||||||
|
messageId,
|
||||||
|
senderName,
|
||||||
|
content,
|
||||||
|
);
|
||||||
|
this.sendMessage("", reaction);
|
||||||
|
this.addReaction(reaction);
|
||||||
|
};
|
||||||
|
|
||||||
subscribe = (): void => {
|
subscribe = (): void => {
|
||||||
this.connectionModel.addChannel(this.info.primaryChannel);
|
this.connectionModel.addChannel(this.info.primaryChannel);
|
||||||
};
|
};
|
||||||
@@ -231,11 +288,12 @@ export default class ChatModel {
|
|||||||
const chatMessages: ChatMessage[] = [];
|
const chatMessages: ChatMessage[] = [];
|
||||||
for (const messageId of messageIds) {
|
for (const messageId of messageIds) {
|
||||||
const messagePath: string[] = this.getMessagePath(messageId);
|
const messagePath: string[] = this.getMessagePath(messageId);
|
||||||
const chatMessage: ChatMessage | any =
|
const chatMessage: ChatMessage | null =
|
||||||
this.storageModel.readStringifiable(
|
this.storageModel.readStringifiable(
|
||||||
messagePath,
|
messagePath,
|
||||||
ChatMessageReference,
|
ChatMessageReference,
|
||||||
);
|
);
|
||||||
|
if (chatMessage == null) continue;
|
||||||
chatMessages.push(chatMessage);
|
chatMessages.push(chatMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,6 +303,27 @@ export default class ChatModel {
|
|||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get reactions(): ChatMessageReaction[] {
|
||||||
|
const reactionIds: string[] = this.storageModel.list(
|
||||||
|
this.getReactionDirPath(),
|
||||||
|
);
|
||||||
|
if (!Array.isArray(reactionIds)) return [];
|
||||||
|
|
||||||
|
const reactions: ChatMessageReaction[] = [];
|
||||||
|
for (const reactionId of reactionIds) {
|
||||||
|
const reactionPath: string[] = this.getReactionPath(reactionId);
|
||||||
|
const reaction: ChatMessageReaction | null =
|
||||||
|
this.storageModel.readStringifiable(
|
||||||
|
reactionPath,
|
||||||
|
ChatMessageReactionReference,
|
||||||
|
);
|
||||||
|
if (reaction == null) continue;
|
||||||
|
reactions.push(reaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reactions;
|
||||||
|
}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
constructor(
|
constructor(
|
||||||
storageModel: StorageModel,
|
storageModel: StorageModel,
|
||||||
@@ -324,9 +403,27 @@ export default class ChatModel {
|
|||||||
|
|
||||||
return chatMessage;
|
return chatMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static createMessageReaction = (
|
||||||
|
messageId: string,
|
||||||
|
sender: string,
|
||||||
|
content: ReactionSymbol,
|
||||||
|
): ChatMessageReaction => {
|
||||||
|
const fileContent = FileModel.createFileContent(v4(), "reaction");
|
||||||
|
const reaction: ChatMessageReaction = {
|
||||||
|
...fileContent,
|
||||||
|
|
||||||
|
messageId,
|
||||||
|
sender,
|
||||||
|
content,
|
||||||
|
};
|
||||||
|
return reaction;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// types
|
// types
|
||||||
|
export type ReactionSymbol = "👍" | "✅" | "❗️" | "‼️" | "❓";
|
||||||
|
|
||||||
export interface ChatInfo extends ValidObject {
|
export interface ChatInfo extends ValidObject {
|
||||||
primaryChannel: string;
|
primaryChannel: string;
|
||||||
secondaryChannels: string[];
|
secondaryChannels: string[];
|
||||||
@@ -355,6 +452,13 @@ export interface ChatMessage extends ValidObject {
|
|||||||
stringifiedFile: string;
|
stringifiedFile: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ChatMessageReaction
|
||||||
|
extends ValidObject, FileContent<"reaction"> {
|
||||||
|
messageId: string;
|
||||||
|
sender: string;
|
||||||
|
content: ReactionSymbol | string;
|
||||||
|
}
|
||||||
|
|
||||||
// references
|
// references
|
||||||
export const ChatInfoReference: ChatInfo = {
|
export const ChatInfoReference: ChatInfo = {
|
||||||
dataVersion: DATA_VERSION,
|
dataVersion: DATA_VERSION,
|
||||||
@@ -380,3 +484,16 @@ export const ChatMessageReference: ChatMessage = {
|
|||||||
|
|
||||||
stringifiedFile: "",
|
stringifiedFile: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ChatMessageReactionReference: ChatMessageReaction = {
|
||||||
|
dataVersion: DATA_VERSION,
|
||||||
|
|
||||||
|
fileId: "",
|
||||||
|
fileContentId: "",
|
||||||
|
creationDate: "",
|
||||||
|
type: "reaction",
|
||||||
|
|
||||||
|
messageId: "",
|
||||||
|
sender: "",
|
||||||
|
content: "",
|
||||||
|
};
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export default class FileModel {
|
|||||||
if (didStore == false) return;
|
if (didStore == false) return;
|
||||||
|
|
||||||
this.boardsAndTasksModel.handleFileContent(fileContent);
|
this.boardsAndTasksModel.handleFileContent(fileContent);
|
||||||
|
this.chatModel.handleReaction(fileContent);
|
||||||
};
|
};
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
|
|||||||
@@ -247,6 +247,10 @@ export const filePaths = {
|
|||||||
info: (id: string) => [...filePaths.chat.chatBase(id), "info"],
|
info: (id: string) => [...filePaths.chat.chatBase(id), "info"],
|
||||||
color: (id: string) => [...filePaths.chat.chatBase(id), "color"],
|
color: (id: string) => [...filePaths.chat.chatBase(id), "color"],
|
||||||
messages: (id: string) => [...filePaths.chat.chatBase(id), "messages"],
|
messages: (id: string) => [...filePaths.chat.chatBase(id), "messages"],
|
||||||
|
reactions: (id: string) => [
|
||||||
|
...filePaths.chat.chatBase(id),
|
||||||
|
"reactions",
|
||||||
|
],
|
||||||
lastUsedPage: (id: string) => [
|
lastUsedPage: (id: string) => [
|
||||||
...filePaths.chat.chatBase(id),
|
...filePaths.chat.chatBase(id),
|
||||||
"last-used-page",
|
"last-used-page",
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import * as React from "bloatless-react";
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
import { ChatMessage, ChatMessageStatus } from "../../Model/Chat/chatModel";
|
import {
|
||||||
|
ChatMessage,
|
||||||
|
ChatMessageReaction,
|
||||||
|
ChatMessageReactionReference,
|
||||||
|
ChatMessageStatus,
|
||||||
|
ReactionSymbol,
|
||||||
|
} from "../../Model/Chat/chatModel";
|
||||||
|
|
||||||
import CoreViewModel from "../Global/coreViewModel";
|
import CoreViewModel from "../Global/coreViewModel";
|
||||||
import MessagePageViewModel from "../Pages/messagePageViewModel";
|
import MessagePageViewModel from "../Pages/messagePageViewModel";
|
||||||
@@ -19,6 +25,12 @@ export default class ChatMessageViewModel {
|
|||||||
);
|
);
|
||||||
sentByUser: boolean;
|
sentByUser: boolean;
|
||||||
|
|
||||||
|
reactionsThumbsUp = new React.MapState<ChatMessageReaction>();
|
||||||
|
reactionsCheck = new React.MapState<ChatMessageReaction>();
|
||||||
|
reactionsAttention = new React.MapState<ChatMessageReaction>();
|
||||||
|
reactionsDoubleAttention = new React.MapState<ChatMessageReaction>();
|
||||||
|
reactionsQuestion = new React.MapState<ChatMessageReaction>();
|
||||||
|
|
||||||
// state
|
// state
|
||||||
isPresentingInfoModal: React.State<boolean> = new React.State(false);
|
isPresentingInfoModal: React.State<boolean> = new React.State(false);
|
||||||
|
|
||||||
@@ -42,6 +54,25 @@ export default class ChatMessageViewModel {
|
|||||||
this.isPresentingInfoModal.value = false;
|
this.isPresentingInfoModal.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// reactions
|
||||||
|
addReaction = (reaction: ChatMessageReaction): void => {
|
||||||
|
switch (reaction.content) {
|
||||||
|
case "👍":
|
||||||
|
return this.reactionsThumbsUp.set(reaction.fileId, reaction);
|
||||||
|
case "✅":
|
||||||
|
return this.reactionsCheck.set(reaction.fileId, reaction);
|
||||||
|
case "❗️":
|
||||||
|
return this.reactionsAttention.set(reaction.fileId, reaction);
|
||||||
|
case "‼️":
|
||||||
|
return this.reactionsDoubleAttention.set(
|
||||||
|
reaction.fileId,
|
||||||
|
reaction,
|
||||||
|
);
|
||||||
|
case "❓":
|
||||||
|
return this.reactionsQuestion.set(reaction.fileId, reaction);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// load
|
// load
|
||||||
loadData = (): void => {
|
loadData = (): void => {
|
||||||
this.channel = this.chatMessage.channel;
|
this.channel = this.chatMessage.channel;
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ import * as React from "bloatless-react";
|
|||||||
import CalendarPageViewModel, {
|
import CalendarPageViewModel, {
|
||||||
CALENDAR_EVENT_BOARD_ID,
|
CALENDAR_EVENT_BOARD_ID,
|
||||||
} from "../Pages/calendarPageViewModel";
|
} from "../Pages/calendarPageViewModel";
|
||||||
import ChatModel, { ChatMessage } from "../../Model/Chat/chatModel";
|
import ChatModel, {
|
||||||
|
ChatMessage,
|
||||||
|
ChatMessageReaction,
|
||||||
|
} from "../../Model/Chat/chatModel";
|
||||||
import StorageModel, {
|
import StorageModel, {
|
||||||
StorageModelSubPath,
|
StorageModelSubPath,
|
||||||
filePaths,
|
filePaths,
|
||||||
@@ -176,6 +179,11 @@ export default class ChatViewModel {
|
|||||||
this.notificationViewModel.showNotification(chatMessage);
|
this.notificationViewModel.showNotification(chatMessage);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
chatModel.reactionHandlerManager.addHandler(
|
||||||
|
(reaction: ChatMessageReaction) => {
|
||||||
|
this.messagePageViewModel.showReaction(reaction);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// load
|
// load
|
||||||
this.loadPageSelection();
|
this.loadPageSelection();
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import * as React from "bloatless-react";
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
import { ChatMessage } from "../../Model/Chat/chatModel";
|
import {
|
||||||
|
ChatMessage,
|
||||||
|
ChatMessageReaction,
|
||||||
|
ReactionSymbol,
|
||||||
|
} from "../../Model/Chat/chatModel";
|
||||||
import ChatMessageViewModel from "../Chat/chatMessageViewModel";
|
import ChatMessageViewModel from "../Chat/chatMessageViewModel";
|
||||||
import ChatViewModel from "../Chat/chatViewModel";
|
import ChatViewModel from "../Chat/chatViewModel";
|
||||||
import CoreViewModel from "../Global/coreViewModel";
|
import CoreViewModel from "../Global/coreViewModel";
|
||||||
@@ -37,6 +41,10 @@ export default class MessagePageViewModel {
|
|||||||
messageViewModel.loadData();
|
messageViewModel.loadData();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sendReaction = (messageId: string, content: ReactionSymbol): void => {
|
||||||
|
this.chatViewModel.chatModel.sendReaction(messageId, content);
|
||||||
|
};
|
||||||
|
|
||||||
// view
|
// view
|
||||||
showChatMessage = (chatMessage: ChatMessage): void => {
|
showChatMessage = (chatMessage: ChatMessage): void => {
|
||||||
const chatMessageViewModel = new ChatMessageViewModel(
|
const chatMessageViewModel = new ChatMessageViewModel(
|
||||||
@@ -60,12 +68,22 @@ export default class MessagePageViewModel {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
showReaction = (reaction: ChatMessageReaction): void => {
|
||||||
|
const messageViewModel: ChatMessageViewModel | undefined =
|
||||||
|
this.chatMessageViewModels.value.get(reaction.messageId);
|
||||||
|
if (messageViewModel == undefined) return;
|
||||||
|
messageViewModel.addReaction(reaction);
|
||||||
|
};
|
||||||
|
|
||||||
// load
|
// load
|
||||||
loadData = (): void => {
|
loadData = (): void => {
|
||||||
this.chatMessageViewModels.clear();
|
this.chatMessageViewModels.clear();
|
||||||
for (const chatMessage of this.chatViewModel.chatModel.messages) {
|
for (const chatMessage of this.chatViewModel.chatModel.messages) {
|
||||||
this.showChatMessage(chatMessage);
|
this.showChatMessage(chatMessage);
|
||||||
}
|
}
|
||||||
|
for (const reaction of this.chatViewModel.chatModel.reactions) {
|
||||||
|
this.showReaction(reaction);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// init
|
// init
|
||||||
|
|||||||
Reference in New Issue
Block a user