@@ -11,13 +11,16 @@ import {
1111
1212import { GiphyPreviewMessage as DefaultGiphyPreviewMessage } from './GiphyPreviewMessage' ;
1313import { useGiphyPreview } from './hooks/useGiphyPreview' ;
14- import { useNewMessageNotification } from './hooks/useNewMessageNotification' ;
15- import { usePrependedMessagesCount } from './hooks/usePrependMessagesCount' ;
16- import { useShouldForceScrollToBottom } from './hooks/useShouldForceScrollToBottom' ;
14+ import {
15+ useLastReadData ,
16+ useNewMessageNotification ,
17+ usePrependedMessagesCount ,
18+ useShouldForceScrollToBottom ,
19+ } from './hooks' ;
1720import { MessageNotification as DefaultMessageNotification } from './MessageNotification' ;
1821import { MessageListNotifications as DefaultMessageListNotifications } from './MessageListNotifications' ;
1922import { MessageListMainPanel } from './MessageListMainPanel' ;
20- import { getGroupStyles , GroupStyle , processMessages } from './utils' ;
23+ import { getGroupStyles , getLastReceived , GroupStyle , processMessages } from './utils' ;
2124
2225import { CUSTOM_MESSAGE_TYPE } from '../../constants/messageTypes' ;
2326import { DateSeparator as DefaultDateSeparator } from '../DateSeparator/DateSeparator' ;
@@ -39,17 +42,23 @@ import { useChatContext } from '../../context/ChatContext';
3942import { useComponentContext } from '../../context/ComponentContext' ;
4043import { isDate } from '../../context/TranslationContext' ;
4144
42- import type { Channel } from 'stream-chat' ;
45+ import type { Channel , ChannelState as StreamChannelState , UserResponse } from 'stream-chat' ;
4346
4447import type { ChatProps } from '../Chat' ;
4548import type { DefaultStreamChatGenerics , UnknownType } from '../../types/types' ;
4649
4750const PREPEND_OFFSET = 10 ** 7 ;
4851
49- type VirtuosoContext = {
52+ type VirtuosoContext <
53+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
54+ > = {
5055 customClasses : ChatProps [ 'customClasses' ] ;
56+ /** Latest received message id in the current channel */
57+ lastReceivedMessageId : string | null | undefined ;
5158 messageGroupStyles : Record < string , GroupStyle > ;
5259 numItemsPrepended : number ;
60+ /** Mapping of message ID of own messages to the array of users, who read the given message */
61+ ownMessagesReadByOthers : Record < string , UserResponse < StreamChatGenerics > [ ] > ;
5362 processedMessages : StreamMessage [ ] ;
5463} ;
5564
@@ -63,6 +72,7 @@ type VirtualizedMessageListWithContextProps<
6372 loadingMore : boolean ;
6473 loadingMoreNewer : boolean ;
6574 notifications : ChannelNotifications ;
75+ read ?: StreamChannelState < StreamChatGenerics > [ 'read' ] ;
6676} ;
6777
6878function captureResizeObserverExceededError ( e : ErrorEvent ) {
@@ -133,6 +143,8 @@ const VirtualizedMessageListWithContext = <
133143 notifications,
134144 // TODO: refactor to scrollSeekPlaceHolderConfiguration and components.ScrollSeekPlaceholder, like the Virtuoso Component
135145 overscan = 0 ,
146+ read,
147+ returnAllReadData = false ,
136148 scrollSeekPlaceHolder,
137149 scrollToLatestMessageOnFocus = false ,
138150 separateGiphyPreview = false ,
@@ -201,6 +213,18 @@ const VirtualizedMessageListWithContext = <
201213 client . userID ,
202214 ] ) ;
203215
216+ // get the mapping of own messages to array of users who read them
217+ const ownMessagesReadByOthers = useLastReadData ( {
218+ messages : processedMessages ,
219+ read,
220+ returnAllReadData,
221+ userID : client . userID ,
222+ } ) ;
223+
224+ const lastReceivedMessageId = useMemo ( ( ) => getLastReceived ( processedMessages ) , [
225+ processedMessages ,
226+ ] ) ;
227+
204228 const groupStylesFn = groupStyles || getGroupStyles ;
205229 const messageGroupStyles = useMemo (
206230 ( ) =>
@@ -315,7 +339,12 @@ const VirtualizedMessageListWithContext = <
315339 } ;
316340
317341 const messageRenderer = useCallback (
318- ( messageList : StreamMessage < StreamChatGenerics > [ ] , virtuosoIndex : number ) => {
342+ (
343+ messageList : StreamMessage < StreamChatGenerics > [ ] ,
344+ virtuosoIndex : number ,
345+ virtuosoContext : VirtuosoContext ,
346+ ) => {
347+ const { lastReceivedMessageId, ownMessagesReadByOthers } = virtuosoContext ;
319348 const streamMessageIndex = virtuosoIndex + numItemsPrepended - PREPEND_OFFSET ;
320349 // use custom renderer supplied by client if present and skip the rest
321350 if ( customMessageRenderer ) {
@@ -353,9 +382,11 @@ const VirtualizedMessageListWithContext = <
353382 endOfGroup = { endOfGroup }
354383 firstOfGroup = { firstOfGroup }
355384 groupedByUser = { groupedByUser }
385+ lastReceivedId = { lastReceivedMessageId }
356386 message = { message }
357387 Message = { MessageUIComponent }
358388 messageActions = { props . messageActions }
389+ readBy = { ownMessagesReadByOthers [ message . id ] || [ ] }
359390 />
360391 ) ;
361392 } ,
@@ -463,8 +494,10 @@ const VirtualizedMessageListWithContext = <
463494 context = {
464495 {
465496 customClasses,
497+ lastReceivedMessageId,
466498 messageGroupStyles,
467499 numItemsPrepended,
500+ ownMessagesReadByOthers,
468501 processedMessages,
469502 } as VirtuosoContext
470503 }
@@ -476,7 +509,9 @@ const VirtualizedMessageListWithContext = <
476509 processedMessages ,
477510 highlightedMessageId ,
478511 ) }
479- itemContent = { ( i ) => messageRenderer ( processedMessages , i ) }
512+ itemContent = { ( i , _ , context ) =>
513+ messageRenderer ( processedMessages , i , context as VirtuosoContext )
514+ }
480515 itemSize = { fractionalItemSize }
481516 key = { messageSetKey }
482517 overscan = { overscan }
@@ -555,6 +590,8 @@ export type VirtualizedMessageListProps<
555590 messages ?: StreamMessage < StreamChatGenerics > [ ] ;
556591 /** The amount of extra content the list should render in addition to what's necessary to fill in the viewport */
557592 overscan ?: number ;
593+ /** Keep track of read receipts for each message sent by the user. When disabled, only the last own message delivery / read status is rendered. */
594+ returnAllReadData ?: boolean ;
558595 /**
559596 * Performance improvement by showing placeholders if user scrolls fast through list.
560597 * it can be used like this:
@@ -605,6 +642,7 @@ export function VirtualizedMessageList<
605642 loadingMoreNewer,
606643 messages : contextMessages ,
607644 notifications,
645+ read,
608646 suppressAutoscroll,
609647 } = useChannelStateContext < StreamChatGenerics > ( 'VirtualizedMessageList' ) ;
610648
@@ -623,6 +661,7 @@ export function VirtualizedMessageList<
623661 loadMoreNewer = { loadMoreNewer }
624662 messages = { messages }
625663 notifications = { notifications }
664+ read = { read }
626665 suppressAutoscroll = { suppressAutoscroll }
627666 { ...props }
628667 />
0 commit comments