diff --git a/.changeset/unlucky-berries-guess.md b/.changeset/unlucky-berries-guess.md new file mode 100644 index 000000000000..5a4cc9aba3e9 --- /dev/null +++ b/.changeset/unlucky-berries-guess.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': minor +--- + +Replace the read receipt receipt indicator in order to improve the accessibility complience diff --git a/apps/meteor/client/components/message/ReadReceiptIndicator.tsx b/apps/meteor/client/components/message/ReadReceiptIndicator.tsx index a92faed363bd..90b3bb52c995 100644 --- a/apps/meteor/client/components/message/ReadReceiptIndicator.tsx +++ b/apps/meteor/client/components/message/ReadReceiptIndicator.tsx @@ -1,15 +1,29 @@ +import type { IMessage } from '@rocket.chat/core-typings'; import { Box, Icon } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; type ReadReceiptIndicatorProps = { + mid: IMessage['_id']; unread?: boolean; }; -const ReadReceiptIndicator = ({ unread }: ReadReceiptIndicatorProps): ReactElement | null => ( - - - -); +const ReadReceiptIndicator = ({ mid, unread }: ReadReceiptIndicatorProps): ReactElement | null => { + const t = useTranslation(); + + return ( + + + + ); +}; export default ReadReceiptIndicator; diff --git a/apps/meteor/client/components/message/variants/RoomMessage.tsx b/apps/meteor/client/components/message/variants/RoomMessage.tsx index dce673def68f..dd36dfa3eaff 100644 --- a/apps/meteor/client/components/message/variants/RoomMessage.tsx +++ b/apps/meteor/client/components/message/variants/RoomMessage.tsx @@ -69,7 +69,7 @@ const RoomMessage = ({ role='listitem' aria-roledescription={sequential ? t('sequential_message') : t('message')} tabIndex={0} - aria-labelledby={`${message._id}-displayName ${message._id}-time ${message._id}-content`} + aria-labelledby={`${message._id}-displayName ${message._id}-time ${message._id}-content ${message._id}-read-status`} onClick={selecting ? toggleSelected : undefined} isSelected={selected} isEditing={editing} diff --git a/apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx b/apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx index 29932e276215..84ea4039ca93 100644 --- a/apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx +++ b/apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx @@ -50,7 +50,7 @@ const RoomMessageContent = ({ message, unread, all, mention, searchText }: RoomM <> {(!encrypted || normalizedMessage.e2e === 'done') && ( )} - {readReceiptEnabled && } + {readReceiptEnabled && } ); }; diff --git a/apps/meteor/client/components/message/variants/thread/ThreadMessageContent.tsx b/apps/meteor/client/components/message/variants/thread/ThreadMessageContent.tsx index 8616f1223812..7098a2709d5b 100644 --- a/apps/meteor/client/components/message/variants/thread/ThreadMessageContent.tsx +++ b/apps/meteor/client/components/message/variants/thread/ThreadMessageContent.tsx @@ -75,7 +75,7 @@ const ThreadMessageContent = ({ message }: ThreadMessageContentProps): ReactElem )} - {readReceiptEnabled && } + {readReceiptEnabled && } ); }; diff --git a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx index 81748dab2dcd..086ed82efdf6 100644 --- a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx +++ b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx @@ -1,6 +1,5 @@ import type { ReadReceipt } from '@rocket.chat/core-typings'; -import { css } from '@rocket.chat/css-in-js'; -import { Box, Palette } from '@rocket.chat/fuselage'; +import { Box } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; import type { ReactElement } from 'react'; import React from 'react'; @@ -8,27 +7,12 @@ import React from 'react'; import { useFormatDateAndTime } from '../../../../hooks/useFormatDateAndTime'; import { useUserDisplayName } from '../../../../hooks/useUserDisplayName'; -const hoverStyle = css` - &:hover { - background-color: ${Palette.surface['surface-neutral']}; - } -`; - const ReadReceiptRow = ({ user, ts }: ReadReceipt): ReactElement => { const displayName = useUserDisplayName(user || {}); const formatDateAndTime = useFormatDateAndTime({ withSeconds: true }); return ( - + diff --git a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx index 418f45baefa5..c4da16264646 100644 --- a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx +++ b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx @@ -41,9 +41,13 @@ const ReadReceiptsModal = ({ messageId, onClose }: ReadReceiptsModalProps): Reac return ( {readReceipts.length < 1 && t('No_results_found')} - {readReceipts.map((receipt) => ( - - ))} + {readReceipts.length > 0 && ( +
+ {readReceipts.map((receipt) => ( + + ))} +
+ )}
); }; diff --git a/apps/meteor/ee/client/startup/readReceipt.ts b/apps/meteor/ee/client/startup/readReceipt.ts index 938cc4b6133f..94c2b0c65de1 100644 --- a/apps/meteor/ee/client/startup/readReceipt.ts +++ b/apps/meteor/ee/client/startup/readReceipt.ts @@ -17,8 +17,8 @@ Meteor.startup(() => { MessageAction.addButton({ id: 'receipt-detail', - icon: 'info-circled', - label: 'Info', + icon: 'double-check', + label: 'Read_Receipts', context: ['starred', 'message', 'message-mobile', 'threads', 'videoconf', 'videoconf-threads'], type: 'duplication', action(_, props) { diff --git a/apps/meteor/tests/e2e/read-receipts.spec.ts b/apps/meteor/tests/e2e/read-receipts.spec.ts new file mode 100644 index 000000000000..0fe4759472e8 --- /dev/null +++ b/apps/meteor/tests/e2e/read-receipts.spec.ts @@ -0,0 +1,51 @@ +import { IS_EE } from './config/constants'; +import { createAuxContext } from './fixtures/createAuxContext'; +import { Users } from './fixtures/userStates'; +import { HomeChannel } from './page-objects'; +import { createTargetChannel, setSettingValueById } from './utils'; +import { expect, test } from './utils/test'; + +test.use({ storageState: Users.admin.state }); + +test.describe.serial('read-receipts', () => { + let poHomeChannel: HomeChannel; + let targetChannel: string; + + test.skip(!IS_EE, 'Enterprise Only'); + + test.beforeAll(async ({ api }) => { + await setSettingValueById(api, 'Message_Read_Receipt_Enabled', true); + await setSettingValueById(api, 'Message_Read_Receipt_Store_Users', true); + + targetChannel = await createTargetChannel(api); + }); + + test.beforeEach(async ({ page }) => { + poHomeChannel = new HomeChannel(page); + + await page.goto('/home'); + }); + + test('should show read receipts message sent status in the sent message', async ({ browser }) => { + const { page } = await createAuxContext(browser, Users.user1); + const auxContext = { page, poHomeChannel: new HomeChannel(page) }; + await auxContext.poHomeChannel.sidenav.openChat(targetChannel); + await auxContext.poHomeChannel.content.sendMessage('hello admin'); + + await expect(auxContext.poHomeChannel.content.lastUserMessage.getByRole('status', { name: 'Message sent' })).toBeVisible(); + await auxContext.page.close(); + }); + + test('should show read receipts message viewed status in the sent message', async () => { + await poHomeChannel.sidenav.openChat(targetChannel); + await expect(poHomeChannel.content.lastUserMessage.getByRole('status', { name: 'Message viewed' })).toBeVisible(); + }); + + test('should show the reads receipt modal with the users who read the message', async ({ page }) => { + await poHomeChannel.sidenav.openChat(targetChannel); + await poHomeChannel.content.openLastMessageMenu(); + await page.locator('role=menuitem[name="Read receipts"]').click(); + + await expect(page.getByRole('dialog').getByRole('listitem')).toHaveCount(2); + }); +}); diff --git a/apps/meteor/tests/e2e/utils/index.ts b/apps/meteor/tests/e2e/utils/index.ts index 1939b8b2cb11..9f83fc0ae246 100644 --- a/apps/meteor/tests/e2e/utils/index.ts +++ b/apps/meteor/tests/e2e/utils/index.ts @@ -1 +1,2 @@ export * from './create-target-channel'; +export * from './setSettingValueById'; diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 82e2dc2860ff..1dc586fb0c4a 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -3619,6 +3619,8 @@ "Messages": "Messages", "Messages_selected": "Messages selected", "Messages_sent": "Messages sent", + "Message_sent": "Message sent", + "Message_viewed": "Message viewed", "Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here": "Messages that are sent to the Incoming WebHook will be posted here.", "Meta": "Meta", "Meta_Description": "Set custom Meta properties.",