From f89741d174c8ead2c5af7cbd1ccd8bd5382846bc Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Fri, 14 Feb 2025 15:27:57 -0300 Subject: [PATCH] refactor: Moves `getUserDisplayName` outside from meteor app (#35031) --- .../app/lib/server/functions/attachMessage.ts | 2 +- .../server/startup/mentionUserNotInChannel.ts | 3 +- .../UserMenu/UserMenuHeader.tsx | 2 +- .../client/components/UserInfo/UserInfo.tsx | 2 +- .../components/message/MessageHeader.tsx | 7 ++- .../message/variants/SystemMessage.tsx | 5 +- apps/meteor/client/hooks/useRoomName.ts | 3 +- .../client/lib/getUserDisplayName.spec.ts | 16 ++++++ .../client/sidebar/header/UserMenuHeader.tsx | 2 +- .../moderation/helpers/ContextMessage.tsx | 2 +- .../views/conference/ConferencePage.tsx | 2 +- .../MessageList/ContactHistoryMessage.tsx | 5 +- .../hooks/useOutlookOpenCall.ts | 2 +- .../views/room/UserCard/UserCardWithData.tsx | 2 +- .../RoomForeword/RoomForewordUsernameList.tsx | 3 - .../RoomForewordUsernameListItem.tsx | 8 +-- .../composer/messageBox/MessageBoxReplies.tsx | 48 ++-------------- .../composer/messageBox/MessageBoxReply.tsx | 55 +++++++++++++++++++ .../VideoConfList/VideoConfListItem.tsx | 7 ++- .../hooks/useVideoConfRoomName.ts | 3 +- .../actions/useReportUser.tsx | 2 +- .../ForwardMessageModal.tsx | 2 +- .../PinMessageModal/PinMessageModal.tsx | 2 +- .../ReadReceiptsModal/ReadReceiptRow.tsx | 2 +- apps/meteor/lib/createQuoteAttachment.ts | 4 +- apps/meteor/lib/getUserDisplayName.ts | 4 -- .../server/lib/rooms/roomCoordinator.ts | 2 +- packages/core-typings/src/IUser.ts | 3 + .../VideoConferenceBlock.tsx | 11 +++- packages/ui-client/src/components/index.ts | 1 - packages/ui-client/src/hooks/index.ts | 7 +++ .../src/hooks/useUserDisplayName.spec.ts | 36 ++++++++++++ .../src}/hooks/useUserDisplayName.ts | 3 +- packages/ui-client/src/index.ts | 6 +- .../VideoConfMessageUserStack.tsx | 7 ++- 35 files changed, 170 insertions(+), 101 deletions(-) create mode 100644 apps/meteor/client/lib/getUserDisplayName.spec.ts create mode 100644 apps/meteor/client/views/room/composer/messageBox/MessageBoxReply.tsx delete mode 100644 apps/meteor/lib/getUserDisplayName.ts create mode 100644 packages/ui-client/src/hooks/index.ts create mode 100644 packages/ui-client/src/hooks/useUserDisplayName.spec.ts rename {apps/meteor/client => packages/ui-client/src}/hooks/useUserDisplayName.ts (83%) diff --git a/apps/meteor/app/lib/server/functions/attachMessage.ts b/apps/meteor/app/lib/server/functions/attachMessage.ts index d7bd45ba01b..ce5f3aaf7c8 100644 --- a/apps/meteor/app/lib/server/functions/attachMessage.ts +++ b/apps/meteor/app/lib/server/functions/attachMessage.ts @@ -1,6 +1,6 @@ +import { getUserDisplayName } from '@rocket.chat/core-typings'; import type { IMessage, IRoom, MessageAttachment } from '@rocket.chat/core-typings'; -import { getUserDisplayName } from '../../../../lib/getUserDisplayName'; import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; import { settings } from '../../../settings/server/cached'; import { getUserAvatarURL } from '../../../utils/server/getUserAvatarURL'; diff --git a/apps/meteor/app/lib/server/startup/mentionUserNotInChannel.ts b/apps/meteor/app/lib/server/startup/mentionUserNotInChannel.ts index 68d18cbfeac..45d1343f357 100644 --- a/apps/meteor/app/lib/server/startup/mentionUserNotInChannel.ts +++ b/apps/meteor/app/lib/server/startup/mentionUserNotInChannel.ts @@ -1,12 +1,11 @@ import { api } from '@rocket.chat/core-services'; import type { IMessage } from '@rocket.chat/core-typings'; -import { isDirectMessageRoom, isEditedMessage, isOmnichannelRoom, isRoomFederated } from '@rocket.chat/core-typings'; +import { isDirectMessageRoom, isEditedMessage, isOmnichannelRoom, isRoomFederated, getUserDisplayName } from '@rocket.chat/core-typings'; import { Subscriptions, Users } from '@rocket.chat/models'; import type { ActionsBlock } from '@rocket.chat/ui-kit'; import moment from 'moment'; import { callbacks } from '../../../../lib/callbacks'; -import { getUserDisplayName } from '../../../../lib/getUserDisplayName'; import { isTruthy } from '../../../../lib/isTruthy'; import { i18n } from '../../../../server/lib/i18n'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenuHeader.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenuHeader.tsx index 158b666b64c..9c506cf350f 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenuHeader.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenuHeader.tsx @@ -1,12 +1,12 @@ import type { IUser } from '@rocket.chat/core-typings'; import { Box, Margins } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useSetting } from '@rocket.chat/ui-contexts'; import { useTranslation } from 'react-i18next'; import MarkdownText from '../../../components/MarkdownText'; import { UserStatus } from '../../../components/UserStatus'; -import { useUserDisplayName } from '../../../hooks/useUserDisplayName'; type UserMenuHeaderProps = { user: IUser }; diff --git a/apps/meteor/client/components/UserInfo/UserInfo.tsx b/apps/meteor/client/components/UserInfo/UserInfo.tsx index cbd5fb3b90e..4a0413d9128 100644 --- a/apps/meteor/client/components/UserInfo/UserInfo.tsx +++ b/apps/meteor/client/components/UserInfo/UserInfo.tsx @@ -1,5 +1,6 @@ import type { IUser, Serialized } from '@rocket.chat/core-typings'; import { Box, Margins, Tag } from '@rocket.chat/fuselage'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; import { memo } from 'react'; @@ -7,7 +8,6 @@ import { useTranslation } from 'react-i18next'; import { useTimeAgo } from '../../hooks/useTimeAgo'; import { useUserCustomFields } from '../../hooks/useUserCustomFields'; -import { useUserDisplayName } from '../../hooks/useUserDisplayName'; import { ContextualbarScrollableContent } from '../Contextualbar'; import { InfoPanel, diff --git a/apps/meteor/client/components/message/MessageHeader.tsx b/apps/meteor/client/components/message/MessageHeader.tsx index 1a2109f2c67..8a259a88178 100644 --- a/apps/meteor/client/components/message/MessageHeader.tsx +++ b/apps/meteor/client/components/message/MessageHeader.tsx @@ -7,6 +7,7 @@ import { MessageStatusPrivateIndicator, MessageNameContainer, } from '@rocket.chat/fuselage'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import type { KeyboardEvent, ReactElement } from 'react'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -14,7 +15,6 @@ import { useTranslation } from 'react-i18next'; import StatusIndicators from './StatusIndicators'; import MessageRoles from './header/MessageRoles'; import { useMessageListShowUsername, useMessageListShowRealName, useMessageListShowRoles } from './list/MessageListContext'; -import { getUserDisplayName } from '../../../lib/getUserDisplayName'; import { useFormatDateAndTime } from '../../hooks/useFormatDateAndTime'; import { useFormatTime } from '../../hooks/useFormatTime'; import { useUserData } from '../../hooks/useUserData'; @@ -37,6 +37,7 @@ const MessageHeader = ({ message }: MessageHeaderProps): ReactElement => { const user: UserPresence = { ...message.u, roles: [], ...useUserData(message.u._id) }; const usernameAndRealNameAreSame = !user.name || user.username === user.name; const showUsername = useMessageListShowUsername() && showRealName && !usernameAndRealNameAreSame; + const displayName = useUserDisplayName(user); const showRoles = useMessageListShowRoles(); const roles = useMessageRoles(message.u._id, message.rid, showRoles); @@ -48,7 +49,7 @@ const MessageHeader = ({ message }: MessageHeaderProps): ReactElement => { tabIndex={0} role='button' id={`${message._id}-displayName`} - aria-label={getUserDisplayName(user.name, user.username, showRealName)} + aria-label={displayName} onClick={(e) => openUserCard(e, message.u.username)} onKeyDown={(e: KeyboardEvent) => { (e.code === 'Enter' || e.code === 'Space') && openUserCard(e, message.u.username); @@ -61,7 +62,7 @@ const MessageHeader = ({ message }: MessageHeaderProps): ReactElement => { title={!showUsername && !usernameAndRealNameAreSame ? `@${user.username}` : undefined} data-username={user.username} > - {message.alias || getUserDisplayName(user.name, user.username, showRealName)} + {message.alias || displayName} {showUsername && ( <> diff --git a/apps/meteor/client/components/message/variants/SystemMessage.tsx b/apps/meteor/client/components/message/variants/SystemMessage.tsx index 7824ad7bec9..34e8b48ee27 100644 --- a/apps/meteor/client/components/message/variants/SystemMessage.tsx +++ b/apps/meteor/client/components/message/variants/SystemMessage.tsx @@ -12,13 +12,13 @@ import { MessageNameContainer, } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactElement, KeyboardEvent } from 'react'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { MessageTypes } from '../../../../app/ui-utils/client'; -import { getUserDisplayName } from '../../../../lib/getUserDisplayName'; import { useFormatDateAndTime } from '../../../hooks/useFormatDateAndTime'; import { useFormatTime } from '../../../hooks/useFormatTime'; import { useUserData } from '../../../hooks/useUserData'; @@ -49,6 +49,7 @@ const SystemMessage = ({ message, showUserAvatar, ...props }: SystemMessageProps const user: UserPresence = { ...message.u, roles: [], ...useUserData(message.u._id) }; const usernameAndRealNameAreSame = !user.name || user.username === user.name; const showUsername = useMessageListShowUsername() && showRealName && !usernameAndRealNameAreSame; + const displayName = useUserDisplayName(user); const messageType = MessageTypes.getType(message); @@ -85,7 +86,7 @@ const SystemMessage = ({ message, showUserAvatar, ...props }: SystemMessageProps style={{ cursor: 'pointer' }} {...triggerProps} > - {getUserDisplayName(user.name, user.username, showRealName)} + {displayName} {showUsername && ( <> {' '} diff --git a/apps/meteor/client/hooks/useRoomName.ts b/apps/meteor/client/hooks/useRoomName.ts index 62cfd45568f..e0f4c2dbdd2 100644 --- a/apps/meteor/client/hooks/useRoomName.ts +++ b/apps/meteor/client/hooks/useRoomName.ts @@ -1,9 +1,8 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { isDirectMessageRoom } from '@rocket.chat/core-typings'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useUserSubscription } from '@rocket.chat/ui-contexts'; -import { useUserDisplayName } from './useUserDisplayName'; - /** * * Hook to get the name of the room diff --git a/apps/meteor/client/lib/getUserDisplayName.spec.ts b/apps/meteor/client/lib/getUserDisplayName.spec.ts new file mode 100644 index 00000000000..b99311b1ee1 --- /dev/null +++ b/apps/meteor/client/lib/getUserDisplayName.spec.ts @@ -0,0 +1,16 @@ +import { getUserDisplayName } from '@rocket.chat/core-typings'; + +const fakeUser = { + name: 'John Doe', + username: 'john.doe', +}; + +it('should return username if UI_Use_Real_Name setting is false', () => { + const result = getUserDisplayName(fakeUser.name, fakeUser.username, false); + expect(result).toBe(fakeUser.username); +}); + +it('should return name if UI_Use_Real_Name setting is true', () => { + const result = getUserDisplayName(fakeUser.name, fakeUser.username, true); + expect(result).toBe(fakeUser.name); +}); diff --git a/apps/meteor/client/sidebar/header/UserMenuHeader.tsx b/apps/meteor/client/sidebar/header/UserMenuHeader.tsx index 05a0a79e7cf..16e7b094bf8 100644 --- a/apps/meteor/client/sidebar/header/UserMenuHeader.tsx +++ b/apps/meteor/client/sidebar/header/UserMenuHeader.tsx @@ -1,12 +1,12 @@ import type { IUser } from '@rocket.chat/core-typings'; import { Box, Margins } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useSetting } from '@rocket.chat/ui-contexts'; import { useTranslation } from 'react-i18next'; import MarkdownText from '../../components/MarkdownText'; import { UserStatus } from '../../components/UserStatus'; -import { useUserDisplayName } from '../../hooks/useUserDisplayName'; const UserMenuHeader = ({ user }: { user: IUser }) => { const { t } = useTranslation(); diff --git a/apps/meteor/client/views/admin/moderation/helpers/ContextMessage.tsx b/apps/meteor/client/views/admin/moderation/helpers/ContextMessage.tsx index 94a6e37ba87..2d5081c2f69 100644 --- a/apps/meteor/client/views/admin/moderation/helpers/ContextMessage.tsx +++ b/apps/meteor/client/views/admin/moderation/helpers/ContextMessage.tsx @@ -2,6 +2,7 @@ import type { IMessage, MessageReport, MessageAttachment } from '@rocket.chat/co import { isE2EEMessage, isQuoteAttachment } from '@rocket.chat/core-typings'; import { Message, MessageName, MessageToolbarItem, MessageToolbarWrapper, MessageUsername } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useSetting } from '@rocket.chat/ui-contexts'; import { useTranslation } from 'react-i18next'; @@ -12,7 +13,6 @@ import UiKitMessageBlock from '../../../../components/message/uikit/UiKitMessage import { useFormatDate } from '../../../../hooks/useFormatDate'; import { useFormatDateAndTime } from '../../../../hooks/useFormatDateAndTime'; import { useFormatTime } from '../../../../hooks/useFormatTime'; -import { useUserDisplayName } from '../../../../hooks/useUserDisplayName'; import MessageReportInfo from '../MessageReportInfo'; import useDeleteMessage from '../hooks/useDeleteMessage'; import { useDismissMessageAction } from '../hooks/useDismissMessageAction'; diff --git a/apps/meteor/client/views/conference/ConferencePage.tsx b/apps/meteor/client/views/conference/ConferencePage.tsx index 6131218c52a..5717f4d823c 100644 --- a/apps/meteor/client/views/conference/ConferencePage.tsx +++ b/apps/meteor/client/views/conference/ConferencePage.tsx @@ -1,9 +1,9 @@ +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useRoute, useSetModal, useUser } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import { useEffect } from 'react'; import ConferencePageError from './ConferencePageError'; -import { useUserDisplayName } from '../../hooks/useUserDisplayName'; import { useVideoConfOpenCall } from '../room/contextualBar/VideoConference/hooks/useVideoConfOpenCall'; import PageLoading from '../root/PageLoading'; diff --git a/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx b/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx index f7631134ece..901b97ed2c7 100644 --- a/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx +++ b/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx @@ -19,10 +19,10 @@ import { Bubble, } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getUserDisplayName } from '../../../../../lib/getUserDisplayName'; import MessageContentBody from '../../../../components/message/MessageContentBody'; import StatusIndicators from '../../../../components/message/StatusIndicators'; import Attachments from '../../../../components/message/content/Attachments'; @@ -44,6 +44,7 @@ const ContactHistoryMessage = ({ message, sequential, isNewDay, showUserAvatar } const format = useFormatDate(); const formatTime = useFormatTime(); + const displayName = useUserDisplayName(message.u); const quotes = message?.attachments?.filter(isQuoteAttachment) || []; @@ -106,7 +107,7 @@ const ContactHistoryMessage = ({ message, sequential, isNewDay, showUserAvatar } {!sequential && ( - {message.alias || getUserDisplayName(message.u.name, message.u.username, false)} + {message.alias || displayName} @{message.u.username} diff --git a/apps/meteor/client/views/outlookCalendar/hooks/useOutlookOpenCall.ts b/apps/meteor/client/views/outlookCalendar/hooks/useOutlookOpenCall.ts index 80269ec04b5..acde6ebfe63 100644 --- a/apps/meteor/client/views/outlookCalendar/hooks/useOutlookOpenCall.ts +++ b/apps/meteor/client/views/outlookCalendar/hooks/useOutlookOpenCall.ts @@ -1,6 +1,6 @@ +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useUser } from '@rocket.chat/ui-contexts'; -import { useUserDisplayName } from '../../../hooks/useUserDisplayName'; import { useVideoConfOpenCall } from '../../room/contextualBar/VideoConference/hooks/useVideoConfOpenCall'; export const useOutlookOpenCall = (meetingUrl?: string) => { diff --git a/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx b/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx index cb514a70d51..c9b3e722965 100644 --- a/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx +++ b/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx @@ -1,3 +1,4 @@ +import { getUserDisplayName } from '@rocket.chat/core-typings'; import type { IRoom } from '@rocket.chat/core-typings'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { GenericMenu } from '@rocket.chat/ui-client'; @@ -6,7 +7,6 @@ import type { ReactElement } from 'react'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getUserDisplayName } from '../../../../lib/getUserDisplayName'; import LocalTime from '../../../components/LocalTime'; import { UserCard, UserCardAction, UserCardRole, UserCardSkeleton } from '../../../components/UserCard'; import { ReactiveUserStatus } from '../../../components/UserStatus'; diff --git a/apps/meteor/client/views/room/body/RoomForeword/RoomForewordUsernameList.tsx b/apps/meteor/client/views/room/body/RoomForeword/RoomForewordUsernameList.tsx index 6e62ab42a55..015cc591693 100644 --- a/apps/meteor/client/views/room/body/RoomForeword/RoomForewordUsernameList.tsx +++ b/apps/meteor/client/views/room/body/RoomForeword/RoomForewordUsernameList.tsx @@ -1,6 +1,5 @@ import type { IUser } from '@rocket.chat/core-typings'; import { Margins } from '@rocket.chat/fuselage'; -import { useSetting } from '@rocket.chat/ui-contexts'; import RoomForewordUsernameListItem from './RoomForewordUsernameListItem'; import { roomCoordinator } from '../../../../lib/rooms/roomCoordinator'; @@ -8,7 +7,6 @@ import { roomCoordinator } from '../../../../lib/rooms/roomCoordinator'; type RoomForewordUsernameListProps = { usernames: Array> }; const RoomForewordUsernameList = ({ usernames }: RoomForewordUsernameListProps) => { - const useRealName = useSetting('UI_Use_Real_Name', false); return ( {usernames.map((username) => ( @@ -16,7 +14,6 @@ const RoomForewordUsernameList = ({ usernames }: RoomForewordUsernameListProps) username={username} key={username} href={roomCoordinator.getRouteLink('d', { name: username }) || undefined} - useRealName={useRealName} /> ))} diff --git a/apps/meteor/client/views/room/body/RoomForeword/RoomForewordUsernameListItem.tsx b/apps/meteor/client/views/room/body/RoomForeword/RoomForewordUsernameListItem.tsx index 48c0cd36a70..83fdce994b6 100644 --- a/apps/meteor/client/views/room/body/RoomForeword/RoomForewordUsernameListItem.tsx +++ b/apps/meteor/client/views/room/body/RoomForeword/RoomForewordUsernameListItem.tsx @@ -1,23 +1,23 @@ import type { IUser } from '@rocket.chat/core-typings'; import { Icon, Tag, Skeleton } from '@rocket.chat/fuselage'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; -import { getUserDisplayName } from '../../../../../lib/getUserDisplayName'; import { useUserInfoQuery } from '../../../../hooks/useUserInfoQuery'; type RoomForewordUsernameListItemProps = { href: string | undefined; username: NonNullable; - useRealName: boolean; }; -const RoomForewordUsernameListItem = ({ username, href, useRealName }: RoomForewordUsernameListItemProps) => { +const RoomForewordUsernameListItem = ({ username, href }: RoomForewordUsernameListItemProps) => { const { data, isLoading, isError, isSuccess } = useUserInfoQuery({ username }); + const displayName = useUserDisplayName({ name: data?.user?.name, username }); return ( } data-username={username} large href={href}> {isLoading && } {isError && username} - {isSuccess && getUserDisplayName(data?.user?.name, username, useRealName)} + {isSuccess && displayName} ); }; diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx index 6428426c8cf..1a4b6d48a56 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx @@ -1,13 +1,8 @@ -import type { MessageQuoteAttachment } from '@rocket.chat/core-typings'; -import { css } from '@rocket.chat/css-in-js'; -import { IconButton, Box, Margins } from '@rocket.chat/fuselage'; -import { useSetting } from '@rocket.chat/ui-contexts'; +import { Box } from '@rocket.chat/fuselage'; import type { ReactElement } from 'react'; import { memo, useSyncExternalStore } from 'react'; -import { getUserDisplayName } from '../../../../../lib/getUserDisplayName'; -import { QuoteAttachment } from '../../../../components/message/content/attachments/QuoteAttachment'; -import AttachmentProvider from '../../../../providers/AttachmentProvider'; +import MessageBoxReply from './MessageBoxReply'; import { useChat } from '../../contexts/ChatContext'; const MessageBoxReplies = (): ReactElement | null => { @@ -19,49 +14,14 @@ const MessageBoxReplies = (): ReactElement | null => { const replies = useSyncExternalStore(chat.composer.quotedMessages.subscribe, chat.composer.quotedMessages.get); - const useRealName = useSetting('UI_Use_Real_Name', false); - if (!replies.length) { return null; } - const closeWrapperStyle = css` - position: absolute; - right: 0.5rem; - top: 0.75rem; - `; - return ( - {replies.map((reply, key) => ( - - - - ({ ...obj, collapsed: true })), - collapsed: true, - } as MessageQuoteAttachment - } - /> - - { - chat.composer?.dismissQuotedMessage(reply._id); - }} - > - - - - + {replies.map((reply) => ( + ))} ); diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxReply.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBoxReply.tsx new file mode 100644 index 00000000000..321a196308f --- /dev/null +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxReply.tsx @@ -0,0 +1,55 @@ +import type { IMessage, MessageQuoteAttachment } from '@rocket.chat/core-typings'; +import { css } from '@rocket.chat/css-in-js'; +import { IconButton, Box, Margins } from '@rocket.chat/fuselage'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; +import type { ReactElement } from 'react'; +import { memo } from 'react'; + +import { QuoteAttachment } from '../../../../components/message/content/attachments/QuoteAttachment'; +import AttachmentProvider from '../../../../providers/AttachmentProvider'; +import { useChat } from '../../contexts/ChatContext'; + +const MessageBoxReply = ({ reply }: { reply: IMessage }): ReactElement | null => { + const chat = useChat(); + + const displayName = useUserDisplayName(reply?.u); + + const closeWrapperStyle = css` + position: absolute; + right: 0.5rem; + top: 0.75rem; + `; + + return ( + + + + ({ ...obj, collapsed: true })), + collapsed: true, + } as MessageQuoteAttachment + } + /> + + { + chat?.composer?.dismissQuotedMessage(reply._id); + }} + > + + + + + ); +}; + +export default memo(MessageBoxReply); diff --git a/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListItem.tsx b/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListItem.tsx index 9f3e04fd4de..a131208998b 100644 --- a/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListItem.tsx +++ b/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListItem.tsx @@ -3,7 +3,8 @@ import { css } from '@rocket.chat/css-in-js'; import { Button, Message, Box, Avatar, Palette, IconButton, ButtonGroup } from '@rocket.chat/fuselage'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { UserAvatar } from '@rocket.chat/ui-avatar'; -import { useTranslation, useSetting } from '@rocket.chat/ui-contexts'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; +import { useTranslation } from '@rocket.chat/ui-contexts'; import { useVideoConfJoinCall } from '@rocket.chat/ui-video-conf'; import type { ReactElement } from 'react'; @@ -24,7 +25,6 @@ const VideoConfListItem = ({ const t = useTranslation(); const formatDate = useTimeAgo(); const joinCall = useVideoConfJoinCall(); - const showRealName = useSetting('UI_Use_Real_Name', false); const { _id: callId, @@ -35,6 +35,7 @@ const VideoConfListItem = ({ discussionRid, } = videoConfData; + const displayName = useUserDisplayName({ name, username }); const joinedUsers = users.filter((user) => user._id !== _id); const hovered = css` @@ -67,7 +68,7 @@ const VideoConfListItem = ({ {username && } - {showRealName ? name : username} + {displayName} {formatDate(createdAt)} diff --git a/apps/meteor/client/views/room/contextualBar/VideoConference/hooks/useVideoConfRoomName.ts b/apps/meteor/client/views/room/contextualBar/VideoConference/hooks/useVideoConfRoomName.ts index a8676ebc5c1..b560b6dda07 100644 --- a/apps/meteor/client/views/room/contextualBar/VideoConference/hooks/useVideoConfRoomName.ts +++ b/apps/meteor/client/views/room/contextualBar/VideoConference/hooks/useVideoConfRoomName.ts @@ -1,9 +1,8 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { isDirectMessageRoom } from '@rocket.chat/core-typings'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useUserSubscription } from '@rocket.chat/ui-contexts'; -import { useUserDisplayName } from '../../../../../hooks/useUserDisplayName'; - export const useVideoConfRoomName = (room: IRoom): string | undefined => { const subscription = useUserSubscription(room._id); const username = useUserDisplayName({ name: subscription?.fname, username: subscription?.name }); diff --git a/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useReportUser.tsx b/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useReportUser.tsx index a80039f1748..9ace47406c9 100644 --- a/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useReportUser.tsx +++ b/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useReportUser.tsx @@ -1,10 +1,10 @@ import type { IUser } from '@rocket.chat/core-typings'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useEndpoint, useSetModal, useToastMessageDispatch, useUserId } from '@rocket.chat/ui-contexts'; import { useMutation } from '@tanstack/react-query'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { useUserDisplayName } from '../../../../../hooks/useUserDisplayName'; import ReportUserModal from '../../../contextualBar/UserInfo/ReportUserModal'; import type { UserInfoAction } from '../useUserInfoActions'; diff --git a/apps/meteor/client/views/room/modals/ForwardMessageModal/ForwardMessageModal.tsx b/apps/meteor/client/views/room/modals/ForwardMessageModal/ForwardMessageModal.tsx index bf9d4a042fb..36f3bcb5bbd 100644 --- a/apps/meteor/client/views/room/modals/ForwardMessageModal/ForwardMessageModal.tsx +++ b/apps/meteor/client/views/room/modals/ForwardMessageModal/ForwardMessageModal.tsx @@ -1,6 +1,7 @@ import type { IMessage, MessageQuoteAttachment } from '@rocket.chat/core-typings'; import { Modal, Field, FieldGroup, FieldLabel, FieldRow, FieldHint, ButtonGroup, Button } from '@rocket.chat/fuselage'; import { useClipboard } from '@rocket.chat/fuselage-hooks'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useTranslation, useEndpoint, useToastMessageDispatch, useUserAvatarPath } from '@rocket.chat/ui-contexts'; import { useMutation } from '@tanstack/react-query'; import type { ReactElement } from 'react'; @@ -9,7 +10,6 @@ import { useForm, Controller } from 'react-hook-form'; import UserAndRoomAutoCompleteMultiple from '../../../../components/UserAndRoomAutoCompleteMultiple'; import { QuoteAttachment } from '../../../../components/message/content/attachments/QuoteAttachment'; -import { useUserDisplayName } from '../../../../hooks/useUserDisplayName'; import { prependReplies } from '../../../../lib/utils/prependReplies'; type ForwardMessageProps = { diff --git a/apps/meteor/client/views/room/modals/PinMessageModal/PinMessageModal.tsx b/apps/meteor/client/views/room/modals/PinMessageModal/PinMessageModal.tsx index 2568a0e1215..11394efe1bb 100644 --- a/apps/meteor/client/views/room/modals/PinMessageModal/PinMessageModal.tsx +++ b/apps/meteor/client/views/room/modals/PinMessageModal/PinMessageModal.tsx @@ -1,11 +1,11 @@ import type { MessageQuoteAttachment, IMessage } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import { useTranslation, useUserAvatarPath } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactElement } from 'react'; import GenericModal from '../../../../components/GenericModal'; import { QuoteAttachment } from '../../../../components/message/content/attachments/QuoteAttachment'; -import { useUserDisplayName } from '../../../../hooks/useUserDisplayName'; import AttachmentProvider from '../../../../providers/AttachmentProvider'; type PinMessageModalProps = { message: IMessage } & ComponentProps; diff --git a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx index d6e870992da..6b10cc60280 100644 --- a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx +++ b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx @@ -1,10 +1,10 @@ import type { ReadReceipt } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; +import { useUserDisplayName } from '@rocket.chat/ui-client'; import type { ReactElement } from 'react'; import { useFormatDateAndTime } from '../../../../hooks/useFormatDateAndTime'; -import { useUserDisplayName } from '../../../../hooks/useUserDisplayName'; const ReadReceiptRow = ({ user, ts }: ReadReceipt): ReactElement => { const displayName = useUserDisplayName(user || {}); diff --git a/apps/meteor/lib/createQuoteAttachment.ts b/apps/meteor/lib/createQuoteAttachment.ts index 99e0f6f9229..d7a757b1549 100644 --- a/apps/meteor/lib/createQuoteAttachment.ts +++ b/apps/meteor/lib/createQuoteAttachment.ts @@ -1,8 +1,6 @@ -import { isTranslatedMessage } from '@rocket.chat/core-typings'; +import { isTranslatedMessage, getUserDisplayName } from '@rocket.chat/core-typings'; import type { ITranslatedMessage, IMessage } from '@rocket.chat/core-typings'; -import { getUserDisplayName } from './getUserDisplayName'; - export function createQuoteAttachment( message: IMessage | ITranslatedMessage, messageLink: string, diff --git a/apps/meteor/lib/getUserDisplayName.ts b/apps/meteor/lib/getUserDisplayName.ts deleted file mode 100644 index 5722a39be8a..00000000000 --- a/apps/meteor/lib/getUserDisplayName.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { IUser } from '@rocket.chat/core-typings'; - -export const getUserDisplayName = (name: IUser['name'], username: IUser['username'], useRealName: boolean): string | undefined => - useRealName ? name || username : username; diff --git a/apps/meteor/server/lib/rooms/roomCoordinator.ts b/apps/meteor/server/lib/rooms/roomCoordinator.ts index 4f4242f5a34..0f5ff97bdc2 100644 --- a/apps/meteor/server/lib/rooms/roomCoordinator.ts +++ b/apps/meteor/server/lib/rooms/roomCoordinator.ts @@ -1,9 +1,9 @@ +import { getUserDisplayName } from '@rocket.chat/core-typings'; import type { IRoom, RoomType, IUser, IMessage, ReadReceipt, ValueOf, AtLeast } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; import { settings } from '../../../app/settings/server'; import type { IRoomTypeConfig, IRoomTypeServerDirectives, RoomSettingsEnum, RoomMemberActions } from '../../../definition/IRoomTypeConfig'; -import { getUserDisplayName } from '../../../lib/getUserDisplayName'; import { RoomCoordinator } from '../../../lib/rooms/coordinator'; class RoomCoordinatorServer extends RoomCoordinator { diff --git a/packages/core-typings/src/IUser.ts b/packages/core-typings/src/IUser.ts index 0a2905b2ed9..c1ba49b556e 100644 --- a/packages/core-typings/src/IUser.ts +++ b/packages/core-typings/src/IUser.ts @@ -264,3 +264,6 @@ export type AvatarServiceObject = { }; export type AvatarObject = AvatarReset | AvatarUrlObj | FormData | AvatarServiceObject; + +export const getUserDisplayName = (name: IUser['name'], username: IUser['username'], useRealName: boolean): string | undefined => + useRealName ? name || username : username; diff --git a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx index cb1d861dc33..a1937e0416d 100644 --- a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx @@ -1,4 +1,7 @@ -import { VideoConferenceStatus } from '@rocket.chat/core-typings'; +import { + getUserDisplayName, + VideoConferenceStatus, +} from '@rocket.chat/core-typings'; import { useGoToRoom, useSetting, @@ -42,7 +45,7 @@ const VideoConferenceBlock = ({ const userId = useUserId(); const goToRoom = useGoToRoom(); const displayAvatars = useUserPreference('displayAvatars'); - const showRealName = useSetting('UI_Use_Real_Name'); + const showRealName = useSetting('UI_Use_Real_Name', false); const { action, viewId = undefined, rid } = useContext(UiKitContext); @@ -127,7 +130,9 @@ const VideoConferenceBlock = ({ const joinedNamesOrUsernames = [...data.users] .splice(0, MAX_USERS) - .map(({ name, username }) => (showRealName ? name || username : username)) + .map(({ name, username }) => + getUserDisplayName(name, username, showRealName), + ) .join(', '); const title = diff --git a/packages/ui-client/src/components/index.ts b/packages/ui-client/src/components/index.ts index 7308c8e7543..4b637518ebd 100644 --- a/packages/ui-client/src/components/index.ts +++ b/packages/ui-client/src/components/index.ts @@ -4,7 +4,6 @@ export * from './ExternalLink'; export * from './DotLeader'; export * from './CustomFieldsForm'; export * from './PasswordVerifier/PasswordVerifier'; -export * from '../hooks/useValidatePassword'; export { default as TextSeparator } from './TextSeparator'; export * from './TooltipComponent'; export * as UserStatus from './UserStatus'; diff --git a/packages/ui-client/src/hooks/index.ts b/packages/ui-client/src/hooks/index.ts new file mode 100644 index 00000000000..eff3cd8569d --- /dev/null +++ b/packages/ui-client/src/hooks/index.ts @@ -0,0 +1,7 @@ +export * from './useFeaturePreview'; +export * from './useDefaultSettingFeaturePreviewList'; +export * from './useFeaturePreviewList'; +export * from './usePreferenceFeaturePreviewList'; +export * from './useDocumentTitle'; +export * from './useUserDisplayName'; +export * from './useValidatePassword'; diff --git a/packages/ui-client/src/hooks/useUserDisplayName.spec.ts b/packages/ui-client/src/hooks/useUserDisplayName.spec.ts new file mode 100644 index 00000000000..a4ed61fbc9b --- /dev/null +++ b/packages/ui-client/src/hooks/useUserDisplayName.spec.ts @@ -0,0 +1,36 @@ +import { mockAppRoot } from '@rocket.chat/mock-providers'; +import { renderHook } from '@testing-library/react'; + +import { useUserDisplayName } from './useUserDisplayName'; + +const fakeUser = { + name: 'John Doe', + username: 'john.doe', +}; + +it('should return username if UI_Use_Real_Name setting is false', () => { + const { result } = renderHook(() => useUserDisplayName(fakeUser), { + legacyRoot: true, + wrapper: mockAppRoot().withSetting('UI_Use_Real_Name', false).build(), + }); + + expect(result.current).toBe(fakeUser.username); +}); + +it('should return name if UI_Use_Real_Name setting is true', () => { + const { result } = renderHook(() => useUserDisplayName(fakeUser), { + legacyRoot: true, + wrapper: mockAppRoot().withSetting('UI_Use_Real_Name', true).build(), + }); + + expect(result.current).toBe(fakeUser.name); +}); + +it('should return username if UI_Use_Real_Name setting is true and user has no name', () => { + const { result } = renderHook(() => useUserDisplayName({ ...fakeUser, name: undefined }), { + legacyRoot: true, + wrapper: mockAppRoot().withSetting('UI_Use_Real_Name', true).build(), + }); + + expect(result.current).toBe(fakeUser.username); +}); diff --git a/apps/meteor/client/hooks/useUserDisplayName.ts b/packages/ui-client/src/hooks/useUserDisplayName.ts similarity index 83% rename from apps/meteor/client/hooks/useUserDisplayName.ts rename to packages/ui-client/src/hooks/useUserDisplayName.ts index bbfc38f1d44..8bbefd6cefb 100644 --- a/apps/meteor/client/hooks/useUserDisplayName.ts +++ b/packages/ui-client/src/hooks/useUserDisplayName.ts @@ -1,8 +1,7 @@ import type { IUser } from '@rocket.chat/core-typings'; +import { getUserDisplayName } from '@rocket.chat/core-typings'; import { useSetting } from '@rocket.chat/ui-contexts'; -import { getUserDisplayName } from '../../lib/getUserDisplayName'; - export const useUserDisplayName = ({ name, username }: Pick): string | undefined => { const useRealName = useSetting('UI_Use_Real_Name'); diff --git a/packages/ui-client/src/index.ts b/packages/ui-client/src/index.ts index a96ef265aad..0938345895e 100644 --- a/packages/ui-client/src/index.ts +++ b/packages/ui-client/src/index.ts @@ -1,7 +1,3 @@ export * from './components'; -export * from './hooks/useFeaturePreview'; -export * from './hooks/useDefaultSettingFeaturePreviewList'; -export * from './hooks/useFeaturePreviewList'; -export * from './hooks/usePreferenceFeaturePreviewList'; -export * from './hooks/useDocumentTitle'; export * from './helpers'; +export * from './hooks'; diff --git a/packages/ui-video-conf/src/VideoConfMessage/VideoConfMessageUserStack.tsx b/packages/ui-video-conf/src/VideoConfMessage/VideoConfMessageUserStack.tsx index 724d9ff5a39..ed8dd09ec48 100644 --- a/packages/ui-video-conf/src/VideoConfMessage/VideoConfMessageUserStack.tsx +++ b/packages/ui-video-conf/src/VideoConfMessage/VideoConfMessageUserStack.tsx @@ -1,4 +1,5 @@ import type { IVideoConferenceUser, Serialized } from '@rocket.chat/core-typings'; +import { getUserDisplayName } from '@rocket.chat/core-typings'; import { Avatar, Box, Icon } from '@rocket.chat/fuselage'; import { useSetting, useUserAvatarPath, useUserPreference } from '@rocket.chat/ui-contexts'; import { memo, type ReactElement } from 'react'; @@ -11,7 +12,7 @@ type VideoConfMessageUserStackProps = { const VideoConfMessageUserStack = ({ users }: VideoConfMessageUserStackProps): ReactElement => { const displayAvatars = useUserPreference('displayAvatars'); - const showRealName = useSetting('UI_Use_Real_Name'); + const showRealName = useSetting('UI_Use_Real_Name', false); const getUserAvatarPath = useUserAvatarPath(); return ( @@ -23,8 +24,8 @@ const VideoConfMessageUserStack = ({ users }: VideoConfMessageUserStackProps): R ))}