From ca91dc2dc62869809fb882202a0478f259ad5e50 Mon Sep 17 00:00:00 2001 From: shubham yadav <126192924+yadavshubham01@users.noreply.github.com> Date: Wed, 6 Nov 2024 02:48:31 +0530 Subject: [PATCH] Add useUploadAttachment hook (#7617) (#7690) Reusing the useUploadAttachment Hook In the implementation of the feature to ensure the attachment table is updated whenever new images are added to a RICH_TEXT field #7617 , it is likely that the useUploadAttachment hook is reused. The useUploadAttachment hook is responsible for handling the upload of attachments, including images, and returning the uploaded file URL. By reusing this hook, you can leverage its existing functionality to handle image uploads within the RICH_TEXT field. In this case, the modified image handling logic would utilize the useUploadAttachment hook to upload new images added to the RICH_TEXT content. The hook would then return the uploaded file URL, which would be used to update the attachment table with the details of the newly added images. By reusing the useUploadAttachment hook, you can avoid duplicating code and ensure consistency in the way attachments are handled throughout the application. Fixes #6565 --------- Co-authored-by: Charles Bochet Co-authored-by: Lucas Bordeau --- .../activities/components/RichTextEditor.tsx | 90 +++---------------- .../files/hooks/useUploadAttachmentFile.tsx | 10 ++- 2 files changed, 22 insertions(+), 78 deletions(-) diff --git a/packages/twenty-front/src/modules/activities/components/RichTextEditor.tsx b/packages/twenty-front/src/modules/activities/components/RichTextEditor.tsx index 21ac7228d3da..26dd4204e631 100644 --- a/packages/twenty-front/src/modules/activities/components/RichTextEditor.tsx +++ b/packages/twenty-front/src/modules/activities/components/RichTextEditor.tsx @@ -1,7 +1,7 @@ import { useApolloClient } from '@apollo/client'; import { useCreateBlockNote } from '@blocknote/react'; import { isArray, isNonEmptyString } from '@sniptt/guards'; -import { ClipboardEvent, useCallback, useMemo } from 'react'; +import { useCallback, useMemo } from 'react'; import { useRecoilCallback, useRecoilState } from 'recoil'; import { Key } from 'ts-key-enum'; import { useDebouncedCallback } from 'use-debounce'; @@ -20,20 +20,16 @@ import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDraw import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { isNonTextWritingKey } from '@/ui/utilities/hotkey/utils/isNonTextWritingKey'; -import { FileFolder, useUploadFileMutation } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; -import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; - -import { getFileType } from '../files/utils/getFileType'; import { BLOCK_SCHEMA } from '@/activities/blocks/constants/Schema'; +import { useUploadAttachmentFile } from '@/activities/files/hooks/useUploadAttachmentFile'; import { Note } from '@/activities/types/Note'; import { Task } from '@/activities/types/Task'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import '@blocknote/core/fonts/inter.css'; import '@blocknote/mantine/style.css'; import '@blocknote/react/style.css'; -import { getFileAbsoluteURI } from '~/utils/file/getFileAbsoluteURI'; type RichTextEditorProps = { activityId: string; @@ -121,22 +117,13 @@ export const RichTextEditor = ({ canCreateActivityState, ); - const [uploadFile] = useUploadFileMutation(); + const { uploadAttachmentFile } = useUploadAttachmentFile(); - const handleUploadAttachment = async (file: File): Promise => { - if (isUndefinedOrNull(file)) { - return ''; - } - const result = await uploadFile({ - variables: { - file, - fileFolder: FileFolder.Attachment, - }, + const handleUploadAttachment = async (file: File) => { + return await uploadAttachmentFile(file, { + id: activityId, + targetObjectNameSingular: activityObjectNameSingular, }); - if (!result?.data?.uploadFile) { - throw new Error("Couldn't upload Image"); - } - return getFileAbsoluteURI(result.data.uploadFile); }; const prepareBody = (newStringifiedBody: string) => { @@ -152,8 +139,6 @@ export const RichTextEditor = ({ const imageProps = block.props; const imageUrl = new URL(imageProps.url); - imageUrl.searchParams.delete('token'); - return { ...block, props: { @@ -284,65 +269,19 @@ export const RichTextEditor = ({ } }, [activity, activityBody]); + const handleEditorBuiltInUploadFile = async (file: File) => { + const { attachementAbsoluteURL } = await handleUploadAttachment(file); + + return attachementAbsoluteURL; + }; + const editor = useCreateBlockNote({ initialContent: initialBody, domAttributes: { editor: { class: 'editor' } }, schema: BLOCK_SCHEMA, - uploadFile: handleUploadAttachment, + uploadFile: handleEditorBuiltInUploadFile, }); - const handleImagePaste = async (event: ClipboardEvent) => { - const clipboardItems = event.clipboardData?.items; - - if (isDefined(clipboardItems)) { - for (let i = 0; i < clipboardItems.length; i++) { - if (clipboardItems[i].kind === 'file') { - const isImage = clipboardItems[i].type.match('^image/'); - const pastedFile = clipboardItems[i].getAsFile(); - if (!pastedFile) { - return; - } - - const attachmentUrl = await handleUploadAttachment(pastedFile); - - if (!attachmentUrl) { - return; - } - - if (isDefined(isImage)) { - editor?.insertBlocks( - [ - { - type: 'image', - props: { - url: attachmentUrl, - }, - }, - ], - editor?.getTextCursorPosition().block, - 'after', - ); - } else { - editor?.insertBlocks( - [ - { - type: 'file', - props: { - url: attachmentUrl, - fileType: getFileType(pastedFile.name), - name: pastedFile.name, - }, - }, - ], - editor?.getTextCursorPosition().block, - 'after', - ); - } - } - } - } - }; - useScopedHotkeys( Key.Escape, () => { @@ -427,7 +366,6 @@ export const RichTextEditor = ({ diff --git a/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx b/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx index 301a324668a7..bbd8d6152af4 100644 --- a/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx +++ b/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx @@ -7,7 +7,9 @@ import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivi import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; +import { isNonEmptyString } from '@sniptt/guards'; import { FileFolder, useUploadFileMutation } from '~/generated/graphql'; +import { getFileAbsoluteURI } from '~/utils/file/getFileAbsoluteURI'; // Note: This is probably not the right way to do this. export const computePathWithoutToken = (attachmentPath: string): string => { @@ -36,8 +38,8 @@ export const useUploadAttachmentFile = () => { const attachmentPath = result?.data?.uploadFile; - if (!attachmentPath) { - return; + if (!isNonEmptyString(attachmentPath)) { + throw new Error("Couldn't upload the attachment."); } const targetableObjectFieldIdName = getActivityTargetObjectFieldIdName({ @@ -55,6 +57,10 @@ export const useUploadAttachmentFile = () => { } as Partial; await createOneAttachment(attachmentToCreate); + + const attachementAbsoluteURL = getFileAbsoluteURI(attachmentPath); + + return { attachementAbsoluteURL }; }; return { uploadAttachmentFile };