diff --git a/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx b/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx index 3bbf1ccdc11..3b850d6a000 100644 --- a/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx +++ b/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx @@ -6,11 +6,14 @@ import { MessageGenericPreviewTitle, MessageGenericPreviewDescription, } from '@rocket.chat/fuselage'; +import { useUniqueId } from '@rocket.chat/fuselage-hooks'; import { useMediaUrl } from '@rocket.chat/ui-contexts'; import type { UIEvent } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { getFileExtension } from '../../../../../../lib/utils/getFileExtension'; +import { forAttachmentDownload, registerDownloadForUid } from '../../../../../hooks/useDownloadFromServiceWorker'; import MarkdownText from '../../../../MarkdownText'; import MessageCollapsible from '../../../MessageCollapsible'; import MessageContentBody from '../../../MessageContentBody'; @@ -31,18 +34,33 @@ const GenericFileAttachment = ({ collapsed, }: GenericFileAttachmentProps) => { const getURL = useMediaUrl(); + const uid = useUniqueId(); + const { t } = useTranslation(); const handleTitleClick = (event: UIEvent): void => { - if (openDocumentViewer && link && format === 'PDF') { + if (openDocumentViewer && link) { event.preventDefault(); - openDocumentViewer(`${getURL(link)}?contentDisposition=inline`, format, ''); + + if (format === 'PDF') { + const url = new URL(getURL(link)); + url.searchParams.set('contentDisposition', 'inline'); + openDocumentViewer(url.toString(), format, ''); + return; + } + + registerDownloadForUid(uid, t, title); + forAttachmentDownload(uid, link); } }; const getExternalUrl = () => { if (!hasDownload || !link) return undefined; - if (openDocumentViewer) return `${getURL(link)}?download`; + if (openDocumentViewer) { + const url = new URL(getURL(link), window.location.host); + url.searchParams.set('download', ''); + return url.toString(); + } return getURL(link); }; diff --git a/apps/meteor/client/hooks/useDownloadFromServiceWorker.ts b/apps/meteor/client/hooks/useDownloadFromServiceWorker.ts index 9a44d8d5fd2..5ab7f804fec 100644 --- a/apps/meteor/client/hooks/useDownloadFromServiceWorker.ts +++ b/apps/meteor/client/hooks/useDownloadFromServiceWorker.ts @@ -15,6 +15,23 @@ navigator.serviceWorker.addEventListener('message', (event) => { } }); +export const registerDownloadForUid = (uid: string, t: ReturnType['t'], title?: string) => { + ee.once(uid, ({ result }) => { + downloadAs({ data: [new Blob([result])] }, title ?? t('Download')); + }); +}; + +export const forAttachmentDownload = (uid: string, href: string, controller?: ServiceWorker | null) => { + if (!controller) { + controller = navigator.serviceWorker.controller; + } + controller?.postMessage({ + type: 'attachment-download', + url: href, + id: uid, + }); +}; + export const useDownloadFromServiceWorker = (href: string, title?: string) => { const { controller } = navigator.serviceWorker; @@ -22,13 +39,7 @@ export const useDownloadFromServiceWorker = (href: string, title?: string) => { const { t } = useTranslation(); - useEffect( - () => - ee.once(uid, ({ result }) => { - downloadAs({ data: [new Blob([result])] }, title ?? t('Download')); - }), - [title, t, uid], - ); + useEffect(() => registerDownloadForUid(uid, t, title), [title, t, uid]); return { disabled: !controller, @@ -37,11 +48,7 @@ export const useDownloadFromServiceWorker = (href: string, title?: string) => { (e: React.MouseEvent) => { e.preventDefault(); - controller?.postMessage({ - type: 'attachment-download', - url: href, - id: uid, - }); + forAttachmentDownload(uid, href, controller); }, [href, uid, controller], ), diff --git a/apps/meteor/client/lib/chats/flows/uploadFiles.ts b/apps/meteor/client/lib/chats/flows/uploadFiles.ts index ee1be0189ba..2cf0c70cd2f 100644 --- a/apps/meteor/client/lib/chats/flows/uploadFiles.ts +++ b/apps/meteor/client/lib/chats/flows/uploadFiles.ts @@ -3,6 +3,7 @@ import { isRoomFederated } from '@rocket.chat/core-typings'; import { e2e } from '../../../../app/e2e/client'; import { fileUploadIsValidContentType } from '../../../../app/utils/client'; +import { getFileExtension } from '../../../../lib/utils/getFileExtension'; import FileUploadModal from '../../../views/room/modals/FileUploadModal'; import { imperativeModal } from '../../imperativeModal'; import { prependReplies } from '../../utils/prependReplies'; @@ -137,7 +138,7 @@ export const uploadFiles = async (chat: ChatAPI, files: readonly File[], resetFi attachments.push({ ...attachment, size: file.size, - // format: getFileExtension(file.name), + format: getFileExtension(file.name), }); } diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx index f7ce6077ded..9c52b78ca59 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx @@ -8,6 +8,7 @@ import { useSubscription } from 'use-subscription'; import { getUserDisplayName } from '../../../../../lib/getUserDisplayName'; import { QuoteAttachment } from '../../../../components/message/content/attachments/QuoteAttachment'; +import AttachmentProvider from '../../../../providers/AttachmentProvider'; import { useChat } from '../../contexts/ChatContext'; const MessageBoxReplies = (): ReactElement | null => { @@ -39,19 +40,21 @@ const MessageBoxReplies = (): ReactElement | null => { {replies.map((reply, key) => ( - ({ ...obj, collapsed: true })), - collapsed: true, - } as MessageQuoteAttachment - } - /> + + ({ ...obj, collapsed: true })), + collapsed: true, + } as MessageQuoteAttachment + } + /> + ; @@ -31,7 +32,9 @@ const PinMessageModal = ({ message, ...props }: PinMessageModalProps): ReactElem {t('Are_you_sure_you_want_to_pin_this_message')} - + + + {t('Pinned_messages_are_visible_to_everyone')}