Skip to content

Commit 79c67c7

Browse files
authored
feat: Disable confirm button while requesting delete message (RocketChat#37276)
1 parent 65fbcbe commit 79c67c7

6 files changed

Lines changed: 88 additions & 37 deletions

File tree

.changeset/moody-spoons-press.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/meteor': minor
3+
---
4+
5+
Disables the delete message confirmation button to prevent the action from being triggered while the request is in progress

apps/meteor/client/lib/chats/flows/requestMessageDeletion.ts

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import type { IMessage } from '@rocket.chat/core-typings';
2-
import { GenericModal, imperativeModal } from '@rocket.chat/ui-client';
2+
import { imperativeModal } from '@rocket.chat/ui-client';
33

44
import { t } from '../../../../app/utils/lib/i18n';
5+
import DeleteMessageConfirmModal from '../../../views/room/modals/DeleteMessageConfirmModal';
56
import { dispatchToastMessage } from '../../toast';
67
import type { ChatAPI } from '../ChatAPI';
78

@@ -15,28 +16,6 @@ export const requestMessageDeletion = async (chat: ChatAPI, message: IMessage):
1516

1617
await new Promise<void>((resolve, reject) => {
1718
const mid = chat.currentEditingMessage.getMID();
18-
const onConfirm = async (): Promise<void> => {
19-
try {
20-
if (!(await chat.data.canDeleteMessage(message))) {
21-
dispatchToastMessage({ type: 'error', message: t('Message_deleting_blocked') });
22-
return;
23-
}
24-
await chat.data.deleteMessage(message);
25-
26-
imperativeModal.close();
27-
28-
if (mid === message._id) {
29-
chat.currentEditingMessage.stop();
30-
}
31-
chat.composer?.focus();
32-
33-
dispatchToastMessage({ type: 'success', message: t('Your_entry_has_been_deleted') });
34-
resolve();
35-
} catch (error) {
36-
dispatchToastMessage({ type: 'error', message: error });
37-
reject(error);
38-
}
39-
};
4019

4120
const onCloseModal = async (): Promise<void> => {
4221
imperativeModal.close();
@@ -50,14 +29,13 @@ export const requestMessageDeletion = async (chat: ChatAPI, message: IMessage):
5029
};
5130

5231
imperativeModal.open({
53-
component: GenericModal,
32+
component: DeleteMessageConfirmModal,
5433
props: {
55-
title: t('Are_you_sure'),
56-
children: room ? t('The_message_is_a_discussion_you_will_not_be_able_to_recover') : t('You_will_not_be_able_to_recover'),
57-
variant: 'danger',
58-
confirmText: t('Yes_delete_it'),
59-
onConfirm,
60-
onClose: onCloseModal,
34+
room,
35+
chat,
36+
resolve,
37+
reject,
38+
message,
6139
onCancel: onCloseModal,
6240
},
6341
});
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import type { IMessage, IRoom } from '@rocket.chat/core-typings';
2+
import { GenericModal } from '@rocket.chat/ui-client';
3+
import { useToastMessageDispatch } from '@rocket.chat/ui-contexts';
4+
import { useMutation } from '@tanstack/react-query';
5+
import { useTranslation } from 'react-i18next';
6+
7+
import type { ChatAPI } from '../../../../lib/chats/ChatAPI';
8+
9+
const DeleteMessageConfirmModal = ({
10+
room,
11+
chat,
12+
resolve,
13+
reject,
14+
onCancel,
15+
message,
16+
}: {
17+
room?: IRoom;
18+
chat: ChatAPI;
19+
resolve: () => void;
20+
reject: (reason?: any) => void;
21+
message: IMessage;
22+
onCancel: () => void;
23+
}) => {
24+
const { t } = useTranslation();
25+
const mid = chat.currentEditingMessage.getMID();
26+
const dispatchToastMessage = useToastMessageDispatch();
27+
28+
const deleteMessageMutation = useMutation({
29+
mutationFn: async () => {
30+
if (!(await chat.data.canDeleteMessage(message))) {
31+
throw new Error(t('Message_deleting_blocked'));
32+
}
33+
34+
await chat.data.deleteMessage(message);
35+
},
36+
onSuccess: () => {
37+
if (mid === message._id) {
38+
chat.currentEditingMessage.stop();
39+
}
40+
chat.composer?.focus();
41+
42+
dispatchToastMessage({ type: 'success', message: t('Your_entry_has_been_deleted') });
43+
resolve();
44+
},
45+
onError: (error) => {
46+
dispatchToastMessage({ type: 'error', message: error });
47+
reject(error);
48+
},
49+
onSettled: () => {
50+
onCancel();
51+
},
52+
});
53+
54+
return (
55+
<GenericModal
56+
variant='danger'
57+
title={t('Are_you_sure')}
58+
confirmText={t('Yes_delete_it')}
59+
children={room ? t('The_message_is_a_discussion_you_will_not_be_able_to_recover') : t('You_will_not_be_able_to_recover')}
60+
onConfirm={deleteMessageMutation.mutate}
61+
onCancel={onCancel}
62+
confirmDisabled={deleteMessageMutation.isPending}
63+
/>
64+
);
65+
};
66+
67+
export default DeleteMessageConfirmModal;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './DeleteMessageConfirmModal';

apps/meteor/tests/e2e/message-actions.spec.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,10 @@ test.describe.serial('message-actions', () => {
116116
await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('this message was edited');
117117
});
118118

119-
test('expect message is deleted', async ({ page }) => {
119+
test('should delete message ', async () => {
120120
await poHomeChannel.content.sendMessage('Message to delete');
121-
await poHomeChannel.content.openLastMessageMenu();
122-
await page.locator('role=menuitem[name="Delete"]').click();
123-
await page.locator('#modal-root .rcx-button-group--align-end .rcx-button--danger').click();
121+
await poHomeChannel.content.deleteLastMessage();
122+
124123
await expect(poHomeChannel.content.lastUserMessage.locator('[data-qa-type="message-body"]:has-text("Message to delete")')).toHaveCount(
125124
0,
126125
);

apps/meteor/tests/e2e/page-objects/fragments/home-content.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -438,9 +438,9 @@ export class HomeContent {
438438
}
439439

440440
async openLastMessageMenu(): Promise<void> {
441-
await this.page.locator('[data-qa-type="message"]').last().hover();
442-
await this.page.locator('[data-qa-type="message"]').last().locator('role=button[name="More"]').waitFor();
443-
await this.page.locator('[data-qa-type="message"]').last().locator('role=button[name="More"]').click();
441+
await this.lastUserMessage.hover();
442+
await this.lastUserMessage.getByRole('button', { name: 'More', exact: true }).waitFor();
443+
await this.lastUserMessage.getByRole('button', { name: 'More', exact: true }).click();
444444
}
445445

446446
get threadMessageList(): Locator {
@@ -574,6 +574,7 @@ export class HomeContent {
574574
await this.openLastMessageMenu();
575575
await this.btnOptionDeleteMessage.click();
576576
await this.btnModalConfirmDelete.click();
577+
await expect(this.btnModalConfirmDelete).toBeDisabled();
577578
}
578579

579580
get btnClearSelection() {

0 commit comments

Comments
 (0)