@@ -66,14 +66,15 @@ import { TypingProvider } from '../../context/TypingContext';
6666
6767import {
6868 DEFAULT_INITIAL_CHANNEL_PAGE_SIZE ,
69+ DEFAULT_JUMP_TO_PAGE_SIZE ,
6970 DEFAULT_NEXT_CHANNEL_PAGE_SIZE ,
7071 DEFAULT_THREAD_PAGE_SIZE ,
7172} from '../../constants/limits' ;
7273
7374import type { UnreadMessagesNotificationProps } from '../MessageList' ;
7475import { hasMoreMessagesProbably , UnreadMessagesSeparator } from '../MessageList' ;
7576import { useChannelContainerClasses } from './hooks/useChannelContainerClasses' ;
76- import { makeAddNotifications } from './utils' ;
77+ import { findInMsgSetByDate , findInMsgSetById , makeAddNotifications } from './utils' ;
7778import { getChannel } from '../../utils' ;
7879
7980import type { MessageProps } from '../Message/types' ;
@@ -554,6 +555,10 @@ const ChannelInner = <
554555 } ;
555556 } ) ;
556557
558+ if ( event . type === 'channel.truncated' && event . cid === channel . cid ) {
559+ _setChannelUnreadUiState ( undefined ) ;
560+ }
561+
557562 throttledCopyStateFromChannel ( ) ;
558563 } ;
559564
@@ -709,7 +714,7 @@ const ChannelInner = <
709714 return queryResponse . messages . length ;
710715 } ;
711716
712- const loadMoreNewer = async ( limit = 100 ) => {
717+ const loadMoreNewer = async ( limit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE ) => {
713718 if ( ! online . current || ! window . navigator . onLine || ! state . hasMoreNewer ) return 0 ;
714719
715720 const newestMessage = state ?. messages ?. [ state ?. messages ?. length - 1 ] ;
@@ -744,7 +749,7 @@ const ChannelInner = <
744749
745750 const clearHighlightedMessageTimeoutId = useRef < ReturnType < typeof setTimeout > | null > ( null ) ;
746751
747- const jumpToMessage = async ( messageId : string , messageLimit = 100 ) => {
752+ const jumpToMessage = async ( messageId : string , messageLimit = DEFAULT_JUMP_TO_PAGE_SIZE ) => {
748753 dispatch ( { loadingMore : true , type : 'setLoadingMore' } ) ;
749754 await channel . state . loadMessageIntoState ( messageId , undefined , messageLimit ) ;
750755
@@ -783,56 +788,118 @@ const ChannelInner = <
783788 } ;
784789
785790 const jumpToFirstUnreadMessage = useCallback (
786- async ( queryMessageLimit = 100 ) => {
787- if ( ! ( client . user && channelUnreadUiState ?. unread_messages ) ) return ;
788- if ( ! channelUnreadUiState ?. last_read_message_id ) {
789- addNotification ( t ( 'Failed to jump to the first unread message' ) , 'error' ) ;
790- return ;
791- }
792-
793- let indexOfLastReadMessage ;
791+ async ( queryMessageLimit = DEFAULT_JUMP_TO_PAGE_SIZE ) => {
792+ if ( ! channelUnreadUiState ?. unread_messages ) return ;
793+ let lastReadMessageId = channelUnreadUiState ?. last_read_message_id ;
794+ let firstUnreadMessageId = channelUnreadUiState ?. first_unread_message_id ;
795+ let isInCurrentMessageSet = false ;
796+ let hasMoreMessages = true ;
797+
798+ if ( firstUnreadMessageId ) {
799+ const result = findInMsgSetById ( firstUnreadMessageId , channel . state . messages ) ;
800+ isInCurrentMessageSet = result . index !== - 1 ;
801+ } else if ( lastReadMessageId ) {
802+ const result = findInMsgSetById ( lastReadMessageId , channel . state . messages ) ;
803+ isInCurrentMessageSet = ! ! result . target ;
804+ firstUnreadMessageId =
805+ result . index > - 1 ? channel . state . messages [ result . index + 1 ] ?. id : undefined ;
806+ } else {
807+ const lastReadTimestamp = channelUnreadUiState . last_read . getTime ( ) ;
808+ const { index : lastReadMessageIndex , target : lastReadMessage } = findInMsgSetByDate (
809+ channelUnreadUiState . last_read ,
810+ channel . state . messages ,
811+ true ,
812+ ) ;
813+
814+ if ( lastReadMessage ) {
815+ firstUnreadMessageId = channel . state . messages [ lastReadMessageIndex + 1 ] ?. id ;
816+ isInCurrentMessageSet = ! ! firstUnreadMessageId ;
817+ lastReadMessageId = lastReadMessage . id ;
818+ } else {
819+ dispatch ( { loadingMore : true , type : 'setLoadingMore' } ) ;
820+ let messages ;
821+ try {
822+ messages = (
823+ await channel . query (
824+ {
825+ messages : {
826+ created_at_around : channelUnreadUiState . last_read . toISOString ( ) ,
827+ limit : queryMessageLimit ,
828+ } ,
829+ } ,
830+ 'new' ,
831+ )
832+ ) . messages ;
833+ } catch ( e ) {
834+ addNotification ( t ( 'Failed to jump to the first unread message' ) , 'error' ) ;
835+ loadMoreFinished ( hasMoreMessages , channel . state . messages ) ;
836+ return ;
837+ }
794838
795- const currentMessageSet = channel . state . messages ;
796- for ( let i = currentMessageSet . length - 1 ; i >= 0 ; i -- ) {
797- const { id } = currentMessageSet [ i ] ;
798- if ( id === channelUnreadUiState . last_read_message_id ) {
799- indexOfLastReadMessage = i ;
800- break ;
839+ const firstMessageWithCreationDate = messages . find ( ( msg ) => msg . created_at ) ;
840+ if ( ! firstMessageWithCreationDate ) {
841+ addNotification ( t ( 'Failed to jump to the first unread message' ) , 'error' ) ;
842+ loadMoreFinished ( hasMoreMessages , channel . state . messages ) ;
843+ return ;
844+ }
845+ const firstMessageTimestamp = new Date (
846+ firstMessageWithCreationDate . created_at as string ,
847+ ) . getTime ( ) ;
848+ if ( lastReadTimestamp < firstMessageTimestamp ) {
849+ // whole channel is unread
850+ firstUnreadMessageId = firstMessageWithCreationDate . id ;
851+ hasMoreMessages = false ;
852+ } else {
853+ const result = findInMsgSetByDate ( channelUnreadUiState . last_read , messages ) ;
854+ lastReadMessageId = result . target ?. id ;
855+ hasMoreMessages = result . index >= Math . floor ( queryMessageLimit / 2 ) ;
856+ }
857+ loadMoreFinished ( hasMoreMessages , channel . state . messages ) ;
801858 }
802859 }
803860
804- if ( typeof indexOfLastReadMessage === 'undefined' ) {
861+ if ( ! firstUnreadMessageId && ! lastReadMessageId ) {
862+ addNotification ( t ( 'Failed to jump to the first unread message' ) , 'error' ) ;
863+ return ;
864+ }
865+
866+ if ( ! isInCurrentMessageSet ) {
805867 dispatch ( { loadingMore : true , type : 'setLoadingMore' } ) ;
806- let hasMoreMessages = true ;
807868 try {
808- await channel . state . loadMessageIntoState (
809- channelUnreadUiState . last_read_message_id ,
810- undefined ,
811- queryMessageLimit ,
812- ) ;
869+ const targetId = ( firstUnreadMessageId ?? lastReadMessageId ) as string ;
870+ await channel . state . loadMessageIntoState ( targetId , undefined , queryMessageLimit ) ;
813871 /**
814872 * if the index of the last read message on the page is beyond the half of the page,
815873 * we have arrived to the oldest page of the channel
816874 */
817- indexOfLastReadMessage = channel . state . messages . findIndex (
818- ( message ) => message . id === channelUnreadUiState . last_read_message_id ,
875+ const indexOfTarget = channel . state . messages . findIndex (
876+ ( message ) => message . id === targetId ,
819877 ) as number ;
820- hasMoreMessages = indexOfLastReadMessage >= Math . floor ( queryMessageLimit / 2 ) ;
878+ hasMoreMessages = indexOfTarget >= Math . floor ( queryMessageLimit / 2 ) ;
879+ loadMoreFinished ( hasMoreMessages , channel . state . messages ) ;
880+ firstUnreadMessageId =
881+ firstUnreadMessageId ?? channel . state . messages [ indexOfTarget + 1 ] ?. id ;
821882 } catch ( e ) {
822883 addNotification ( t ( 'Failed to jump to the first unread message' ) , 'error' ) ;
823884 loadMoreFinished ( hasMoreMessages , channel . state . messages ) ;
824885 return ;
825886 }
826-
827- loadMoreFinished ( hasMoreMessages , channel . state . messages ) ;
828887 }
829888
830- const firstUnreadMessage = channel . state . messages [ indexOfLastReadMessage + 1 ] ;
831- const jumpToMessageId = firstUnreadMessage ?. id ?? channelUnreadUiState . last_read_message_id ;
889+ if ( ! firstUnreadMessageId ) {
890+ addNotification ( t ( 'Failed to jump to the first unread message' ) , 'error' ) ;
891+ return ;
892+ }
893+ if ( ! channelUnreadUiState . first_unread_message_id )
894+ _setChannelUnreadUiState ( {
895+ ...channelUnreadUiState ,
896+ first_unread_message_id : firstUnreadMessageId ,
897+ last_read_message_id : lastReadMessageId ,
898+ } ) ;
832899
833900 dispatch ( {
834901 hasMoreNewer : channel . state . messages !== channel . state . latestMessages ,
835- highlightedMessageId : jumpToMessageId ,
902+ highlightedMessageId : firstUnreadMessageId ,
836903 type : 'jumpToMessageFinished' ,
837904 } ) ;
838905
@@ -845,7 +912,7 @@ const ChannelInner = <
845912 dispatch ( { type : 'clearHighlightedMessage' } ) ;
846913 } , 500 ) ;
847914 } ,
848- [ addNotification , channel , client , loadMoreFinished , t , channelUnreadUiState ] ,
915+ [ addNotification , channel , loadMoreFinished , t , channelUnreadUiState ] ,
849916 ) ;
850917
851918 const deleteMessage = useCallback (
0 commit comments