Show sent messages before the server confirms them
The composer now puts the bubble and clears the input as soon as you send, so a slow connection never holds either. The bot's status row reads "<name> is getting your message..." until the saved message arrives (by response or push), then switches to thinking. A failed send removes the bubble and restores the text and files.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import type { BotMessageWithAttachments } from "@/src/types";
|
||||
import dropSentMessage from "./drop-sent-message";
|
||||
|
||||
const pendingMessage = (overrides: Partial<BotMessageWithAttachments> = {}): BotMessageWithAttachments => ({
|
||||
id: -1,
|
||||
author: "user",
|
||||
text: "Hello",
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const savedMessage = (overrides: Partial<BotMessageWithAttachments> = {}): BotMessageWithAttachments => ({
|
||||
id: 7,
|
||||
author: "user",
|
||||
text: "Hello",
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe("dropSentMessage", () => {
|
||||
test("drops the pending copy the saved message replaces", () => {
|
||||
const other = pendingMessage({ id: -2, text: "Later" });
|
||||
|
||||
expect(
|
||||
dropSentMessage({ pending: [pendingMessage(), other], message: savedMessage() }),
|
||||
).toEqual([other]);
|
||||
});
|
||||
|
||||
test("leaves the thread alone when nothing matches", () => {
|
||||
const pending = [pendingMessage({ text: "Something else" })];
|
||||
|
||||
expect(dropSentMessage({ pending, message: savedMessage() })).toBe(pending);
|
||||
});
|
||||
|
||||
test("matches on the quote as well as the text", () => {
|
||||
const pending = [pendingMessage({ reply_to: { id: 3, author: "bot", text: "Hi" } })];
|
||||
|
||||
expect(dropSentMessage({ pending, message: savedMessage({ reply_to_message_id: 3 }) })).toEqual([]);
|
||||
expect(
|
||||
dropSentMessage({ pending, message: savedMessage({ reply_to_message_id: 4 }) }),
|
||||
).toBe(pending);
|
||||
});
|
||||
|
||||
test("only drops one copy of the same words", () => {
|
||||
const pending = [pendingMessage({ id: -1 }), pendingMessage({ id: -2 })];
|
||||
|
||||
expect(dropSentMessage({ pending, message: savedMessage() })).toEqual([pendingMessage({ id: -2 })]);
|
||||
});
|
||||
|
||||
test("never drops a bot message", () => {
|
||||
const pending = [pendingMessage()];
|
||||
const message = savedMessage({ author: "bot" });
|
||||
|
||||
expect(dropSentMessage({ pending, message })).toBe(pending);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { BotMessageWithAttachments } from "@/src/types";
|
||||
|
||||
type Params = {
|
||||
/**
|
||||
* Messages shown before the server has them.
|
||||
*/
|
||||
pending: BotMessageWithAttachments[];
|
||||
/**
|
||||
* The saved message that has arrived, from the send's response or a
|
||||
* push.
|
||||
*/
|
||||
message: BotMessageWithAttachments;
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes a pending message off the thread once the saved one arrives, so a
|
||||
* pushed copy never shows beside the bubble still waiting for its
|
||||
* response. Only user messages can be pending. The first one that matches
|
||||
* is enough: same text, same quote, same number of files.
|
||||
*/
|
||||
export default function dropSentMessage({ pending, message }: Params): BotMessageWithAttachments[] {
|
||||
if (!pending.length || message.author != "user") return pending;
|
||||
|
||||
const index = pending.findIndex(
|
||||
(item) =>
|
||||
item.text == message.text &&
|
||||
(item.reply_to?.id || null) == (message.reply_to_message_id || null) &&
|
||||
(item.attachments?.length || 0) == (message.attachments?.length || 0),
|
||||
);
|
||||
|
||||
if (index < 0) return pending;
|
||||
|
||||
return [...pending.slice(0, index), ...pending.slice(index + 1)];
|
||||
}
|
||||
Reference in New Issue
Block a user