From 542420eb7345aa02ebdd66b50a765616c2f1ce47 Mon Sep 17 00:00:00 2001 From: Rajat Dabade Date: Mon, 2 Jun 2025 10:59:17 +0530 Subject: [PATCH] MM-64243 Fix the animation delay while send the post in the channel (#8868) * MM-64243 Fix the animation delay while send the post in the channel * Updated test and logic --------- Co-authored-by: Mattermost Build --- .../send_draft/send_draft.test.tsx | 1 + .../send_handler/send_handler.test.tsx | 51 -------------- app/hooks/handle_send_message.test.tsx | 66 ++----------------- app/hooks/handle_send_message.ts | 41 ++++++------ 4 files changed, 27 insertions(+), 132 deletions(-) diff --git a/app/components/draft_scheduled_post/draft_scheduled_post_actions/send_draft/send_draft.test.tsx b/app/components/draft_scheduled_post/draft_scheduled_post_actions/send_draft/send_draft.test.tsx index c194275fe..957a64f50 100644 --- a/app/components/draft_scheduled_post/draft_scheduled_post_actions/send_draft/send_draft.test.tsx +++ b/app/components/draft_scheduled_post/draft_scheduled_post_actions/send_draft/send_draft.test.tsx @@ -162,6 +162,7 @@ describe('Send Draft', () => { }); it('should call dismissBottomSheet after sending the draft and should call createPost', async () => { + jest.mocked(canPostDraftInChannelOrThread).mockResolvedValueOnce(true); jest.mocked(sendMessageWithAlert).mockImplementation(() => { return Promise.resolve(); }); diff --git a/app/components/post_draft/send_handler/send_handler.test.tsx b/app/components/post_draft/send_handler/send_handler.test.tsx index ffc1309fe..82fb996b7 100644 --- a/app/components/post_draft/send_handler/send_handler.test.tsx +++ b/app/components/post_draft/send_handler/send_handler.test.tsx @@ -8,12 +8,10 @@ import {removeDraft} from '@actions/local/draft'; import {createPost} from '@actions/remote/post'; import {General} from '@constants'; import {DRAFT_TYPE_DRAFT, DRAFT_TYPE_SCHEDULED} from '@constants/draft'; -import {SNACK_BAR_TYPE} from '@constants/snack_bar'; import {renderWithEverything} from '@test/intl-test-helper'; import TestHelper from '@test/test_helper'; import {sendMessageWithAlert} from '@utils/post'; import {canPostDraftInChannelOrThread} from '@utils/scheduled_post'; -import {showSnackBar} from '@utils/snack_bar'; import SendHandler from './send_handler'; @@ -260,53 +258,4 @@ describe('components/post_draft/send_handler/SendHandler', () => { // Varify removeDraft function is been called. expect(removeDraft).toHaveBeenCalled(); }); - - it('should show snackbar if creating post failing when executing sendMessageHandler when send_draft_button is checked', async () => { - // Mock implementation to capture the sendMessageHandler - let capturedHandler: Function; - jest.mocked(sendMessageWithAlert).mockImplementation((params) => { - capturedHandler = params.sendMessageHandler; - return Promise.resolve(); - }); - jest.mocked(createPost).mockResolvedValueOnce({ - error: new Error('Failed to create post'), - }); - - const props = { - ...baseProps, - isFromDraftView: true, - draftType: DRAFT_TYPE_DRAFT, - value: 'test message', - }; - - const wrapper = renderWithEverything( - , {database}, - ); - - // Find and press the send button - const sendButton = wrapper.getByTestId('send_draft_button'); - - await act(async () => { - fireEvent.press(sendButton); - }); - - // Verify sendMessageWithAlert was called - expect(sendMessageWithAlert).toHaveBeenCalledWith(expect.objectContaining({ - sendMessageHandler: expect.any(Function), - })); - - // Now execute the captured handler to simulate user confirming the send - await act(async () => { - await capturedHandler(); - }); - - expect(showSnackBar).toHaveBeenCalledWith({ - barType: SNACK_BAR_TYPE.CREATE_POST_ERROR, - customMessage: 'Failed to create post', - type: 'error', - }); - - // Varify removeDraft function is been called. - expect(removeDraft).not.toHaveBeenCalled(); - }); }); diff --git a/app/hooks/handle_send_message.test.tsx b/app/hooks/handle_send_message.test.tsx index 0e50c5d1b..ea74b5916 100644 --- a/app/hooks/handle_send_message.test.tsx +++ b/app/hooks/handle_send_message.test.tsx @@ -13,13 +13,11 @@ import {createPost} from '@actions/remote/post'; import {createScheduledPost} from '@actions/remote/scheduled_post'; import {handleCallsSlashCommand} from '@calls/actions'; import {Events, Screens} from '@constants'; -import {SNACK_BAR_TYPE} from '@constants/snack_bar'; import {useServerUrl} from '@context/server'; import DatabaseManager from '@database/manager'; import DraftUploadManager from '@managers/draft_upload_manager'; import {getPostById} from '@queries/servers/post'; import * as DraftUtils from '@utils/draft'; -import {showSnackBar} from '@utils/snack_bar'; import {useHandleSendMessage} from './handle_send_message'; @@ -87,6 +85,10 @@ describe('useHandleSendMessage', () => { }); }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('should handle basic message send', async () => { const {result} = renderHook(() => useHandleSendMessage(defaultProps), {wrapper}); @@ -395,24 +397,6 @@ describe('useHandleSendMessage', () => { expect(defaultProps.clearDraft).toHaveBeenCalled(); }); - it('should handle failed post creation', async () => { - jest.mocked(createPost).mockResolvedValueOnce({ - error: new Error('Failed to create post'), - }); - - const props = { - ...defaultProps, - value: 'test message', - }; - - const {result} = renderHook(() => useHandleSendMessage(props), {wrapper}); - - await act(async () => { - const response = await result.current.handleSendMessage(); - expect(response?.error).toBeDefined(); - }); - }); - it('should fetch and handle channel timezones', async () => { jest.mocked(getChannelTimezones).mockResolvedValueOnce({ channelTimezones: ['UTC', 'America/New_York'], @@ -434,21 +418,6 @@ describe('useHandleSendMessage', () => { ); }); - it('should not allow sending during message submission', () => { - const props = { - ...defaultProps, - value: 'test message', - }; - - const {result} = renderHook(() => useHandleSendMessage(props), {wrapper}); - - act(() => { - result.current.handleSendMessage(); - }); - - expect(result.current.canSend).toBe(false); - }); - it('should handle channel-wide mentions confirmation', async () => { jest.spyOn(DraftUtils, 'textContainsAtAllAtChannel').mockReturnValue(true); jest.spyOn(DraftUtils, 'alertChannelWideMention'); @@ -662,33 +631,6 @@ describe('useHandleSendMessage', () => { }); }); - it('should handle failed post creation', async () => { - jest.mocked(createPost).mockResolvedValueOnce({ - error: new Error('Failed to create post'), - }); - - const props = { - ...defaultProps, - isFromDraftView: true, - value: 'test message', - }; - - const {result} = renderHook(() => useHandleSendMessage(props), {wrapper}); - - await act(async () => { - const response = await result.current.handleSendMessage(); - expect(response?.error).toBeDefined(); - }); - - expect(showSnackBar).toHaveBeenCalledWith({ - barType: SNACK_BAR_TYPE.CREATE_POST_ERROR, - customMessage: 'Failed to create post', - type: 'error', - }); - expect(defaultProps.clearDraft).not.toHaveBeenCalled(); - expect(DeviceEventEmitter.emit).not.toHaveBeenCalled(); - }); - it('should show alert when root post is not found', async () => { jest.mocked(getPostById).mockResolvedValueOnce(undefined); diff --git a/app/hooks/handle_send_message.ts b/app/hooks/handle_send_message.ts index 70380e236..28e201e6e 100644 --- a/app/hooks/handle_send_message.ts +++ b/app/hooks/handle_send_message.ts @@ -106,7 +106,7 @@ export const useHandleSendMessage = ({ setSendingMessage(false); }, [serverUrl, rootId, clearDraft]); - const doSubmitMessage = useCallback(async (schedulingInfo?: SchedulingInfo): Promise => { + const doSubmitMessage = useCallback(async (schedulingInfo?: SchedulingInfo) => { const postFiles = files.filter((f) => !f.failed); const post = { user_id: currentUserId, @@ -128,20 +128,16 @@ export const useHandleSendMessage = ({ let response: CreateResponse; if (schedulingInfo) { response = await createScheduledPost(serverUrl, scheduledPostFromPost(post, schedulingInfo, postPriority, postFiles)); - } else { - response = await createPost(serverUrl, post, postFiles); - } - - if (response.error && isFromDraftView) { - showSnackBar({ - barType: SNACK_BAR_TYPE.CREATE_POST_ERROR, - customMessage: getErrorMessage(response.error), - type: MESSAGE_TYPE.ERROR, - }); - return response; - } - - if (isFromDraftView) { + if (response.error) { + showSnackBar({ + barType: SNACK_BAR_TYPE.SCHEDULED_POST_CREATION_ERROR, + customMessage: getErrorMessage(response.error), + type: MESSAGE_TYPE.ERROR, + }); + } else { + clearDraft(); + } + } else if (isFromDraftView) { const shouldClearDraft = await canPostDraftInChannelOrThread({ serverUrl, rootId, @@ -152,16 +148,23 @@ export const useHandleSendMessage = ({ deactivatedChannel, }); - if (shouldClearDraft) { - clearDraft(); + if (!shouldClearDraft) { + return; } + + createPost(serverUrl, post, postFiles); + clearDraft(); + + // Early return to avoid calling DeviceEventEmitter.emit + return; } else { + // Response error is handled at the post level so don't have to wait to clear draft + createPost(serverUrl, post, postFiles); clearDraft(); } + setSendingMessage(false); DeviceEventEmitter.emit(Events.POST_LIST_SCROLL_TO_BOTTOM, rootId ? Screens.THREAD : Screens.CHANNEL); - - return response; }, [files, currentUserId, channelId, rootId, value, postPriority, isFromDraftView, serverUrl, intl, canPost, channelIsArchived, channelIsReadOnly, deactivatedChannel, clearDraft]); const showSendToAllOrChannelOrHereAlert = useCallback((calculatedMembersCount: number, atHere: boolean, schedulingInfo?: SchedulingInfo) => {