From d14b0c428276877fafd173ab498ded7852a6dc1f Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Wed, 28 Sep 2022 16:45:16 +0300 Subject: [PATCH] add action system and move message sending to it --- frontend/src/components/Message.svelte | 2 +- frontend/src/components/MessageInput.svelte | 40 +++--------------- frontend/src/stores.js | 47 +++++++++++++++++++-- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/frontend/src/components/Message.svelte b/frontend/src/components/Message.svelte index a65c049..2787b8c 100644 --- a/frontend/src/components/Message.svelte +++ b/frontend/src/components/Message.svelte @@ -13,7 +13,7 @@ replyString += `@${message.author_username}: `; - setMessageInputEvent.update(replyString); + setMessageInputEvent.emit(replyString); }; diff --git a/frontend/src/components/MessageInput.svelte b/frontend/src/components/MessageInput.svelte index 5b0a64b..2232c80 100644 --- a/frontend/src/components/MessageInput.svelte +++ b/frontend/src/components/MessageInput.svelte @@ -2,7 +2,7 @@ import { onDestroy, onMount } from "svelte"; import request from "../request"; import { apiRoute, getItem } from "../storage"; - import { messagesStoreProvider, overlayStore, selectedChannel, setMessageInputEvent, smallViewport, typingStore, userInfoStore } from "../stores"; + import { messagesStoreProvider, overlayStore, selectedChannel, sendMessageAction, setMessageInputEvent, smallViewport, typingStore, userInfoStore } from "../stores"; export let channel; let messageInput = ""; @@ -41,37 +41,11 @@ const sendMessage = async () => { messageTextarea.focus(); - - if (messageInput.trim() === "" || !$userInfoStore) - return; - - // optimistically add message to store - const optimisticMessageId = Math.floor(Math.random() * 999999); - const optimisticMessage = { - id: optimisticMessageId, - content: messageInput, - channel_id: channel.id, - author_id: $userInfoStore.id, - author_username: $userInfoStore.username, - created_at: Date.now().toString(), - _isPending: true - }; - messages.addMessage(optimisticMessage); - messageInput = ""; - - const res = await request("POST", apiRoute(`channels/${channel.id}/messages`), true, { - content: optimisticMessage.content, - optimistic_id: optimisticMessageId + sendMessageAction.emit({ + channelId: channel.id, + content: messageInput }); - - if (res.success && res.ok) { - messages.setMessage(optimisticMessageId, res.json); - } else { - messages.deleteMessage({ - id: optimisticMessageId - }); - overlayStore.toast("Couldn't send message"); - } + messageInput = ""; }; const onKeydown = async (e) => { @@ -100,10 +74,10 @@ } }; onMount(focusTextarea); - unsubscribers.push(selectedChannel.watch(focusTextarea)); + unsubscribers.push(selectedChannel.on(focusTextarea)); // Handle the setMessageInput event - unsubscribers.push(setMessageInputEvent.watch((value) => { + unsubscribers.push(setMessageInputEvent.on((value) => { messageInput = value; if (messageTextarea) { messageTextarea.focus(); diff --git a/frontend/src/stores.js b/frontend/src/stores.js index 8376896..d2f5065 100644 --- a/frontend/src/stores.js +++ b/frontend/src/stores.js @@ -20,7 +20,7 @@ class Store { } // like subscribe, but without initially calling the handler - watch(handler) { + on(handler) { storeLog(`[Watch] (${this.name})`, "handler:", handler); this._handlers.add(handler); @@ -51,7 +51,7 @@ class Store { } // like set(), but without checking if the value is the same - update(value) { + emit(value) { this.value = value; this.updated(); } @@ -100,10 +100,16 @@ class Store { } } +function createAction(name, handler) { + const store = new Store(null, name); + store.on(handler); + return store; +} + class StorageItemStore extends Store { constructor(key) { super(getItem(key), `StorageItemStore[key=${key}]`); - this.watch(e => setItem(key, e)); + this.on(e => setItem(key, e)); } } @@ -637,7 +643,40 @@ export const typingStore = new TypingStore(); export const presenceStore = new PresenceStore(); export const unreadStore = new UnreadStore(); export const pluginStore = new PluginStore(); + export const setMessageInputEvent = new Store(null, "event:setMessageInput"); +export const sendMessageAction = createAction("sendMessageAction", async ({channelId, content}) => { + if (content.trim() === "" || !userInfoStore.value) + return; + + // optimistically add message to store + const optimisticMessageId = Math.floor(Math.random() * 999999); + const optimisticMessage = { + id: optimisticMessageId, + content: content, + channel_id: channelId, + author_id: userInfoStore.value.id, + author_username: userInfoStore.value.username, + created_at: Date.now().toString(), + _isPending: true + }; + const messagesStoreForChannel = messagesStoreProvider.getStore(channelId); + messagesStoreForChannel.addMessage(optimisticMessage); + + const res = await request("POST", apiRoute(`channels/${channelId}/messages`), true, { + content: optimisticMessage.content, + optimistic_id: optimisticMessageId + }); + + if (res.success && res.ok) { + messagesStoreForChannel.setMessage(optimisticMessageId, res.json); + } else { + messagesStoreForChannel.deleteMessage({ + id: optimisticMessageId + }); + overlayStore.toast("Couldn't send message"); + } +}); export const allStores = { selectedChannel, @@ -658,7 +697,7 @@ export const allStores = { setMessageInputEvent, }; -selectedChannel.watch((newSelectedChannel) => { +selectedChannel.on((newSelectedChannel) => { if (getItem("ui:stateful:presistSelectedChannel")) { setItem("state:openChannelId", newSelectedChannel.id); }