stream-chat-react-native-core 5.12.0-beta.3 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/lib/commonjs/components/Channel/Channel.js +40 -24
  2. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  3. package/lib/commonjs/components/Channel/hooks/useTargetedMessage.js +3 -3
  4. package/lib/commonjs/components/Channel/hooks/useTargetedMessage.js.map +1 -1
  5. package/lib/commonjs/components/ChannelPreview/ChannelPreview.js +9 -2
  6. package/lib/commonjs/components/ChannelPreview/ChannelPreview.js.map +1 -1
  7. package/lib/commonjs/components/MessageList/MessageList.js +84 -77
  8. package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
  9. package/lib/commonjs/components/MessageList/utils/getReadStates.js +9 -4
  10. package/lib/commonjs/components/MessageList/utils/getReadStates.js.map +1 -1
  11. package/lib/commonjs/version.json +1 -1
  12. package/lib/module/components/Channel/Channel.js +40 -24
  13. package/lib/module/components/Channel/Channel.js.map +1 -1
  14. package/lib/module/components/Channel/hooks/useTargetedMessage.js +3 -3
  15. package/lib/module/components/Channel/hooks/useTargetedMessage.js.map +1 -1
  16. package/lib/module/components/ChannelPreview/ChannelPreview.js +9 -2
  17. package/lib/module/components/ChannelPreview/ChannelPreview.js.map +1 -1
  18. package/lib/module/components/MessageList/MessageList.js +84 -77
  19. package/lib/module/components/MessageList/MessageList.js.map +1 -1
  20. package/lib/module/components/MessageList/utils/getReadStates.js +9 -4
  21. package/lib/module/components/MessageList/utils/getReadStates.js.map +1 -1
  22. package/lib/module/version.json +1 -1
  23. package/package.json +1 -1
  24. package/src/components/Channel/Channel.tsx +35 -15
  25. package/src/components/Channel/hooks/useTargetedMessage.ts +3 -3
  26. package/src/components/ChannelPreview/ChannelPreview.tsx +7 -0
  27. package/src/components/MessageList/MessageList.tsx +57 -56
  28. package/src/components/MessageList/utils/getReadStates.ts +3 -4
  29. package/src/version.json +1 -1
@@ -52,6 +52,13 @@ const ChannelPreviewWithContext = <
52
52
  const channelLastMessage = channel.lastMessage();
53
53
  const channelLastMessageString = `${channelLastMessage?.id}${channelLastMessage?.updated_at}`;
54
54
 
