diff --git a/src/components/Icons.tsx b/src/components/Icons.tsx index 008a7a893..d329e043d 100644 --- a/src/components/Icons.tsx +++ b/src/components/Icons.tsx @@ -640,6 +640,20 @@ export function RightArrow(props: IconProps) { ); } +export function UploadIcon(props: IconProps) { + return ( + + + + ); +} + export function TopRightArrow(props: IconProps) { return ( { + try { + if (!input.files) return; + await addAttachments(channelId, messageId, existingAttachmentCount, input.files); + } finally { + input.remove(); + } + }); +} + +async function addAttachments(channelId: string, messageId: string, existingAttachmentCount: number, files: FileList) { + if (!files) return; + + if (files.length + existingAttachmentCount > 10) { + const remaining = 10 - existingAttachmentCount; + if (remaining <= 0) { + showToast("You cannot add more attachments to this message.", Toasts.Type.FAILURE); + return; + } + + showToast(`You can only add ${pluralise(remaining, "more attachment")} to this message.`, Toasts.Type.FAILURE); + return; + } + + showToast("Uploading, this can take a while...", Toasts.Type.CLOCK); + + const { body: { attachments } } = await RestAPI.post({ + url: `/channels/${channelId}/attachments`, + body: { + files: Array.from(files, file => ({ + filename: file.name, + file_size: file.size, + id: uniqueId(), + is_clip: false + })) + } + }) as { body: { attachments: { id: string, upload_url: string, upload_filename: string; }[]; }; }; + + const newAttachments = await Promise.all( + attachments.map((file, i) => + fetch(file.upload_url, { + method: "PUT", + body: files[i] + }).then(() => ({ + id: file.id, + uploaded_filename: file.upload_filename, + filename: files[i].name + })) + ) + ); + + + const msg = MessageStore.getMessage(channelId, messageId); + + await RestAPI.patch({ + url: `/channels/${channelId}/messages/${messageId}`, + body: { + attachments: [ + ...msg.attachments, + ...newAttachments + ] + } + }); + + showToast(`${files.length === 1 ? "Attachment" : "Attachments"} added successfully!`, Toasts.Type.SUCCESS); +} + +function canAddAttachments(msg: Message) { + return ( + [MessageType.DEFAULT, MessageType.REPLY].includes(msg.type) && + !msg.hasFlag(MessageFlags.IS_VOICE_MESSAGE) && + AuthenticationStore.getId() === msg.author.id && + msg.attachments.length < 10 + ); +} + +function handlePaste(e: ClipboardEvent) { + if (!e.clipboardData?.files.length) return; + + const msg = EditMessageStore.getEditingMessage(SelectedChannelStore.getChannelId()); + if (!msg) return; + + e.preventDefault(); + e.stopImmediatePropagation(); + + addAttachments(msg.channel_id, msg.id, msg.attachments.length, e.clipboardData.files); +} + +export default definePlugin({ + name: "AddAttachments", + description: "Allows you to add new attachments while editing messages", + authors: [Devs.Lumap], + + start() { + document.addEventListener("paste", handlePaste, { capture: true }); + }, + stop() { + document.removeEventListener("paste", handlePaste, { capture: true }); + }, + + messagePopoverButton: { + icon: UploadIcon, + render(msg) { + if (!canAddAttachments(msg)) return null; + + const channel = ChannelStore.getChannel(msg.channel_id); + if (!channel.isPrivate() && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return null; + + return { + label: "Add Attachments", + icon: UploadIcon, + message: msg, + channel: ChannelStore.getChannel(msg.channel_id), + onClick: () => chooseAttachments(msg.channel_id, msg.id, msg.attachments.length) + }; + }, + }, + + chatBarButton: { + icon: UploadIcon, + render({ channel, type }) { + if (type.analyticsName !== "edit") return null; + + const msg = EditMessageStore.getEditingMessage(channel.id); + if (!msg || !canAddAttachments(msg)) return null; + + return ( + chooseAttachments(msg.channel_id, msg.id, msg.attachments.length)} + > + + + ); + } + } +});