@@ -699,7 +699,7 @@ const ChannelWithContext = <
699699
700700 const connectionChangedHandler = ( event : ConnectionChangeEvent ) => {
701701 if ( event . online ) {
702- reloadChannel ( ) ;
702+ resyncChannel ( ) ;
703703 }
704704 } ;
705705
@@ -746,6 +746,7 @@ const ChannelWithContext = <
746746 try {
747747 await queryCall ( ) ;
748748 setLastRead ( new Date ( ) ) ;
749+ setHasMore ( true ) ;
749750 copyChannelState ( ) ;
750751 } catch ( err ) {
751752 setError ( err ) ;
@@ -879,11 +880,86 @@ const ChannelWithContext = <
879880 return ;
880881 } ) ;
881882
882- const reloadChannel = ( ) => {
883- channel ?. state . clearMessages ( ) ;
884- return loadChannel ( ) ;
883+ const resyncChannel = async ( ) => {
884+ if ( ! channel ) return ;
885+
886+ setError ( false ) ;
887+ try {
888+ /**
889+ * Allow a buffer of 30 new messages, so that MessageList won't move its scroll position,
890+ * giving smooth user experience.
891+ */
892+ const state = await channel . watch ( {
893+ messages : {
894+ limit : messages . length + 30 ,
895+ } ,
896+ } ) ;
897+
898+ const oldListTopMessage = messages [ 0 ] ;
899+ const oldListTopMessageId = messages [ 0 ] ?. id ;
900+ const oldListBottomMessage = messages [ messages . length - 1 ] ;
901+
902+ const newListTopMessage = state . messages [ 0 ] ;
903+ const newListBottomMessage = state . messages [ state . messages . length - 1 ] ;
904+
905+ if (
906+ ! oldListTopMessage || // previous list was empty
907+ ! oldListBottomMessage || // previous list was empty
908+ ! newListTopMessage || // new list is truncated
909+ ! newListBottomMessage // new list is truncated
910+ ) {
911+ /** Channel was truncated */
912+ channel . state . clearMessages ( ) ;
913+ channel . state . setIsUpToDate ( true ) ;
914+ channel . state . addMessagesSorted ( state . messages ) ;
915+ copyChannelState ( ) ;
916+ return ;
917+ }
918+
919+ const oldListTopMessageCreatedAt = oldListTopMessage . created_at ;
920+ const oldListBottomMessageCreatedAt = oldListBottomMessage . created_at ;
921+ const newListTopMessageCreatedAt = newListTopMessage . created_at
922+ ? new Date ( newListTopMessage . created_at )
923+ : new Date ( ) ;
924+ const newListBottomMessageCreatedAt = newListBottomMessage ?. created_at
925+ ? new Date ( newListBottomMessage . created_at )
926+ : new Date ( ) ;
927+
928+ let finalMessages = [ ] ;
929+
930+ if (
931+ oldListTopMessage &&
932+ oldListTopMessageCreatedAt &&
933+ oldListBottomMessageCreatedAt &&
934+ newListTopMessageCreatedAt < oldListTopMessageCreatedAt &&
935+ newListBottomMessageCreatedAt >= oldListBottomMessageCreatedAt
936+ ) {
937+ const index = state . messages . findIndex (
938+ ( message ) => message . id === oldListTopMessageId ,
939+ ) ;
940+ finalMessages = state . messages . slice ( index ) ;
941+ } else {
942+ finalMessages = state . messages ;
943+ }
944+
945+ channel . state . setIsUpToDate ( true ) ;
946+
947+ channel . state . clearMessages ( ) ;
948+ channel . state . addMessagesSorted ( finalMessages ) ;
949+ setHasMore ( true ) ;
950+ copyChannelState ( ) ;
951+ } catch ( err ) {
952+ setError ( err ) ;
953+ setLoading ( false ) ;
954+ }
885955 } ;
886956
957+ const reloadChannel = ( ) =>
958+ channelQueryCall ( async ( ) => {
959+ await channel ?. watch ( ) ;
960+ channel ?. state . setIsUpToDate ( true ) ;
961+ } ) ;
962+
887963 /**
888964 * Makes a query to load messages in channel.
889965 */
@@ -1206,6 +1282,7 @@ const ChannelWithContext = <
12061282 newMessages : ChannelState < At , Ch , Co , Ev , Me , Re , Us > [ 'messages' ] ,
12071283 ) => {
12081284 setLoadingMore ( false ) ;
1285+ setError ( false ) ;
12091286 setHasMore ( updatedHasMore ) ;
12101287 setMessages ( newMessages ) ;
12111288 } ,
@@ -1220,7 +1297,9 @@ const ChannelWithContext = <
12201297 Re ,
12211298 Us
12221299 > [ 'loadMore' ] = async ( ) => {
1223- if ( loadingMore || hasMore === false ) return ;
1300+ if ( loadingMore || hasMore === false ) {
1301+ return ;
1302+ }
12241303 setLoadingMore ( true ) ;
12251304
12261305 if ( ! messages . length ) {
@@ -1247,7 +1326,9 @@ const ChannelWithContext = <
12471326 }
12481327 } catch ( err ) {
12491328 console . warn ( 'Message pagination request failed with error' , err ) ;
1250- return setLoadingMore ( false ) ;
1329+ setError ( err ) ;
1330+ setLoadingMore ( false ) ;
1331+ throw err ;
12511332 }
12521333 } ;
12531334
@@ -1280,8 +1361,9 @@ const ChannelWithContext = <
12801361 }
12811362 } catch ( err ) {
12821363 console . warn ( 'Message pagination request failed with error' , err ) ;
1364+ setError ( err ) ;
12831365 setLoadingMoreRecent ( false ) ;
1284- return ;
1366+ throw err ;
12851367 }
12861368 } ;
12871369
@@ -1290,6 +1372,7 @@ const ChannelWithContext = <
12901372 ( newMessages : ChannelState < At , Ch , Co , Ev , Me , Re , Us > [ 'messages' ] ) => {
12911373 setLoadingMoreRecent ( false ) ;
12921374 setMessages ( newMessages ) ;
1375+ setError ( false ) ;
12931376 } ,
12941377 ) ;
12951378
@@ -1426,24 +1509,63 @@ const ChannelWithContext = <
14261509 Re ,
14271510 Us
14281511 > [ 'loadMoreThread' ] = async ( ) => {
1429- if ( threadLoadingMore || ! thread ?. id ) return ;
1512+ if ( threadLoadingMore || ! thread ?. id ) {
1513+ return ;
1514+ }
14301515 setThreadLoadingMore ( true ) ;
14311516
1432- if ( channel ) {
1433- const parentID = thread . id ;
1517+ try {
1518+ if ( channel ) {
1519+ const parentID = thread . id ;
14341520
1435- const oldMessages = channel . state . threads [ parentID ] || [ ] ;
1436- const oldestMessageID = oldMessages ?. [ 0 ] ?. id ;
1521+ /**
1522+ * In the channel is re-initializing, then threads may get wiped out during the process
1523+ * (check `addMessagesSorted` method on channel.state). In those cases, we still want to
1524+ * preserve the messages on active thread, so lets simply copy messages from UI state to
1525+ * `channel.state`.
1526+ */
1527+ channel . state . threads [ parentID ] = threadMessages ;
1528+ const oldestMessageID = threadMessages ?. [ 0 ] ?. id ;
1529+
1530+ const limit = 50 ;
1531+ const queryResponse = await channel . getReplies ( parentID , {
1532+ id_lt : oldestMessageID ,
1533+ limit,
1534+ } ) ;
1535+
1536+ const updatedHasMore = queryResponse . messages . length === limit ;
1537+ const updatedThreadMessages = channel . state . threads [ parentID ] || [ ] ;
1538+ loadMoreThreadFinished ( updatedHasMore , updatedThreadMessages ) ;
1539+ }
1540+ } catch ( err ) {
1541+ console . warn ( 'Message pagination request failed with error' , err ) ;
1542+ setError ( err ) ;
1543+ setThreadLoadingMore ( false ) ;
1544+ throw err ;
1545+ }
1546+ } ;
1547+
1548+ const reloadThread = async ( ) => {
1549+ if ( ! channel || ! thread ?. id ) return ;
1550+
1551+ setThreadLoadingMore ( true ) ;
1552+ try {
1553+ const parentID = thread . id ;
14371554
14381555 const limit = 50 ;
1556+ channel . state . threads [ parentID ] = [ ] ;
14391557 const queryResponse = await channel . getReplies ( parentID , {
1440- id_lt : oldestMessageID ,
1441- limit,
1558+ limit : 50 ,
14421559 } ) ;
14431560
14441561 const updatedHasMore = queryResponse . messages . length === limit ;
14451562 const updatedThreadMessages = channel . state . threads [ parentID ] || [ ] ;
14461563 loadMoreThreadFinished ( updatedHasMore , updatedThreadMessages ) ;
1564+ } catch ( err ) {
1565+ console . warn ( 'Thread loading request failed with error' , err ) ;
1566+ setError ( err ) ;
1567+ setThreadLoadingMore ( false ) ;
1568+ throw err ;
14471569 }
14481570 } ;
14491571
@@ -1625,6 +1747,7 @@ const ChannelWithContext = <
16251747 closeThread,
16261748 loadMoreThread,
16271749 openThread,
1750+ reloadThread,
16281751 setThreadLoadingMore,
16291752 thread,
16301753 threadHasMore,
@@ -1636,14 +1759,12 @@ const ChannelWithContext = <
16361759 typing,
16371760 } ) ;
16381761
1639- if ( ! channel || error ) {
1762+ if ( ! channel || ( error && messages . length === 0 ) ) {
16401763 return (
16411764 < LoadingErrorIndicator
16421765 error = { error }
16431766 listType = 'message'
1644- retry = { ( ) => {
1645- loadMore ( ) ;
1646- } }
1767+ retry = { reloadChannel }
16471768 />
16481769 ) ;
16491770 }
0 commit comments