11import { ChannelState } from './channel_state' ;
2+ import { MessageComposer } from './messageComposer' ;
3+ import { MessageReceiptsTracker } from './messageDelivery' ;
24import {
35 generateChannelTempCid ,
46 logChatPromiseExecution ,
@@ -74,7 +76,6 @@ import type {
7476} from './types' ;
7577import type { Role } from './permissions' ;
7678import type { CustomChannelData } from './custom_types' ;
77- import { MessageComposer } from './messageComposer' ;
7879
7980/**
8081 * Channel - The Channel class manages it's own state.
@@ -110,6 +111,7 @@ export class Channel {
110111 disconnected : boolean ;
111112 push_preferences ?: PushPreference ;
112113 public readonly messageComposer : MessageComposer ;
114+ public readonly messageReceiptsTracker : MessageReceiptsTracker ;
113115
114116 /**
115117 * constructor - Create a channel
@@ -158,6 +160,13 @@ export class Channel {
158160 client : this . _client ,
159161 compositionContext : this ,
160162 } ) ;
163+
164+ this . messageReceiptsTracker = new MessageReceiptsTracker ( {
165+ locateMessage : ( timestampMs ) => {
166+ const msg = this . state . findMessageByTimestamp ( timestampMs ) ;
167+ return msg && { timestampMs, msgId : msg . id } ;
168+ } ,
169+ } ) ;
161170 }
162171
163172 /**
@@ -1131,16 +1140,26 @@ export class Channel {
11311140 }
11321141
11331142 /**
1134- * markRead - Send the mark read event for this user, only works if the `read_events` setting is enabled
1143+ * markRead - Send the mark read event for this user, only works if the `read_events` setting is enabled. Syncs the message delivery report candidates local state.
11351144 *
11361145 * @param {MarkReadOptions } data
11371146 * @return {Promise<EventAPIResponse | null> } Description
11381147 */
11391148 async markRead ( data : MarkReadOptions = { } ) {
1149+ return await this . getClient ( ) . messageDeliveryReporter . markRead ( this , data ) ;
1150+ }
1151+
1152+ /**
1153+ * markReadRequest - Send the mark read event for this user, only works if the `read_events` setting is enabled
1154+ *
1155+ * @param {MarkReadOptions } data
1156+ * @return {Promise<EventAPIResponse | null> } Description
1157+ */
1158+ async markAsReadRequest ( data : MarkReadOptions = { } ) {
11401159 this . _checkInitialized ( ) ;
11411160
11421161 if ( ! this . getConfig ( ) ?. read_events && ! this . getClient ( ) . _isUsingServerAuth ( ) ) {
1143- return Promise . resolve ( null ) ;
1162+ return null ;
11441163 }
11451164
11461165 return await this . getClient ( ) . post < EventAPIResponse > ( this . _channelURL ( ) + '/read' , {
@@ -1554,6 +1573,7 @@ export class Channel {
15541573 { method : 'upsertChannels' } ,
15551574 ) ;
15561575
1576+ this . getClient ( ) . syncDeliveredCandidates ( [ this ] ) ;
15571577 return state ;
15581578 }
15591579
@@ -1874,18 +1894,50 @@ export class Channel {
18741894 break ;
18751895 case 'message.read' :
18761896 if ( event . user ?. id && event . created_at ) {
1897+ const previousReadState = channelState . read [ event . user . id ] ;
18771898 channelState . read [ event . user . id ] = {
1899+ // in case we already have delivery information
1900+ ...previousReadState ,
18781901 last_read : new Date ( event . created_at ) ,
18791902 last_read_message_id : event . last_read_message_id ,
18801903 user : event . user ,
18811904 unread_messages : 0 ,
18821905 } ;
1906+ this . messageReceiptsTracker . onMessageRead ( {
1907+ user : event . user ,
1908+ readAt : event . created_at ,
1909+ lastReadMessageId : event . last_read_message_id ,
1910+ } ) ;
1911+ const client = this . getClient ( ) ;
18831912
1884- if ( event . user ?. id === this . getClient ( ) . user ?. id ) {
1913+ const isOwnEvent = event . user ?. id === client . user ?. id ;
1914+
1915+ if ( isOwnEvent ) {
18851916 channelState . unreadCount = 0 ;
1917+ client . syncDeliveredCandidates ( [ this ] ) ;
18861918 }
18871919 }
18881920 break ;
1921+ case 'message.delivered' :
1922+ // todo: update also on thread
1923+ if ( event . user ?. id && event . created_at ) {
1924+ const previousReadState = channelState . read [ event . user . id ] ;
1925+ channelState . read [ event . user . id ] = {
1926+ ...previousReadState ,
1927+ last_delivered_at : event . last_delivered_at
1928+ ? new Date ( event . last_delivered_at )
1929+ : undefined ,
1930+ last_delivered_message_id : event . last_delivered_message_id ,
1931+ user : event . user ,
1932+ } ;
1933+
1934+ this . messageReceiptsTracker . onMessageDelivered ( {
1935+ user : event . user ,
1936+ deliveredAt : event . created_at ,
1937+ lastDeliveredMessageId : event . last_delivered_message_id ,
1938+ } ) ;
1939+ }
1940+ break ;
18891941 case 'user.watching.start' :
18901942 case 'user.updated' :
18911943 if ( event . user ?. id ) {
@@ -1921,8 +1973,9 @@ export class Channel {
19211973 break ;
19221974 case 'message.new' :
19231975 if ( event . message ) {
1976+ const client = this . getClient ( ) ;
19241977 /* if message belongs to current user, always assume timestamp is changed to filter it out and add again to avoid duplication */
1925- const ownMessage = event . user ?. id === this . getClient ( ) . user ?. id ;
1978+ const ownMessage = event . user ?. id === client . user ?. id ;
19261979 const isThreadMessage =
19271980 event . message . parent_id && ! event . message . show_in_channel ;
19281981
@@ -1947,6 +2000,8 @@ export class Channel {
19472000 last_read : new Date ( event . created_at as string ) ,
19482001 user : event . user ,
19492002 unread_messages : 0 ,
2003+ last_delivered_at : new Date ( event . created_at as string ) ,
2004+ last_delivered_message_id : event . message . id ,
19502005 } ;
19512006 } else {
19522007 channelState . read [ userId ] . unread_messages += 1 ;
@@ -1957,6 +2012,8 @@ export class Channel {
19572012 if ( this . _countMessageAsUnread ( event . message ) ) {
19582013 channelState . unreadCount = channelState . unreadCount + 1 ;
19592014 }
2015+
2016+ client . syncDeliveredCandidates ( [ this ] ) ;
19602017 }
19612018 break ;
19622019 case 'message.updated' :
@@ -2057,11 +2114,13 @@ export class Channel {
20572114 break ;
20582115 case 'notification.mark_unread' : {
20592116 const ownMessage = event . user ?. id === this . getClient ( ) . user ?. id ;
2060- if ( ! ( ownMessage && event . user ) ) break ;
2117+ if ( ! ownMessage || ! event . user ) break ;
20612118
20622119 const unreadCount = event . unread_messages ?? 0 ;
2063-
2120+ const currentState = channelState . read [ event . user . id ] ;
20642121 channelState . read [ event . user . id ] = {
2122+ // keep the message delivery info
2123+ ...currentState ,
20652124 first_unread_message_id : event . first_unread_message_id ,
20662125 last_read : new Date ( event . last_read_at as string ) ,
20672126 last_read_message_id : event . last_read_message_id ,
@@ -2070,6 +2129,11 @@ export class Channel {
20702129 } ;
20712130
20722131 channelState . unreadCount = unreadCount ;
2132+ this . messageReceiptsTracker . onNotificationMarkUnread ( {
2133+ user : event . user ,
2134+ lastReadAt : event . last_read_at ,
2135+ lastReadMessageId : event . last_read_message_id ,
2136+ } ) ;
20732137 break ;
20742138 }
20752139 case 'channel.updated' :
@@ -2286,6 +2350,8 @@ export class Channel {
22862350 this . state . unreadCount = this . state . read [ read . user . id ] . unread_messages ;
22872351 }
22882352 }
2353+
2354+ this . messageReceiptsTracker . ingestInitial ( state . read ) ;
22892355 }
22902356
22912357 return {
0 commit comments