11import { isThreadMessage , type IMessage , type IRoom , type IThreadMainMessage , type IThreadMessage } from '@rocket.chat/core-typings' ;
2- import { useMethod , useStream } from '@rocket.chat/ui-contexts' ;
3- import { useQuery , useQueryClient } from '@tanstack/react-query' ;
2+ import { useEndpoint , useMethod , useStream } from '@rocket.chat/ui-contexts' ;
3+ import { useInfiniteQuery , useQueryClient } from '@tanstack/react-query' ;
44import { useEffect , useRef } from 'react' ;
55
66import { onClientMessageReceived } from '../../../../../lib/onClientMessageReceived' ;
77import { roomsQueryKeys } from '../../../../../lib/queryKeys' ;
8+ import { getConfig } from '../../../../../lib/utils/getConfig' ;
9+ import { mapMessageFromApi } from '../../../../../lib/utils/mapMessageFromApi' ;
810import { modifyMessageOnFilesDelete } from '../../../../../lib/utils/modifyMessageOnFilesDelete' ;
911import {
1012 createDeleteCriteria ,
1113 markThreadMessagesAsRead ,
1214 mergeThreadMessages ,
15+ mutateThreadMessagesInfiniteData ,
16+ type ThreadMessagesInfiniteData ,
1317 upsertThreadMessageInCache ,
1418} from '../../../../../lib/utils/threadMessageUtils' ;
1519import { useRoom } from '../../../contexts/RoomContext' ;
@@ -18,6 +22,12 @@ const processMessages = async (messages: IMessage[]): Promise<IMessage[]> => {
1822 return Promise . all ( messages . map ( ( msg ) => onClientMessageReceived ( msg ) ) ) ;
1923} ;
2024
25+ const filterThreadMessages = ( messages : IMessage [ ] , tmid : IThreadMainMessage [ '_id' ] ) : IThreadMessage [ ] => {
26+ return messages
27+ . map ( ( m ) => mapMessageFromApi ( m ) )
28+ . filter ( ( msg ) : msg is IThreadMessage => isThreadMessage ( msg ) && msg . tmid === tmid && msg . _id !== tmid && msg . _hidden !== true ) ;
29+ } ;
30+
2131export const useThreadMessagesQuery = ( tmid : IThreadMainMessage [ '_id' ] , rid ?: IRoom [ '_id' ] ) => {
2232 const room = useRoom ( ) ;
2333 const roomId = rid ?? room . _id ;
@@ -31,6 +41,8 @@ export const useThreadMessagesQuery = (tmid: IThreadMainMessage['_id'], rid?: IR
3141
3242 const unprocessedReadMessagesEvent = useRef < { tmid : string ; until : Date } | null > ( null ) ;
3343
44+ const count = parseInt ( `${ getConfig ( 'threadMessagesSize' , 50 ) } ` , 10 ) ;
45+
3446 useEffect ( ( ) => {
3547 const currentQueryKey = roomsQueryKeys . threadMessages ( roomId , tmid ) ;
3648
@@ -44,32 +56,30 @@ export const useThreadMessagesQuery = (tmid: IThreadMainMessage['_id'], rid?: IR
4456 } ) ;
4557
4658 const unsubscribeFromDeleteMessage = subscribeToNotifyRoom ( `${ roomId } /deleteMessage` , ( event ) => {
47- queryClient . setQueryData < IThreadMessage [ ] > ( currentQueryKey , ( old ) => {
48- if ( ! old ) {
49- return old ;
59+ mutateThreadMessagesInfiniteData ( queryClient , currentQueryKey , ( messages ) => {
60+ const index = messages . findIndex ( ( m ) => m . _id === event . _id ) ;
61+ if ( index !== - 1 ) {
62+ messages . splice ( index , 1 ) ;
5063 }
51- return old . filter ( ( m ) => m . _id !== event . _id ) ;
5264 } ) ;
5365 } ) ;
5466
5567 const unsubscribeFromDeleteMessageBulk = subscribeToNotifyRoom ( `${ roomId } /deleteMessageBulk` , ( bulkParams ) => {
5668 const matchDeleteCriteria = createDeleteCriteria ( bulkParams ) ;
5769
58- queryClient . setQueryData < IThreadMessage [ ] > ( currentQueryKey , ( old ) => {
59- if ( ! old ) {
60- return old ;
61- }
62-
70+ mutateThreadMessagesInfiniteData ( queryClient , currentQueryKey , ( messages ) => {
6371 if ( bulkParams . filesOnly ) {
64- return old . map ( ( msg ) => {
72+ for ( let index = 0 ; index < messages . length ; index ++ ) {
73+ const msg = messages [ index ] ;
6574 if ( matchDeleteCriteria ( msg ) ) {
66- return modifyMessageOnFilesDelete ( msg , bulkParams . replaceFileAttachmentsWith ) ;
75+ messages [ index ] = modifyMessageOnFilesDelete ( msg , bulkParams . replaceFileAttachmentsWith ) ;
6776 }
68- return msg ;
69- } ) ;
77+ }
78+ return ;
7079 }
7180
72- return old . filter ( ( msg ) => ! matchDeleteCriteria ( msg ) ) ;
81+ const filtered = messages . filter ( ( msg ) => ! matchDeleteCriteria ( msg ) ) ;
82+ messages . splice ( 0 , messages . length , ...filtered ) ;
7383 } ) ;
7484 } ) ;
7585
@@ -84,11 +94,9 @@ export const useThreadMessagesQuery = (tmid: IThreadMainMessage['_id'], rid?: IR
8494 return ;
8595 }
8696
87- queryClient . setQueryData < IThreadMessage [ ] > ( currentQueryKey , ( old ) => {
88- if ( ! old ) {
89- return old ;
90- }
91- return markThreadMessagesAsRead ( old , until ) ;
97+ mutateThreadMessagesInfiniteData ( queryClient , currentQueryKey , ( messages ) => {
98+ const updated = markThreadMessagesAsRead ( messages , until ) ;
99+ messages . splice ( 0 , messages . length , ...updated ) ;
92100 } ) ;
93101 } ) ;
94102
@@ -100,23 +108,49 @@ export const useThreadMessagesQuery = (tmid: IThreadMainMessage['_id'], rid?: IR
100108 } ;
101109 } , [ tmid , roomId , queryClient , subscribeToRoomMessages , subscribeToNotifyRoom ] ) ;
102110
103- return useQuery ( {
111+ return useInfiniteQuery ( {
104112 queryKey,
105- queryFn : async ( ) => {
106- const cachedMessages = queryClient . getQueryData < IThreadMessage [ ] > ( queryKey ) || [ ] ;
113+ queryFn : async ( { pageParam : offset } ) => {
114+ if ( offset === 0 ) {
115+ void Promise . resolve ( readThreads ( tmid ) ) . catch ( ( ) => undefined ) ;
116+ }
107117
108- const messages = await getThreadMessages ( { tmid } ) ;
109- const filtered = messages . filter (
110- ( msg ) : msg is IThreadMessage => isThreadMessage ( msg ) && msg . tmid === tmid && msg . _id !== tmid && msg . _hidden !== true ,
111- ) ;
118+ const cachedData = offset === 0 ? queryClient . getQueryData < ThreadMessagesInfiniteData > ( queryKey ) : undefined ;
119+ const cachedMessages = cachedData ?. pages [ 0 ] ?. items ?? [ ] ;
112120
113- const sorted = mergeThreadMessages ( cachedMessages , filtered ) ;
114- if ( unprocessedReadMessagesEvent . current ) {
121+ const { messages, total } = await getThreadMessages ( {
122+ tmid,
123+ offset,
124+ count,
125+ sort : JSON . stringify ( { ts : 1 } ) ,
126+ } ) ;
127+
128+ let filtered = filterThreadMessages ( messages , tmid ) ;
129+ if ( offset === 0 ) {
130+ filtered = mergeThreadMessages ( cachedMessages , filtered ) ;
131+ }
132+
133+ if ( offset === 0 && unprocessedReadMessagesEvent . current ) {
115134 const { until } = unprocessedReadMessagesEvent . current ;
116135 unprocessedReadMessagesEvent . current = null ;
117- return processMessages ( markThreadMessagesAsRead ( sorted , until ) ) as Promise < Array < IThreadMessage > > ;
136+ filtered = markThreadMessagesAsRead ( filtered , until ) ;
118137 }
119- return processMessages ( sorted ) as Promise < Array < IThreadMessage > > ;
138+
139+ const processed = ( await processMessages ( filtered ) ) as IThreadMessage [ ] ;
140+
141+ return {
142+ items : processed ,
143+ itemCount : total ,
144+ } ;
145+ } ,
146+ initialPageParam : 0 ,
147+ getNextPageParam : ( lastPage , allPages ) => {
148+ const loadedItemsCount = allPages . reduce ( ( acc , page ) => acc + page . items . length , 0 ) ;
149+ return loadedItemsCount < lastPage . itemCount ? loadedItemsCount : undefined ;
120150 } ,
151+ select : ( { pages } ) => ( {
152+ messages : pages . flatMap ( ( page ) => page . items ) ,
153+ itemCount : pages . at ( - 1 ) ?. itemCount ?? 0 ,
154+ } ) ,
121155 } ) ;
122156} ;
0 commit comments