94 lines
3.1 KiB
TypeScript
94 lines
3.1 KiB
TypeScript
import { chatMessageIdentityKey, groupChatMessagesByDay, type ChatChannelDetailVM, type ChatMessageVM, type ChatResolvedAuthorVM } from "@hivegrid/view-models";
|
|
|
|
import type { ChatPendingAttachment } from "./useChatAttachmentUploads";
|
|
|
|
export type ChatAttachmentSendAttempt = {
|
|
readonly payloadKey: string;
|
|
readonly requestId: string;
|
|
readonly clientMessageId: string;
|
|
readonly fileIds: readonly string[];
|
|
readonly body: string;
|
|
readonly attachments: readonly ChatPendingAttachment[];
|
|
readonly createdAtIso: string;
|
|
readonly deliveryState: "sending" | "failed";
|
|
readonly errorKey: string | null;
|
|
};
|
|
|
|
export function overlayChatAttachmentSendAttempt(
|
|
vm: ChatChannelDetailVM,
|
|
attempt: ChatAttachmentSendAttempt | null,
|
|
currentUser: ChatResolvedAuthorVM
|
|
): ChatChannelDetailVM {
|
|
if (vm.status !== "ready" || attempt === null) return vm;
|
|
const recipientCount = Math.max(0, vm.data.header.memberCount - 1);
|
|
const localMessage: ChatMessageVM = {
|
|
id: `local:${attempt.clientMessageId}`,
|
|
clientMessageId: attempt.clientMessageId,
|
|
source: "local_echo",
|
|
deliveryState: attempt.deliveryState,
|
|
deliveryStateKey: attempt.deliveryState === "sending" ? "chat.message.delivery.sending" : "chat.message.delivery.failed",
|
|
failureReasonKey: attempt.errorKey,
|
|
retryable: attempt.deliveryState === "failed",
|
|
author: currentUser,
|
|
bodyMarkdown: attempt.body || null,
|
|
bodyFormat: "markdown",
|
|
systemEvent: null,
|
|
createdAtIso: attempt.createdAtIso,
|
|
updatedAtIso: attempt.createdAtIso,
|
|
editedAtIso: null,
|
|
deletedAtIso: null,
|
|
tombstoneKey: null,
|
|
parentMessageId: null,
|
|
mentions: [],
|
|
reactions: [],
|
|
thread: null,
|
|
attachments: attempt.attachments.flatMap((attachment) =>
|
|
attachment.fileId
|
|
? [
|
|
{
|
|
id: `${attempt.clientMessageId}:${attachment.fileId}`,
|
|
fileId: attachment.fileId,
|
|
kind: attachment.kind,
|
|
fileName: attachment.fileName,
|
|
mimeType: attachment.mimeType,
|
|
sizeBytes: attachment.sizeBytes,
|
|
downloadHref: "#pending-chat-attachment",
|
|
previewHref: null,
|
|
altText: attachment.kind === "image" ? attachment.fileName : null,
|
|
durationSeconds: attachment.durationSeconds,
|
|
scanStatus: "clean" as const,
|
|
},
|
|
]
|
|
: []
|
|
),
|
|
linkPreviews: [],
|
|
readAggregate: {
|
|
readCount: 0,
|
|
recipientCount,
|
|
readerUserIds: [],
|
|
readerLabels: [],
|
|
labelKey: "chat.message.read.aggregate",
|
|
},
|
|
pin: null,
|
|
actions: {
|
|
canReact: false,
|
|
canReply: false,
|
|
canEdit: false,
|
|
canDelete: false,
|
|
canPin: false,
|
|
canMarkAsTask: false,
|
|
},
|
|
};
|
|
const byKey = new Map(vm.data.messages.map((message) => [chatMessageIdentityKey(message), message]));
|
|
byKey.set(chatMessageIdentityKey(localMessage), localMessage);
|
|
const messages = [...byKey.values()].sort((left, right) => left.createdAtIso.localeCompare(right.createdAtIso));
|
|
return {
|
|
...vm,
|
|
data: {
|
|
...vm.data,
|
|
messages,
|
|
messageGroups: groupChatMessagesByDay(messages),
|
|
},
|
|
};
|
|
}
|