From da7835bcdc4ab289f0c8bb95aff32700d9ac2b39 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 19 Dec 2022 16:40:32 -0300 Subject: [PATCH] Move away all behavior related to legacy message --- .../app/ui-message/{index.js => index.ts} | 0 .../components/LegacyThreadMessageList.tsx | 58 +++ .../Threads/components/ThreadChat.tsx | 329 ++---------------- .../hooks/useLegacyThreadMessageJump.ts | 40 +++ .../useLegacyThreadMessageListScrolling.ts | 88 +++++ .../hooks/useLegacyThreadMessageRef.ts | 112 ++++++ .../Threads/hooks/useLegacyThreadMessages.ts | 47 +++ 7 files changed, 374 insertions(+), 300 deletions(-) rename apps/meteor/app/ui-message/{index.js => index.ts} (100%) create mode 100644 apps/meteor/client/views/room/contextualBar/Threads/components/LegacyThreadMessageList.tsx create mode 100644 apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageJump.ts create mode 100644 apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageListScrolling.ts create mode 100644 apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageRef.ts create mode 100644 apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessages.ts diff --git a/apps/meteor/app/ui-message/index.js b/apps/meteor/app/ui-message/index.ts similarity index 100% rename from apps/meteor/app/ui-message/index.js rename to apps/meteor/app/ui-message/index.ts diff --git a/apps/meteor/client/views/room/contextualBar/Threads/components/LegacyThreadMessageList.tsx b/apps/meteor/client/views/room/contextualBar/Threads/components/LegacyThreadMessageList.tsx new file mode 100644 index 0000000000000..c4e0b0295f3e6 --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/Threads/components/LegacyThreadMessageList.tsx @@ -0,0 +1,58 @@ +import type { IMessage } from '@rocket.chat/core-typings'; +import { useMergedRefs } from '@rocket.chat/fuselage-hooks'; +import { useUserPreference } from '@rocket.chat/ui-contexts'; +import type { ReactElement } from 'react'; +import React from 'react'; + +import { isTruthy } from '../../../../../../lib/isTruthy'; +import LoadingMessagesIndicator from '../../../components/body/LoadingMessagesIndicator'; +import { useLegacyThreadMessageJump } from '../hooks/useLegacyThreadMessageJump'; +import { useLegacyThreadMessageListScrolling } from '../hooks/useLegacyThreadMessageListScrolling'; +import { useLegacyThreadMessageRef } from '../hooks/useLegacyThreadMessageRef'; +import { useLegacyThreadMessages } from '../hooks/useLegacyThreadMessages'; + +type LegacyThreadMessageListProps = { + mainMessage: IMessage; + jumpTo?: string; + onJumpTo?: (mid: IMessage['_id']) => void; +}; + +const LegacyThreadMessageList = function LegacyThreadChatList({ + mainMessage, + jumpTo, + onJumpTo, +}: LegacyThreadMessageListProps): ReactElement { + const { messages, loading } = useLegacyThreadMessages(mainMessage._id); + const messageRef = useLegacyThreadMessageRef(); + const { listWrapperRef: listWrapperScrollRef, listRef: listScrollRef, onScroll: handleScroll } = useLegacyThreadMessageListScrolling(); + const { parentRef: listJumpRef } = useLegacyThreadMessageJump(jumpTo, { enabled: !loading, onJumpTo }); + + const listRef = useMergedRefs(listScrollRef, listJumpRef); + const hideUsernames = useUserPreference('hideUsernames'); + + return ( +
+
    + {loading ? ( +
  • + +
  • + ) : ( + <> +
  • + {messages.map((message, index) => ( +
  • + ))} + + )} +
+
+ ); +}; + +export default LegacyThreadMessageList; diff --git a/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx b/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx index aefe2f4b2f2a2..a7e698862734e 100644 --- a/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx +++ b/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx @@ -1,52 +1,26 @@ import type { IMessage, IThreadMainMessage } from '@rocket.chat/core-typings'; -import { isThreadMainMessage, isThreadMessage, isEditedMessage } from '@rocket.chat/core-typings'; +import { isEditedMessage } from '@rocket.chat/core-typings'; import { CheckBox } from '@rocket.chat/fuselage'; import { useUniqueId } from '@rocket.chat/fuselage-hooks'; import { useCurrentRoute, useMethod, useQueryStringParameter, useRoute, useTranslation, useUserPreference } from '@rocket.chat/ui-contexts'; -import { ReactiveDict } from 'meteor/reactive-dict'; -import type { ReactElement, RefCallback, UIEvent } from 'react'; -import React, { useState, useEffect, useCallback, useContext, useRef, useMemo } from 'react'; +import type { ReactElement } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; -import { Messages } from '../../../../../../app/models/client'; -import { upsertMessageBulk } from '../../../../../../app/ui-utils/client/lib/RoomHistoryManager'; -import type { CommonRoomTemplateInstance } from '../../../../../../app/ui/client/views/app/lib/CommonRoomTemplateInstance'; -import { getCommonRoomEvents } from '../../../../../../app/ui/client/views/app/lib/getCommonRoomEvents'; import { callbacks } from '../../../../../../lib/callbacks'; -import { isTruthy } from '../../../../../../lib/isTruthy'; import VerticalBar from '../../../../../components/VerticalBar'; -import { useReactiveValue } from '../../../../../hooks/useReactiveValue'; -import MessageHighlightContext from '../../../MessageList/contexts/MessageHighlightContext'; import DropTargetOverlay from '../../../components/body/DropTargetOverlay'; -import LoadingMessagesIndicator from '../../../components/body/LoadingMessagesIndicator'; import ComposerContainer from '../../../components/body/composer/ComposerContainer'; import { useFileUploadDropTarget } from '../../../components/body/useFileUploadDropTarget'; -import { useRoomMessageContext } from '../../../components/body/useRoomMessageContext'; import { useChat } from '../../../contexts/ChatContext'; -import { MessageContext } from '../../../contexts/MessageContext'; import { useRoom, useRoomSubscription } from '../../../contexts/RoomContext'; -import { useTabBarClose, useToolboxContext } from '../../../contexts/ToolboxContext'; +import { useTabBarClose } from '../../../contexts/ToolboxContext'; +import LegacyThreadMessageList from './LegacyThreadMessageList'; type ThreadChatProps = { mainMessage: IThreadMainMessage; }; const ThreadChat = ({ mainMessage }: ThreadChatProps): ReactElement => { - const t = useTranslation(); - const atBottomRef = useRef(true); - const wrapperRef = useRef(null); - - const messageContext = useContext(MessageContext); - - const chat = useChat(); - - if (!chat) { - throw new Error('No ChatContext provided'); - } - - const messageHighlightContext = useContext(MessageHighlightContext); - - const subscription = useRoomSubscription(); - const [fileUploadTriggerProps, fileUploadOverlayProps] = useFileUploadDropTarget(); const sendToChannelPreference = useUserPreference<'always' | 'never' | 'default'>('alsoSendThreadToChannel'); @@ -61,9 +35,6 @@ const ThreadChat = ({ mainMessage }: ThreadChatProps): ReactElement => { return !mainMessage.tcount; } }); - const [loading, setLoading] = useState(false); - - const hideUsernames = useUserPreference('hideUsernames'); const handleSend = useCallback((): void => { if (sendToChannelPreference === 'default') { @@ -71,150 +42,30 @@ const ThreadChat = ({ mainMessage }: ThreadChatProps): ReactElement => { } }, [sendToChannelPreference]); - const sendToBottom = useCallback(() => { - const wrapper = wrapperRef.current; - - wrapper?.scrollTo(30, wrapper.scrollHeight); - }, []); - - const sendToBottomIfNecessary = useCallback(() => { - if (atBottomRef.current === true) { - sendToBottom(); - } - }, [sendToBottom]); - - const room = useRoom(); - const roomMessageContext = useRoomMessageContext(room); - const threadMessageContext = useMemo( - () => ({ - ...roomMessageContext, - settings: { - ...roomMessageContext.settings, - showReplyButton: false, - showreply: false, - }, - }), - [roomMessageContext], - ); - - const messages = useReactiveValue( - useCallback(() => { - return Messages.find( - { - $or: [{ tmid: mainMessage._id }, { _id: mainMessage._id }], - _hidden: { $ne: true }, - tmid: mainMessage._id, - _id: { $ne: mainMessage._id }, - }, - { - fields: { - collapsed: 0, - threadMsg: 0, - repliesCount: 0, - }, - sort: { ts: 1 }, - }, - ) - .fetch() - .filter(isThreadMessage); - }, [mainMessage._id]), - ); - - const sendToChannelID = useUniqueId(); - const closeTabBar = useTabBarClose(); const handleComposerEscape = useCallback((): void => { closeTabBar(); }, [closeTabBar]); + const chat = useChat(); + const handleNavigateToPreviousMessage = useCallback((): void => { - chat.messageEditing.toPreviousMessage(); - }, [chat.messageEditing]); + chat?.messageEditing.toPreviousMessage(); + }, [chat?.messageEditing]); const handleNavigateToNextMessage = useCallback((): void => { - chat.messageEditing.toNextMessage(); - }, [chat.messageEditing]); + chat?.messageEditing.toNextMessage(); + }, [chat?.messageEditing]); const handleUploadFiles = useCallback( (files: readonly File[]): void => { - chat.flows.uploadFiles(files); + chat?.flows.uploadFiles(files); }, - [chat], + [chat?.flows], ); - const handleScroll = useCallback(({ currentTarget: e }: UIEvent) => { - atBottomRef.current = e.scrollTop >= e.scrollHeight - e.clientHeight; - }, []); - - const useLegacyMessageTemplate = useUserPreference('useLegacyMessageTemplate') ?? false; - const toolbox = useToolboxContext(); - - useEffect(() => { - const messageList = wrapperRef.current?.querySelector('ul'); - - if (!messageList) { - return; - } - - const messageEvents: Record void> = { - ...getCommonRoomEvents(useLegacyMessageTemplate), - 'click .toggle-hidden'(event: JQuery.ClickEvent) { - const mid = event.target.dataset.message; - if (mid) document.getElementById(mid)?.classList.toggle('message--ignored'); - }, - 'load .gallery-item'() { - sendToBottomIfNecessary(); - }, - 'rendered .js-block-wrapper'() { - sendToBottomIfNecessary(); - }, - }; - - const eventHandlers = Object.entries(messageEvents).map(([key, handler]) => { - const [, event, selector] = key.match(/^(.+?)\s(.+)$/) ?? [key, key]; - return { - event, - selector, - listener: (e: JQuery.TriggeredEvent) => - handler.call(null, e, { data: { rid: room._id, tabBar: toolbox, chatContext: chat } }), - }; - }); - - for (const { event, selector, listener } of eventHandlers) { - $(messageList).on(event, selector, listener); - } - - return () => { - for (const { event, selector, listener } of eventHandlers) { - $(messageList).off(event, selector, listener); - } - }; - }, [chat, room._id, sendToBottomIfNecessary, toolbox, useLegacyMessageTemplate]); - - useEffect(() => { - const messageList = wrapperRef.current?.querySelector('ul'); - - if (!messageList) { - return; - } - - const observer = new ResizeObserver(() => { - sendToBottomIfNecessary(); - }); - - observer.observe(messageList); - - return () => { - observer?.disconnect(); - }; - }, [sendToBottomIfNecessary]); - - const handleComposerResize = useCallback((): void => { - sendToBottomIfNecessary(); - }, [sendToBottomIfNecessary]); - + const room = useRoom(); const readThreads = useMethod('readThreads'); - useEffect(() => { callbacks.add( 'streamNewMessage', @@ -232,166 +83,44 @@ const ThreadChat = ({ mainMessage }: ThreadChatProps): ReactElement => { return () => { callbacks.remove('streamNewMessage', `thread-${room._id}`); }; - }, [mainMessage._id, readThreads, room._id, sendToBottom]); + }, [mainMessage._id, readThreads, room._id]); const jump = useQueryStringParameter('jump'); + const [currentRouteName, currentRouteParams, currentRouteQueryStringParams] = useCurrentRoute(); if (!currentRouteName) { throw new Error('No route name'); } const currentRoute = useRoute(currentRouteName); - useEffect(() => { - if (loading || !jump) { - return; - } - + const handleJumpTo = useCallback(() => { const newQueryStringParams = { ...currentRouteQueryStringParams }; delete newQueryStringParams.jump; currentRoute.replace(currentRouteParams, newQueryStringParams); + }, [currentRoute, currentRouteParams, currentRouteQueryStringParams]); - const messageElement = document.querySelector(`#thread-${jump}`); - if (!messageElement) { - return; - } - - messageElement.classList.add('highlight'); - const removeClass = () => { - messageElement.classList.remove('highlight'); - messageElement.removeEventListener('animationend', removeClass); - }; - messageElement.addEventListener('animationend', removeClass); - setTimeout(() => { - messageElement.scrollIntoView(); - }, 300); - }, [currentRoute, currentRouteParams, currentRouteQueryStringParams, jump, loading]); - - const getThreadMessages = useMethod('getThreadMessages'); - - useEffect(() => { - setLoading(true); - getThreadMessages({ tmid: mainMessage._id }).then((messages) => { - upsertMessageBulk({ msgs: messages }, Messages); - setLoading(false); - }); - }, [getThreadMessages, mainMessage._id]); - - const [reactiveThreadMessageContext] = useState( - () => - new ReactiveDict(undefined, { - ...threadMessageContext, - 'messageHighlightContext.highlightMessageId': messageHighlightContext.highlightMessageId, - messageContext, - 'chatContext': chat, - }), - ); - useEffect(() => { - reactiveThreadMessageContext.set({ - ...threadMessageContext, - 'messageHighlightContext.highlightMessageId': messageHighlightContext.highlightMessageId, - messageContext, - 'chatContext': chat, - }); - }, [chat, messageContext, messageHighlightContext.highlightMessageId, reactiveThreadMessageContext, threadMessageContext]); - - const refs = useRef; reactiveMessage: ReactiveVar }>>(new Map()); - - const getRef = useCallback( - (message: IMessage, index: number) => { - const pair = refs.current.get(message._id); - - if (pair) { - pair.reactiveMessage.set(message); - return pair.callback; - } - - let view: Blaze.View; - - const reactiveMessage = new ReactiveVar(message); - - const callback = (node: HTMLLIElement | null) => { - if (node?.parentElement) { - view = Blaze.renderWithData( - Template.message, - () => { - const message = reactiveMessage.get(); - - return { - index, - msg: message, - room: reactiveThreadMessageContext.get('room'), - subscription: reactiveThreadMessageContext.get('subscription'), - settings: reactiveThreadMessageContext.get('settings'), - u: reactiveThreadMessageContext.get('u'), - chatContext: reactiveThreadMessageContext.get('chatContext'), - messageContext: reactiveThreadMessageContext.get('messageContext'), - hideRoles: true, - shouldCollapseReplies: true, - templatePrefix: 'thread-', - - context: 'threads', - ...(isThreadMainMessage(message) - ? { - customClass: [ - 'thread-main', - message._id === reactiveThreadMessageContext.get('messageHighlightContext.highlightMessageId') ? 'editing' : '', - ] - .filter(Boolean) - .join(' '), - ignored: false, - groupable: false, - } - : { - customClass: - message._id === reactiveThreadMessageContext.get('messageHighlightContext.highlightMessageId') ? 'editing' : '', - context: 'threads', - }), - }; - }, - node.parentElement, - node, - ); - } - - if (!node) { - Blaze.remove(view); - } - }; - - refs.current.set(message._id, { callback, reactiveMessage }); + const subscription = useRoomSubscription(); + const sendToChannelID = useUniqueId(); + const t = useTranslation(); - return callback; - }, - [reactiveThreadMessageContext], - ); + const useLegacyMessageTemplate = useUserPreference('useLegacyMessageTemplate') ?? false; return ( -
-
-
    - {loading ? ( -
  • - -
  • - ) : ( - <> -
  • - {messages.map((message, index) => ( -
  • - ))} - - )} -
-
+
+ {useLegacyMessageTemplate ? ( + + ) : ( + // TODO: create new thread message list + + )} void }, +) => { + const parentRef = useRef(null); + const onJumpToRef = useRef(onJumpTo); + onJumpToRef.current = onJumpTo; + + useEffect(() => { + const parent = parentRef.current; + + if (!enabled || !mid || !parent) { + return; + } + + const messageElement = parent.querySelector(`[data-id="${mid}"]`); + if (!messageElement) { + return; + } + + messageElement.classList.add('highlight'); + + const removeClass = () => { + messageElement.classList.remove('highlight'); + messageElement.removeEventListener('animationend', removeClass); + }; + messageElement.addEventListener('animationend', removeClass); + + setTimeout(() => { + messageElement.scrollIntoView(); + const onJumpTo = onJumpToRef.current; + onJumpTo?.(mid); + }, 300); + }, [enabled, mid, onJumpTo]); + + return { parentRef }; +}; diff --git a/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageListScrolling.ts b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageListScrolling.ts new file mode 100644 index 0000000000000..b19f12c046d00 --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageListScrolling.ts @@ -0,0 +1,88 @@ +import type { UIEvent } from 'react'; +import { useContext, useCallback, useEffect, useRef } from 'react'; + +import type { CommonRoomTemplateInstance } from '../../../../../../app/ui/client/views/app/lib/CommonRoomTemplateInstance'; +import { getCommonRoomEvents } from '../../../../../../app/ui/client/views/app/lib/getCommonRoomEvents'; +import { ChatContext } from '../../../contexts/ChatContext'; +import { useRoom } from '../../../contexts/RoomContext'; +import { useToolboxContext } from '../../../contexts/ToolboxContext'; + +export const useLegacyThreadMessageListScrolling = () => { + const listWrapperRef = useRef(null); + const listRef = useRef(null); + + const atBottomRef = useRef(true); + + const onScroll = useCallback(({ currentTarget: e }: UIEvent) => { + atBottomRef.current = e.scrollTop >= e.scrollHeight - e.clientHeight; + }, []); + + const sendToBottomIfNecessary = useCallback(() => { + if (atBottomRef.current === true) { + const listWrapper = listWrapperRef.current; + + listWrapper?.scrollTo(30, listWrapper.scrollHeight); + } + }, []); + + const toolbox = useToolboxContext(); + + const room = useRoom(); + const chatContext = useContext(ChatContext); + useEffect(() => { + const messageList = listRef.current; + + if (!messageList) { + return; + } + + const messageEvents: Record void> = { + ...getCommonRoomEvents(), + 'click .toggle-hidden'(event: JQuery.ClickEvent) { + const mid = event.target.dataset.message; + if (mid) document.getElementById(mid)?.classList.toggle('message--ignored'); + }, + 'load .gallery-item'() { + sendToBottomIfNecessary(); + }, + 'rendered .js-block-wrapper'() { + sendToBottomIfNecessary(); + }, + }; + + const eventHandlers = Object.entries(messageEvents).map(([key, handler]) => { + const [, event, selector] = key.match(/^(.+?)\s(.+)$/) ?? [key, key]; + return { + event, + selector, + listener: (e: JQuery.TriggeredEvent) => + handler.call(null, e, { data: { rid: room._id, tabBar: toolbox, chatContext } }), + }; + }); + + for (const { event, selector, listener } of eventHandlers) { + $(messageList).on(event, selector, listener); + } + + return () => { + for (const { event, selector, listener } of eventHandlers) { + $(messageList).off(event, selector, listener); + } + }; + }, [chatContext, room._id, sendToBottomIfNecessary, toolbox]); + + useEffect(() => { + const observer = new ResizeObserver(() => { + sendToBottomIfNecessary(); + }); + + if (listWrapperRef.current) observer.observe(listWrapperRef.current); + if (listRef.current) observer.observe(listRef.current); + + return () => { + observer.disconnect(); + }; + }, [sendToBottomIfNecessary]); + + return { listWrapperRef, listRef, onScroll }; +}; diff --git a/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageRef.ts b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageRef.ts new file mode 100644 index 0000000000000..0a177116b843d --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageRef.ts @@ -0,0 +1,112 @@ +import type { IMessage } from '@rocket.chat/core-typings'; +import { isThreadMainMessage } from '@rocket.chat/core-typings'; +import { ReactiveVar } from 'meteor/reactive-var'; +import type { RefCallback } from 'react'; +import { useEffect, useMemo, useState, useContext, useCallback, useRef } from 'react'; + +import MessageHighlightContext from '../../../MessageList/contexts/MessageHighlightContext'; +import { useRoomMessageContext } from '../../../components/body/useRoomMessageContext'; +import { ChatContext } from '../../../contexts/ChatContext'; +import { MessageContext } from '../../../contexts/MessageContext'; +import { useRoom } from '../../../contexts/RoomContext'; + +export const useLegacyThreadMessageRef = () => { + const messageContext = useContext(MessageContext); + const chatContext = useContext(ChatContext); + const messageHighlightContext = useContext(MessageHighlightContext); + const room = useRoom(); + const roomMessageContext = useRoomMessageContext(room); + const threadMessageContext = useMemo( + () => ({ + ...roomMessageContext, + settings: { + ...roomMessageContext.settings, + showReplyButton: false, + showreply: false, + }, + }), + [roomMessageContext], + ); + + const [reactiveThreadMessageContext] = useState( + () => + new ReactiveVar({ + ...threadMessageContext, + 'messageHighlightContext.highlightMessageId': messageHighlightContext.highlightMessageId, + messageContext, + chatContext, + }), + ); + useEffect(() => { + reactiveThreadMessageContext.set({ + ...threadMessageContext, + 'messageHighlightContext.highlightMessageId': messageHighlightContext.highlightMessageId, + messageContext, + chatContext, + }); + }, [chatContext, messageContext, messageHighlightContext.highlightMessageId, reactiveThreadMessageContext, threadMessageContext]); + + const cache = useRef; reactiveMessage: ReactiveVar }>>(new Map()); + + return useCallback( + (message: IMessage, index: number) => { + const pair = cache.current.get(message._id); + + if (pair) { + pair.reactiveMessage.set(message); + return pair.callback; + } + + let view: Blaze.View; + + const reactiveMessage = new ReactiveVar(message); + + const callback = (node: HTMLLIElement | null) => { + if (node?.parentElement) { + view = Blaze.renderWithData( + Template.message, + () => { + const message = reactiveMessage.get(); + const editing = message._id === reactiveThreadMessageContext.get()['messageHighlightContext.highlightMessageId']; + + return { + index, + msg: message, + room: reactiveThreadMessageContext.get().room, + subscription: reactiveThreadMessageContext.get().subscription, + settings: reactiveThreadMessageContext.get().settings, + u: reactiveThreadMessageContext.get().u, + chatContext: reactiveThreadMessageContext.get().chatContext, + messageContext: reactiveThreadMessageContext.get().messageContext, + hideRoles: true, + shouldCollapseReplies: true, + templatePrefix: 'thread-', + ...(isThreadMainMessage(message) + ? { + customClass: ['thread-main', editing ? 'editing' : ''].filter(Boolean).join(' '), + ignored: false, + groupable: false, + } + : { + customClass: editing ? 'editing' : '', + context: 'threads', + }), + }; + }, + node.parentElement, + node, + ); + } + + if (!node) { + Blaze.remove(view); + } + }; + + cache.current.set(message._id, { callback, reactiveMessage }); + + return callback; + }, + [reactiveThreadMessageContext], + ); +}; diff --git a/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessages.ts b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessages.ts new file mode 100644 index 0000000000000..f96c721dbed9e --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessages.ts @@ -0,0 +1,47 @@ +import type { IThreadMainMessage } from '@rocket.chat/core-typings'; +import { isThreadMessage } from '@rocket.chat/core-typings'; +import { useMethod } from '@rocket.chat/ui-contexts'; +import { useEffect, useState, useCallback } from 'react'; + +import { Messages } from '../../../../../../app/models/client'; +import { upsertMessageBulk } from '../../../../../../app/ui-utils/client/lib/RoomHistoryManager'; +import { useReactiveValue } from '../../../../../hooks/useReactiveValue'; + +export const useLegacyThreadMessages = (tmid: IThreadMainMessage['_id']) => { + const messages = useReactiveValue( + useCallback(() => { + return Messages.find( + { + $or: [{ tmid }, { _id: tmid }], + _hidden: { $ne: true }, + tmid, + _id: { $ne: tmid }, + }, + { + fields: { + collapsed: 0, + threadMsg: 0, + repliesCount: 0, + }, + sort: { ts: 1 }, + }, + ) + .fetch() + .filter(isThreadMessage); + }, [tmid]), + ); + + const [loading, setLoading] = useState(false); + + const getThreadMessages = useMethod('getThreadMessages'); + + useEffect(() => { + setLoading(true); + getThreadMessages({ tmid }).then((messages) => { + upsertMessageBulk({ msgs: messages }, Messages); + setLoading(false); + }); + }, [getThreadMessages, tmid]); + + return { messages, loading }; +};