55
+ useEffect(() => {
56
+ const { unsubscribe } = client.on('notification.mark_read', () => {
57
+ setUnread(channel.countUnread());
58
+ });
59
+ return unsubscribe;
60
+ }, []);
61
+
55
62
  useEffect(() => {
56
63
  if (
57
64
  channelLastMessage &&
@@ -272,7 +272,6 @@ const MessageListWithContext = <
272
272
  overlay,
273
273
  reloadChannel,
274
274
  ScrollToBottomButton,
275
- scrollToFirstUnreadThreshold,
276
275
  selectedPicker,
277
276
  setFlatListRef,
278
277
  setMessages,
@@ -332,8 +331,7 @@ const MessageListWithContext = <
332
331
  * If the prop `initialScrollToFirstUnreadMessage` was enabled, then we scroll to the unread msg and set it to true
333
332
  * If not, the default offset of 0 for flatList means that it has been set already
334
333
  */
335
- const initialScrollSet = useRef<boolean>(!initialScrollToFirstUnreadMessage);
336
-
334
+ const [isInitialScrollDone, setInitialScrollDone] = useState(!initialScrollToFirstUnreadMessage);
337
335
  const channelResyncScrollSet = useRef<boolean>(true);
338
336
 
339
337
  /**
@@ -341,6 +339,11 @@ const MessageListWithContext = <
341
339
  */
342
340
  const scrollToDebounceTimeoutRef = useRef<NodeJS.Timeout>();
343
341
 
342
+ /**
343
+ * The timeout id used to lazier load the initial scroll set flag
344
+ */
345
+ const initialScrollSettingTimeoutRef = useRef<NodeJS.Timeout>();
346
+
344
347
  /**
345
348
  * If a messageId was requested to scroll to but was unloaded,
346
349
  * this flag keeps track of it to scroll to it after loading the message
@@ -423,29 +426,39 @@ const MessageListWithContext = <
423
426
  }, [disabled]);
424
427
 
425
428
  useEffect(() => {
426
- /**
427
- * 1. !initialScrollToFirstUnreadMessage && channel.countUnread() > 0
428
- *
429
- * In this case MessageList won't scroll to first unread message when opened, so we can mark
430
- * the channel as read right after opening.
431
- *
432
- * 2. initialScrollToFirstUnreadMessage && channel.countUnread() <= scrollToFirstUnreadThreshold
433
- *
434
- * In this case MessageList will be opened to first unread message.
435
- * But if there are not enough (scrollToFirstUnreadThreshold) unread messages, then MessageList
436
- * won't need to scroll up. So we can safely mark the channel as read right after opening.
437
- */
438
- const shouldMarkReadOnFirstLoad =
439
- !loading &&
440
- channel &&
441
- ((!initialScrollToFirstUnreadMessage && channel.countUnread() > 0) ||
442
- (initialScrollToFirstUnreadMessage &&
443
- channel.countUnread() <= scrollToFirstUnreadThreshold));
444
-
445
- if (shouldMarkReadOnFirstLoad) {
429
+ const getShouldMarkReadAutomatically = (): boolean => {
430
+ if (loading || !channel) {
431
+ // nothing to do
432
+ return false;
433
+ } else if (channel.countUnread() > 0) {
434
+ if (!initialScrollToFirstUnreadMessage) {
435
+ /*
436
+ * In this case MessageList won't scroll to first unread message when opened, so we can mark
437
+ * the channel as read right after opening.
438
+ * */
439
+ return true;
440
+ } else {
441
+ /*
442
+ * In this case MessageList will be opened to first unread message.
443
+ * But if there are were not enough unread messages, so that scrollToBottom button was not shown
444
+ * then MessageList won't need to scroll up. So we can safely mark the channel as read right after opening.
445
+ *
446
+ * NOTE: we must ensure that initial scroll is done, otherwise we do not wait till the unread scroll is finished
447
+ * */
448
+ if (scrollToBottomButtonVisible) return false;
449
+ /* if scrollToBottom button was not visible, wait till
450
+ * - initial scroll is done (indicates that if scrolling to index was needed it was triggered)
451
+ * */
452
+ return isInitialScrollDone;
453
+ }
454
+ }
455
+ return false;
456
+ };
457
+
458
+ if (getShouldMarkReadAutomatically()) {
446
459
  markRead();
447
460
  }
448
- }, [loading]);
461
+ }, [loading, scrollToBottomButtonVisible, isInitialScrollDone]);
449
462
 
