From b1a6f318be41c472c5dc4f2ac4e28f3e0ce3c18d Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sat, 2 Sep 2023 22:43:05 -0400 Subject: [PATCH] fix upload progress --- .../messaging/AttachmentUploadProgress.tsx | 14 ++++-- src/components/messaging/Message.tsx | 4 +- src/components/messaging/MessageGroup.tsx | 4 +- src/components/messaging/MessageInput.tsx | 5 +- src/components/messaging/MessageList.tsx | 7 ++- src/stores/MessageQueue.ts | 42 +---------------- src/stores/MessageStore.ts | 2 +- src/stores/objects/Channel.ts | 5 +- src/stores/objects/QueuedMessage.ts | 46 +++++++++++++++++++ src/utils/REST.ts | 14 +++++- 10 files changed, 84 insertions(+), 59 deletions(-) create mode 100644 src/stores/objects/QueuedMessage.ts diff --git a/src/components/messaging/AttachmentUploadProgress.tsx b/src/components/messaging/AttachmentUploadProgress.tsx index 28166e5..ec4d2a2 100644 --- a/src/components/messaging/AttachmentUploadProgress.tsx +++ b/src/components/messaging/AttachmentUploadProgress.tsx @@ -1,6 +1,7 @@ import { observer } from "mobx-react-lite"; import styled from "styled-components"; -import { QueuedMessage } from "../../stores/MessageQueue"; +import { useAppStore } from "../../stores/AppStore"; +import QueuedMessage from "../../stores/objects/QueuedMessage"; import Icon from "../Icon"; import IconButton from "../IconButton"; @@ -41,7 +42,7 @@ interface Props { } function AttachmentUploadProgress({ message }: Props) { - console.log(message.progress); + const app = useAppStore(); return ( @@ -49,7 +50,14 @@ function AttachmentUploadProgress({ message }: Props) {
{message.files!.length === 1 ? message.files![0].name : `${message.files!.length} files`}
- + { + message.abort(); + // remove the message from the queue + app.queue.remove(message.id); + }} + >
diff --git a/src/components/messaging/Message.tsx b/src/components/messaging/Message.tsx index d2f16e0..88bd506 100644 --- a/src/components/messaging/Message.tsx +++ b/src/components/messaging/Message.tsx @@ -6,8 +6,8 @@ import Moment from "react-moment"; import styled from "styled-components"; import { ContextMenuContext } from "../../contexts/ContextMenuContext"; import useLogger from "../../hooks/useLogger"; -import { QueuedMessage } from "../../stores/MessageQueue"; import { default as MessageObject } from "../../stores/objects/Message"; +import QueuedMessage from "../../stores/objects/QueuedMessage"; import { calculateImageRatio, calculateScaledDimensions } from "../../utils/Message"; import { calendarStrings } from "../../utils/i18n"; import Avatar from "../Avatar"; @@ -183,8 +183,6 @@ function Message({ message, isHeader, isSending, isFailed }: Props) { ); }, []); - if (message instanceof QueuedMessage) console.log(`progress at msg`, message.progress); - // construct the context menu options // React.useEffect(() => { // // if the message is queued, we don't need a context menu diff --git a/src/components/messaging/MessageGroup.tsx b/src/components/messaging/MessageGroup.tsx index 7eea47b..2cde32b 100644 --- a/src/components/messaging/MessageGroup.tsx +++ b/src/components/messaging/MessageGroup.tsx @@ -1,8 +1,9 @@ import { observer } from "mobx-react-lite"; import React from "react"; import styled from "styled-components"; -import { QueuedMessage, QueuedMessageStatus } from "../../stores/MessageQueue"; +import { QueuedMessageStatus } from "../../stores/MessageQueue"; import { default as MessageObject } from "../../stores/objects/Message"; +import QueuedMessage from "../../stores/objects/QueuedMessage"; import Message from "./Message"; const Container = styled.div` @@ -18,7 +19,6 @@ interface Props { */ function MessageGroup({ messages }: Props) { const renderMessage = React.useCallback((message: MessageObject | QueuedMessage, index: number) => { - if (message instanceof QueuedMessage) console.log(`progress at msg group`, message.progress); return ( { - app.queue.error(nonce, error as string); + props.channel.sendMessage(body, msg).catch((error) => { + if (error) app.queue.error(nonce, error as string); }); } diff --git a/src/components/messaging/MessageList.tsx b/src/components/messaging/MessageList.tsx index 3a43f09..7a1a51a 100644 --- a/src/components/messaging/MessageList.tsx +++ b/src/components/messaging/MessageList.tsx @@ -5,10 +5,10 @@ import PulseLoader from "react-spinners/PulseLoader"; import styled from "styled-components"; import useLogger from "../../hooks/useLogger"; import { useAppStore } from "../../stores/AppStore"; -import { QueuedMessage } from "../../stores/MessageQueue"; import Channel from "../../stores/objects/Channel"; import Guild from "../../stores/objects/Guild"; import Message from "../../stores/objects/Message"; +import QueuedMessage from "../../stores/objects/QueuedMessage"; import { Permissions } from "../../utils/Permissions"; import { HorizontalDivider } from "../Divider"; import MessageGroup from "./MessageGroup"; @@ -66,6 +66,7 @@ function MessageList({ guild, channel }: Props) { // get last group const lastGroup = channel.messages.grouped[channel.messages.grouped.length - 1]; + // ignore queued messages if ("status" in lastGroup) return; // get first message in the group to use as before const before = lastGroup[0].id; @@ -112,7 +113,9 @@ function MessageList({ guild, channel }: Props) { } > - {channel.messages.grouped.map((group, index) => renderMessageGroup(group, index))} + {channel.messages.grouped.map((group, index) => ( + + ))} ) : (
; diff --git a/src/stores/MessageStore.ts b/src/stores/MessageStore.ts index 3eedf4b..56b2600 100644 --- a/src/stores/MessageStore.ts +++ b/src/stores/MessageStore.ts @@ -4,8 +4,8 @@ import { action, computed, makeObservable, observable } from "mobx"; import useLogger from "../hooks/useLogger"; import Logger from "../utils/Logger"; import AppStore from "./AppStore"; -import { QueuedMessage } from "./MessageQueue"; import Message from "./objects/Message"; +import QueuedMessage from "./objects/QueuedMessage"; export default class MessageStore { private readonly app: AppStore; diff --git a/src/stores/objects/Channel.ts b/src/stores/objects/Channel.ts index e6e0e77..f461d55 100644 --- a/src/stores/objects/Channel.ts +++ b/src/stores/objects/Channel.ts @@ -19,6 +19,7 @@ import Logger from "../../utils/Logger"; import { APIError } from "../../utils/interfaces/api"; import AppStore from "../AppStore"; import MessageStore from "../MessageStore"; +import QueuedMessage from "./QueuedMessage"; export default class Channel { private readonly logger: Logger = new Logger("Channel"); @@ -198,13 +199,13 @@ export default class Channel { } @action - async sendMessage(data: RESTPostAPIChannelMessageJSONBody | FormData, cb?: (e: ProgressEvent) => void) { + async sendMessage(data: RESTPostAPIChannelMessageJSONBody | FormData, msg?: QueuedMessage) { if (data instanceof FormData) return this.app.rest.postFormData( Routes.channelMessages(this.id), data, undefined, - cb, + msg, ); return this.app.rest.post( Routes.channelMessages(this.id), diff --git a/src/stores/objects/QueuedMessage.ts b/src/stores/objects/QueuedMessage.ts new file mode 100644 index 0000000..e6d203b --- /dev/null +++ b/src/stores/objects/QueuedMessage.ts @@ -0,0 +1,46 @@ +import { MessageType } from "@spacebarchat/spacebar-api-types/v9"; +import { action, makeAutoObservable, observable } from "mobx"; +import { QueuedMessageData, QueuedMessageStatus } from "../MessageQueue"; +import User from "./User"; + +export default class QueuedMessage { + id: string; + channel: string; + author: User; + content: string; + files?: File[]; + @observable progress = 0; + status: QueuedMessageStatus; + error?: string; + timestamp: Date; + type: MessageType; + abortCallback?: () => void; + + constructor(data: QueuedMessageData) { + this.id = data.id; + this.channel = data.channel; + this.author = data.author; + this.content = data.content; + this.files = data.files; + this.status = QueuedMessageStatus.SENDING; + this.timestamp = new Date(); + this.type = MessageType.Default; + + makeAutoObservable(this); + } + + @action + updateProgress(e: ProgressEvent) { + this.progress = Math.round((e.loaded / e.total) * 100); + } + + setAbortCallback(cb: () => void) { + this.abortCallback = cb; + } + + abort() { + if (this.abortCallback) { + this.abortCallback(); + } + } +} diff --git a/src/utils/REST.ts b/src/utils/REST.ts index 5f146b1..7ba601c 100644 --- a/src/utils/REST.ts +++ b/src/utils/REST.ts @@ -3,6 +3,7 @@ // import {DomainStore} from '../stores/DomainStore'; import AppStore from "../stores/AppStore"; +import QueuedMessage from "../stores/objects/QueuedMessage"; import { Globals, RouteSettings } from "./Globals"; import Logger from "./Logger"; @@ -142,13 +143,22 @@ export default class REST { body: FormData, // eslint-disable-next-line @typescript-eslint/no-explicit-any queryParams: Record = {}, - progressCb?: (ev: ProgressEvent) => void, + msg?: QueuedMessage, ): Promise { return new Promise((resolve, reject) => { const url = REST.makeAPIUrl(path, queryParams); this.logger.debug(`POST ${url}; payload:`, body); const xhr = new XMLHttpRequest(); - if (progressCb) xhr.upload.addEventListener("progress", progressCb); + if (msg) { + // add abort callback + msg.setAbortCallback(() => { + this.logger.debug("[PostFormData]: Message called abort"); + xhr.abort(); + reject("aborted"); + }); + // add progress listener + xhr.upload.addEventListener("progress", (e: ProgressEvent) => msg.updateProgress(e)); + } xhr.addEventListener("loadend", () => { // if success, resolve text or json if (xhr.status >= 200 && xhr.status < 300) {