From b7dbe6b13d313641604ee18ef8b158e2c7b28e35 Mon Sep 17 00:00:00 2001 From: marlon-erler Date: Thu, 11 Jul 2024 00:47:58 +0200 Subject: [PATCH] add logic for sending and receiving items --- bun.lockb | Bin 11447 -> 11435 bytes dist/index.js | 127 +++++++++++++++++++++++++++------- src/Model/chatModel.ts | 83 ++++++++++++++++------ src/Views/chatToolView.tsx | 11 ++- src/Views/messageComposer.tsx | 4 +- src/utility.ts | 4 ++ 6 files changed, 180 insertions(+), 49 deletions(-) diff --git a/bun.lockb b/bun.lockb index 85489cfc37debdc3364a7b86642d31583852a723..3dd5d05b04dfd74ce992b9198f27b4483903b997 100755 GIT binary patch delta 968 zcmYLIT}V@582-M~nLBffwYIs=jB|DiN z?WIyF86B1gAr3-{7jNWlUb%LG6gWb5Vx32HBW4gih;c(#jM|Ubgt`?`&23PI93q$|iyXzT44 zSZ)xRo|~&{cAK#tO@e5P(TQ@_*5MEa@VD6Ux0DxsTNFk)9`5@DVGP6DQH2zzK+(&W z7kskSk5S@8b??mQ_%p|!ha5fE8R`m!34z9dUt*&Y7p^D0-pvCX#jrL!QxFS?5q1-w ztS6r&eh*-R%oWnf_YqKV$kHs0Kv5%q2{* z$(SYU-MeetF*B6{rz}R;BrV;!l<0i?qiXubuoWlX-OjHIZC^}h1kTE$#D;V6)sB`A zdumD3uRuu_={!uzVlx}H5@a!>2k#{US+*Af5# delta 981 zcmYLIO=uHA6rR~`%%+XRn5OG?8+KDjBh-eZA%ZrT9@4amG&KhyN-W)4@vkVTMG-X+ z1&cql3`V3N)Qd`rAUPD;i)lT0(YAUhT10yg%)z3UhC&a%&CX;m^L_7q-+MF6yeXt- z(-ZyJKbbsm$Bz)QBa|JvqFp<8@iZFe5ZVp#7@!MK18f8wp!q0`+W?y&?*i0)nCgG9 z;a>&R^+g)b0E!UjX+8%Cb*bznYRCZU8y}`|7*KDZ0_qzy0J;GyaA5sF>wvock;e0Y zdcD1v#xab;D-wP#1I3$Q-osf+SJjCP`xl@0ugxN>7UNWIc5`)LptE+^gY&HWsfX=a|p6e+@9;)8YI zY2x?j0*`}%&Tt@z5PPfCq2=}#kMpIeRLCPmlG)onmxFU(%EKp2T_q(&g2!9~7n_U) zw9(sE=DJN+hB#Cy!X{}gcP0_ae=C_f9k%R?*SF7a2)@szk|!BelG$*sOz-l%-&;-ss?@?pTWi|3Ih4jt(}g+mQ{59`f8jnqb9T^q@VaSWzopZ8>-hRyN;8!x z>F`Q2`(349ldoK2Z^hI#GUS!;7`X}SIC handler(item)); + this.callSubscriptions(); + } + remove(key) { + const item = this.value.get(key); + if (!item) return; + this.value.delete(key); + this.callSubscriptions(); + if (!this.removalHandlers.has(item)) return; + this.removalHandlers.get(item)(item); + this.removalHandlers.delete(item); + } + clear() { + this.value.clear(); + this.callSubscriptions(); + } + // handlers + handleAddition(handler) { + this.additionHandlers.add(handler); + [...this.value.values()].forEach(handler); + } + handleRemoval(item, handler) { + this.removalHandlers.set(item, handler); + } + // stringification + toString() { + const array = [...this.value.entries()]; const json = JSON.stringify(array); return json; } @@ -143,9 +184,8 @@ persistState(localStorageKey, state); return state; } - function restoreListState(localStorageKey) { + function restoreListState(localStorageKey, initialItems = []) { const storedString = localStorage.getItem(localStorageKey) ?? ""; - let initialItems = []; try { const array = JSON.parse(storedString); if (!Array.isArray(array)) throw ""; @@ -156,6 +196,18 @@ persistState(localStorageKey, state); return state; } + function restoreMapState(localStorageKey, initialItems = []) { + const storedString = localStorage.getItem(localStorageKey) ?? ""; + try { + const array = JSON.parse(storedString); + if (!Array.isArray(array)) throw ""; + initialItems = array; + } catch { + } + const state = new MapState(initialItems); + persistState(localStorageKey, state); + return state; + } function createElement(tagName, attributes = {}, ...children) { const element = document.createElement(tagName); if (attributes != null) @@ -346,6 +398,9 @@ messages(id) { return id + "messages"; }, + items(id) { + return id + "items"; + }, outbox(id) { return id + "outbox"; }, @@ -363,6 +418,7 @@ secondaryChannels; encryptionKey; messages; + items; outbox; isOutBoxEmpty; composingMessage; @@ -390,6 +446,7 @@ ); this.encryptionKey = restoreState(storageKeys.encyptionKey(id), ""); this.messages = restoreListState(storageKeys.messages(id)); + this.items = restoreMapState(storageKeys.items(id)); this.outbox = restoreListState(storageKeys.outbox(id)); this.isOutBoxEmpty = createProxyState( [this.outbox], @@ -441,7 +498,12 @@ if (channels.indexOf(this.primaryChannel.value) == -1) return; if (data.subscribed != void 0) this.handleSubscription(data.subscribed); if (!data.messageBody) return; - const { sender, body, channel, isoDate } = JSON.parse(data.messageBody); + const { sender, body, channel, isoDate, itemData } = JSON.parse( + data.messageBody + ); + if (itemData != void 0) { + return this.handleItem(itemData); + } this.handleMessage({ sender, body: await decryptString(body, this.encryptionKey.value), @@ -459,21 +521,11 @@ this.messages.add(chatMessage); if (selectedChat.value != this) this.hasUnreadMessages.value = true; }; + handleItem = (itemData) => { + console.log(itemData); + }; // messages - sendNewMessage = async () => { - if (this.cannotSendMessage.value == true) return; - await this.sendMessageText(this.composingMessage.value); - this.composingMessage.value = ""; - }; - sendMessageText = async (text) => { - const message = await this.createMessage(text); - this.sendExistingMessage(message); - }; - resendMessage = (message) => { - if (this.cannotResendMessage.value == true) return; - this.sendMessageText(message.body); - }; - createMessage = async (messageText) => { + createMessage = async (messageText, itemData) => { const secondaryChannelNames = [ ...this.secondaryChannels.value.values() ]; @@ -482,14 +534,29 @@ ...secondaryChannelNames ]; const joinedChannelName = allChannelNames.join("/"); - return { + const messageObject = { channel: joinedChannelName, sender: senderName.value, body: messageText, isoDate: (/* @__PURE__ */ new Date()).toISOString() }; + if (itemData) messageObject.itemData = itemData; + return messageObject; }; - sendExistingMessage = async (chatMessage) => { + sendMessageFromComposer = async () => { + if (this.cannotSendMessage.value == true) return; + await this.sendMessageFromText(this.composingMessage.value); + this.composingMessage.value = ""; + }; + sendMessageFromText = async (text) => { + const message = await this.createMessage(text); + this.sendMessage(message); + }; + resendMessage = (message) => { + if (this.cannotResendMessage.value == true) return; + this.sendMessageFromText(message.body); + }; + sendMessage = async (chatMessage) => { if (isConnected.value == true && this.isSubscribed.value == true) { const encrypted = this.encryptionKey.value == "" ? chatMessage.body : await encryptString(chatMessage.body, this.encryptionKey.value); chatMessage.body = encrypted; @@ -501,7 +568,7 @@ }; sendMessagesInOutbox = () => { this.outbox.value.forEach((message) => { - this.sendExistingMessage(message); + this.sendMessage(message); this.outbox.remove(message); }); }; @@ -518,6 +585,12 @@ message.body = await decryptString(message.body, this.encryptionKey.value); this.messages.callSubscriptions(); }; + // items + async createItem(item) { + this.items.set(item.id, item); + const message = await this.createMessage("", item); + this.sendMessage(message); + } // channel setChannel = () => { if (this.cannotSetChannel.value == true) return; @@ -1031,7 +1104,13 @@ // src/Views/chatToolView.tsx function ChatToolView(chat) { - return /* @__PURE__ */ createElement("div", { class: "chat-tool-view" }, /* @__PURE__ */ createElement("span", null, "Tools")); + function createItem() { + chat.createItem({ + id: UUID(), + title: "new item" + }); + } + return /* @__PURE__ */ createElement("div", { class: "chat-tool-view" }, /* @__PURE__ */ createElement("button", { "on:click": createItem }, "+"), /* @__PURE__ */ createElement("hr", null)); } // src/Views/messageComposer.tsx @@ -1043,13 +1122,13 @@ style: "max-width: unset", placeholder: translation.composerPlaceholder, "bind:value": chat.composingMessage, - "on:enter": chat.sendNewMessage + "on:enter": chat.sendMessageFromComposer } ), /* @__PURE__ */ createElement( "button", { class: "primary", - "on:click": chat.sendNewMessage, + "on:click": chat.sendMessageFromComposer, "toggle:disabled": chat.cannotSendMessage }, /* @__PURE__ */ createElement("span", { class: "icon" }, "send") diff --git a/src/Model/chatModel.ts b/src/Model/chatModel.ts index ecc5d2d1..1d45b477 100644 --- a/src/Model/chatModel.ts +++ b/src/Model/chatModel.ts @@ -21,6 +21,18 @@ export interface ChatMessage { sender: string; body: string; isoDate: string; + + itemData?: Item; +} + +// item +export interface Item { + id: string; + title: string; +} + +export interface NoteItem extends Item { + body: string; } // chat @@ -34,6 +46,7 @@ export class Chat { encryptionKey: React.State; messages: React.ListState; + items: React.MapState; outbox: React.ListState; isOutBoxEmpty: React.State; @@ -68,6 +81,7 @@ export class Chat { ); this.encryptionKey = React.restoreState(storageKeys.encyptionKey(id), ""); this.messages = React.restoreListState(storageKeys.messages(id)); + this.items = React.restoreMapState(storageKeys.items(id)); this.outbox = React.restoreListState(storageKeys.outbox(id)); this.isOutBoxEmpty = React.createProxyState( [this.outbox], @@ -133,7 +147,14 @@ export class Chat { if (data.subscribed != undefined) this.handleSubscription(data.subscribed); if (!data.messageBody) return; - const { sender, body, channel, isoDate } = JSON.parse(data.messageBody); + const { sender, body, channel, isoDate, itemData } = JSON.parse( + data.messageBody + ); + + if (itemData != undefined) { + return this.handleItem(itemData); + } + this.handleMessage({ sender, body: await decryptString(body, this.encryptionKey.value), @@ -155,25 +176,15 @@ export class Chat { if (selectedChat.value != this) this.hasUnreadMessages.value = true; }; + handleItem = (itemData: Item): void => { + console.log(itemData); + }; + // messages - sendNewMessage = async (): Promise => { - if (this.cannotSendMessage.value == true) return; - - await this.sendMessageText(this.composingMessage.value); - this.composingMessage.value = ""; - }; - - sendMessageText = async (text: string): Promise => { - const message = await this.createMessage(text); - this.sendExistingMessage(message); - }; - - resendMessage = (message: ChatMessage) => { - if (this.cannotResendMessage.value == true) return; - this.sendMessageText(message.body); - }; - - createMessage = async (messageText: string): Promise => { + createMessage = async ( + messageText: string, + itemData?: Item + ): Promise => { // get channels const secondaryChannelNames: string[] = [ ...this.secondaryChannels.value.values(), @@ -185,15 +196,35 @@ export class Chat { // create object const joinedChannelName = allChannelNames.join("/"); - return { + const messageObject: ChatMessage = { channel: joinedChannelName, sender: senderName.value, body: messageText, isoDate: new Date().toISOString(), }; + + if (itemData) messageObject.itemData = itemData; + return messageObject; }; - sendExistingMessage = async (chatMessage: ChatMessage): Promise => { + sendMessageFromComposer = async (): Promise => { + if (this.cannotSendMessage.value == true) return; + + await this.sendMessageFromText(this.composingMessage.value); + this.composingMessage.value = ""; + }; + + sendMessageFromText = async (text: string): Promise => { + const message = await this.createMessage(text); + this.sendMessage(message); + }; + + resendMessage = (message: ChatMessage) => { + if (this.cannotResendMessage.value == true) return; + this.sendMessageFromText(message.body); + }; + + sendMessage = async (chatMessage: ChatMessage): Promise => { if (isConnected.value == true && this.isSubscribed.value == true) { const encrypted = this.encryptionKey.value == "" @@ -211,7 +242,7 @@ export class Chat { sendMessagesInOutbox = () => { this.outbox.value.forEach((message) => { - this.sendExistingMessage(message); + this.sendMessage(message); this.outbox.remove(message); }); }; @@ -233,6 +264,14 @@ export class Chat { this.messages.callSubscriptions(); }; + // items + async createItem(item: Item): Promise { + this.items.set(item.id, item); + + const message = await this.createMessage("", item); + this.sendMessage(message); + } + // channel setChannel = (): void => { if (this.cannotSetChannel.value == true) return; diff --git a/src/Views/chatToolView.tsx b/src/Views/chatToolView.tsx index ca32cfaf..1576c065 100644 --- a/src/Views/chatToolView.tsx +++ b/src/Views/chatToolView.tsx @@ -4,9 +4,18 @@ import { Chat } from "../Model/chatModel"; import { translation } from "../translations"; export function ChatToolView(chat: Chat) { + function createItem() { + chat.createItem({ + id: React.UUID(), + title: "new item", + }); + } + return (
- Tools + +
+
); } diff --git a/src/Views/messageComposer.tsx b/src/Views/messageComposer.tsx index 66a87fed..8d2e281c 100644 --- a/src/Views/messageComposer.tsx +++ b/src/Views/messageComposer.tsx @@ -12,11 +12,11 @@ export function MessageComposer(chat: Chat) { style="max-width: unset" placeholder={translation.composerPlaceholder} bind:value={chat.composingMessage} - on:enter={chat.sendNewMessage} + on:enter={chat.sendMessageFromComposer} >