450
463
  useEffect(() => {
451
464
  const lastReceivedMessage = getLastReceivedMessage(messageList);
@@ -492,7 +505,7 @@ const MessageListWithContext = <
492
505
 
493
506
  if (threadList || hasNoMoreRecentMessagesToLoad) {
494
507
  scrollToBottomIfNeeded();
495
- } else if (!scrollToBottomButtonVisible) {
508
+ } else {
496
509
  setScrollToBottomButtonVisible(true);
497
510
  }
498
511
 
@@ -529,23 +542,17 @@ const MessageListWithContext = <
529
542
  if (!channel || (!channel.initialized && !channel.offlineMode)) return null;
530
543
 
531
544
  const lastRead = channel.lastRead();
532
- const countUnread = channel.countUnread();
533
545
 
534
546
  function isMessageUnread(messageArrayIndex: number): boolean {
535
- if (lastRead && message.created_at) {
536
- return lastRead < message.created_at;
537
- } else {
538
- const isLatestMessageSetShown = !!channel.state.messageSets.find(
539
- (set) => set.isCurrent && set.isLatest,
540
- );
541
- return isLatestMessageSetShown && messageArrayIndex <= countUnread - 1;
547
+ const msg = messageList?.[messageArrayIndex];
548
+ if (lastRead && msg?.created_at) {
549
+ return lastRead < msg.created_at;
542
550
  }
551
+ return false;
543
552
  }
544
553
  const isCurrentMessageUnread = isMessageUnread(index);
545
- const isLastMessageUnread = isMessageUnread(index + 1);
546
-
547
554
  const showUnreadUnderlay = isCurrentMessageUnread && scrollToBottomButtonVisible;
548
- const insertInlineUnreadIndicator = showUnreadUnderlay && !isLastMessageUnread;
555
+ const insertInlineUnreadIndicator = showUnreadUnderlay && !isMessageUnread(index + 1); // show only if previous message is read
549
556
 
550
557
  if (message.type === 'system') {
551
558
  return (
@@ -742,8 +749,8 @@ const MessageListWithContext = <
742
749
  maybeCallOnEndReached();
743
750
  }
744
751
 
745
- // Show scrollToBottom button once scroll position goes beyond 300.
746
- const isScrollAtBottom = offset <= 300;
752
+ // Show scrollToBottom button once scroll position goes beyond 150.
753
+ const isScrollAtBottom = offset <= 150;
747
754
  const showScrollToBottomButton = !isScrollAtBottom || !hasNoMoreRecentMessagesToLoad;
748
755
 
749
756
  const shouldMarkRead =
@@ -829,21 +836,16 @@ const MessageListWithContext = <
829
836
  * Note: This effect fires on every list change with a small debounce so that scrolling isnt abrupted by an immediate rerender
830
837
  */
831
838
  useEffect(() => {
832
- if (scrollToDebounceTimeoutRef.current) clearTimeout(scrollToDebounceTimeoutRef.current);
833
839
  scrollToDebounceTimeoutRef.current = setTimeout(() => {
840
+ if (initialScrollToFirstUnreadMessage) {
841
+ initialScrollSettingTimeoutRef.current = setTimeout(() => {
842
+ // small timeout to ensure that handleScroll is called after scrollToIndex to set this flag
843
+ setInitialScrollDone(true);
844
+ }, 500);
845
+ }
834
846
  // goToMessage method might have requested to scroll to a message
835
847
  let messageIdToScroll: string | undefined = messageIdToScrollToRef.current;
836
- const countUnread = channelRef.current?.countUnread();
837
- if (
838
- !initialScrollSet.current &&
839
- initialScrollToFirstUnreadMessage &&
840
- countUnread > scrollToFirstUnreadThreshold
841
- ) {
842
- // find the first unread message, if we have to initially scroll to an unread message
843
- if (messageList.length >= countUnread) {
844
- messageIdToScroll = messageList[countUnread - 1].id;
845
- }
846
- } else if (targetedMessage && messageIdLastScrolledToRef.current !== targetedMessage) {
848
+ if (targetedMessage && messageIdLastScrolledToRef.current !== targetedMessage) {
847
849
  // if some messageId was targeted but not scrolledTo yet
848
850
  // we have scroll to there after loading completes
849
851
  messageIdToScroll = targetedMessage;
@@ -862,14 +864,13 @@ const MessageListWithContext = <
862
864
  messageIdToScrollToRef.current = undefined;
863
865
  // keep track of this messageId, so that we dont scroll to again for targeted message change
864
866
  messageIdLastScrolledToRef.current = messageIdToScroll;
865
- if (!initialScrollSet.current && initialScrollToFirstUnreadMessage) {
866
- initialScrollSet.current = true;
867
- } else {
868
- setTargetedMessage(messageIdToScroll);
869
- }
870
867
  }
871
868
  }, 150);
872
- }, [channel.initialized, messageList, targetedMessage, initialScrollToFirstUnreadMessage]);
869
+ return () => {
870
+ clearTimeout(scrollToDebounceTimeoutRef.current);
871
+ clearTimeout(initialScrollSettingTimeoutRef.current);
872
+ };
873
+ }, [targetedMessage, initialScrollToFirstUnreadMessage, messageList]);
873
874
 
874
875
  const messagesWithImages =
875
876
  legacyImageViewerSwipeBehaviour &&
@@ -25,10 +25,9 @@ export const getReadStates = <
25
25
  /**
26
26
  * Channel read state is stored by user and we only care about users who aren't the client
27
27
  */
28
- if (clientUserId) {
29
- delete read[clientUserId];
30
- }
31
- const members = Object.values(read);
28
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
29
+ const { [clientUserId ?? '']: _ignore, ...filteredRead } = read;
30
+ const members = Object.values(filteredRead);
32
31
 
33
32
  /**
34
33
  * Track number of members who have read previous messages
package/src/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "5.12.0-beta.3"
2
+ "version": "5.12.0"
3
3
  }