diff --git a/.changeset/seven-pugs-argue.md b/.changeset/seven-pugs-argue.md new file mode 100644 index 000000000000..f4a549124fc7 --- /dev/null +++ b/.changeset/seven-pugs-argue.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixed using real names on messages reactions diff --git a/apps/meteor/client/components/message/content/Reactions.tsx b/apps/meteor/client/components/message/content/Reactions.tsx index 712504ec7a2c..5f2e82b6b742 100644 --- a/apps/meteor/client/components/message/content/Reactions.tsx +++ b/apps/meteor/client/components/message/content/Reactions.tsx @@ -1,9 +1,9 @@ import type { IMessage } from '@rocket.chat/core-typings'; import { MessageReactions, MessageReactionAction } from '@rocket.chat/fuselage'; import type { ReactElement } from 'react'; -import React from 'react'; +import React, { useContext } from 'react'; -import { useOpenEmojiPicker, useReactionsFilter, useUserHasReacted } from '../list/MessageListContext'; +import { MessageListContext, useOpenEmojiPicker, useUserHasReacted } from '../list/MessageListContext'; import Reaction from './reactions/Reaction'; import { useToggleReactionMutation } from './reactions/useToggleReactionMutation'; @@ -13,9 +13,8 @@ type ReactionsProps = { const Reactions = ({ message }: ReactionsProps): ReactElement => { const hasReacted = useUserHasReacted(message); - const filterReactions = useReactionsFilter(message); const openEmojiPicker = useOpenEmojiPicker(message); - + const { username } = useContext(MessageListContext); const toggleReactionMutation = useToggleReactionMutation(); return ( @@ -27,7 +26,8 @@ const Reactions = ({ message }: ReactionsProps): ReactElement => { counter={reactions.usernames.length} hasReacted={hasReacted} name={name} - names={filterReactions(name)} + names={reactions.usernames.filter((user) => user !== username)} + messageId={message._id} onClick={() => toggleReactionMutation.mutate({ mid: message._id, reaction: name })} /> ))} diff --git a/apps/meteor/client/components/message/content/reactions/Reaction.tsx b/apps/meteor/client/components/message/content/reactions/Reaction.tsx index cf68e65b8829..c3ad037d0ccb 100644 --- a/apps/meteor/client/components/message/content/reactions/Reaction.tsx +++ b/apps/meteor/client/components/message/content/reactions/Reaction.tsx @@ -1,11 +1,14 @@ import { MessageReaction as MessageReactionTemplate, MessageReactionEmoji, MessageReactionCounter } from '@rocket.chat/fuselage'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useTooltipClose, useTooltipOpen, useTranslation } from '@rocket.chat/ui-contexts'; +import { useQueryClient } from '@tanstack/react-query'; import type { ReactElement } from 'react'; -import React, { useRef } from 'react'; +import React, { useContext, useRef } from 'react'; import { getEmojiClassNameAndDataTitle } from '../../../../lib/utils/renderEmoji'; +import { useGetMessageByID } from '../../../../views/room/contextualBar/Threads/hooks/useGetMessageByID'; import MarkdownText from '../../../MarkdownText'; +import { MessageListContext } from '../../list/MessageListContext'; // TODO: replace it with proper usage of i18next plurals const getTranslationKey = (users: string[], mine: boolean): TranslationKey => { @@ -33,14 +36,16 @@ type ReactionProps = { counter: number; name: string; names: string[]; + messageId: string; onClick: () => void; }; -const Reaction = ({ hasReacted, counter, name, names, ...props }: ReactionProps): ReactElement => { +const Reaction = ({ hasReacted, counter, name, names, messageId, ...props }: ReactionProps): ReactElement => { const t = useTranslation(); const ref = useRef(null); const openTooltip = useTooltipOpen(); const closeTooltip = useTooltipClose(); + const { showRealName, username } = useContext(MessageListContext); const mine = hasReacted(name); @@ -48,6 +53,42 @@ const Reaction = ({ hasReacted, counter, name, names, ...props }: ReactionProps) const emojiProps = getEmojiClassNameAndDataTitle(name); + const getMessage = useGetMessageByID(); + + const queryClient = useQueryClient(); + + const getNames = async () => { + return queryClient.fetchQuery( + ['chat.getMessage', 'reactions', messageId, names], + async () => { + // This happens if the only reaction is from the current user + if (!names.length) { + return []; + } + + if (!showRealName) { + return names; + } + + const data = await getMessage(messageId); + + const { reactions } = data; + if (!reactions) { + return []; + } + + if (username) { + const index = reactions[name].usernames.indexOf(username); + index >= 0 && reactions[name].names?.splice(index, 1); + return (reactions[name].names || names).filter(Boolean); + } + + return reactions[name].names || names; + }, + { staleTime: 1000 * 60 * 5 }, + ); + }; + return ( { + // if data-tooltip is not set, the tooltip will close on first mouse enter + data-tooltip + onMouseEnter={async (e) => { e.stopPropagation(); e.preventDefault(); + + const users = await getNames(); + ref.current && openTooltip( 10 ? names.length - 10 : names.length, - users: names.slice(0, 10).join(', '), + users: users?.slice(0, 10).join(', ') || '', emoji: name, })} variant='inline' diff --git a/apps/meteor/client/components/message/list/MessageListContext.tsx b/apps/meteor/client/components/message/list/MessageListContext.tsx index 156679fe5463..82cca7377bb6 100644 --- a/apps/meteor/client/components/message/list/MessageListContext.tsx +++ b/apps/meteor/client/components/message/list/MessageListContext.tsx @@ -7,7 +7,6 @@ export type MessageListContextValue = { useShowFollowing: ({ message }: { message: IMessage }) => boolean; useMessageDateFormatter: () => (date: Date) => string; useUserHasReacted: (message: IMessage) => (reaction: string) => boolean; - useReactionsFilter: (message: IMessage) => (reaction: string) => string[]; useOpenEmojiPicker: (message: IMessage) => (event: React.MouseEvent) => void; showRoles: boolean; showRealName: boolean; @@ -25,6 +24,7 @@ export type MessageListContextValue = { autoTranslateLanguage?: string; showColors: boolean; jumpToMessageParam?: string; + username: string | undefined; scrollMessageList?: (callback: (wrapper: HTMLDivElement | null) => ScrollToOptions | void) => void; }; @@ -38,15 +38,12 @@ export const MessageListContext = createContext({ (date: Date): string => date.toString(), useOpenEmojiPicker: () => (): void => undefined, - useReactionsFilter: - (message) => - (reaction: string): string[] => - message.reactions ? message.reactions[reaction]?.usernames || [] : [], showRoles: false, showRealName: false, showUsername: false, showColors: false, scrollMessageList: () => undefined, + username: undefined, }); export const useShowTranslated: MessageListContextValue['useShowTranslated'] = (...args) => @@ -69,5 +66,3 @@ export const useUserHasReacted: MessageListContextValue['useUserHasReacted'] = ( useContext(MessageListContext).useUserHasReacted(message); export const useOpenEmojiPicker: MessageListContextValue['useOpenEmojiPicker'] = (...args) => useContext(MessageListContext).useOpenEmojiPicker(...args); -export const useReactionsFilter: MessageListContextValue['useReactionsFilter'] = (message: IMessage) => - useContext(MessageListContext).useReactionsFilter(message); diff --git a/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx b/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx index ab196b189242..925d5787e396 100644 --- a/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx +++ b/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx @@ -1,5 +1,4 @@ -import type { IMessage } from '@rocket.chat/core-typings'; -import { isMessageReactionsNormalized, isThreadMainMessage } from '@rocket.chat/core-typings'; +import { isThreadMainMessage } from '@rocket.chat/core-typings'; import { useLayout, useUser, useUserPreference, useSetting, useEndpoint, useSearchParameter } from '@rocket.chat/ui-contexts'; import type { VFC, ReactNode } from 'react'; import React, { useMemo, memo } from 'react'; @@ -60,29 +59,6 @@ const MessageListProvider: VFC = ({ children, scrollMe const context: MessageListContextValue = useMemo( () => ({ showColors, - useReactionsFilter: (message: IMessage): ((reaction: string) => string[]) => { - const { reactions } = message; - return !showRealName - ? (reaction: string): string[] => - reactions?.[reaction]?.usernames.filter((user) => user !== username).map((username) => `@${username}`) || [] - : (reaction: string): string[] => { - if (!reactions?.[reaction]) { - return []; - } - if (!isMessageReactionsNormalized(message)) { - return message.reactions?.[reaction]?.usernames.filter((user) => user !== username).map((username) => `@${username}`) || []; - } - if (!username) { - return message.reactions[reaction].names; - } - const index = message.reactions[reaction].usernames.indexOf(username); - if (index === -1) { - return message.reactions[reaction].names; - } - - return message.reactions[reaction].names.splice(index, 1); - }; - }, useUserHasReacted: username ? (message) => (reaction): boolean => @@ -126,6 +102,7 @@ const MessageListProvider: VFC = ({ children, scrollMe chat?.emojiPicker.open(e.currentTarget, (emoji: string) => reactToMessage({ messageId: message._id, reaction: emoji })); } : () => (): void => undefined, + username, }), [ username, diff --git a/packages/core-typings/src/IMessage/IMessage.ts b/packages/core-typings/src/IMessage/IMessage.ts index 190446502f02..cb8edb49a85a 100644 --- a/packages/core-typings/src/IMessage/IMessage.ts +++ b/packages/core-typings/src/IMessage/IMessage.ts @@ -287,9 +287,6 @@ export interface IMessageReactionsNormalized extends IMessage { }; } -export const isMessageReactionsNormalized = (message: IMessage): message is IMessageReactionsNormalized => - Boolean('reactions' in message && message.reactions && message.reactions[0] && 'names' in message.reactions[0]); - export interface IOmnichannelSystemMessage extends IMessage { navigation?: { page: {