stream-chat-react-native-core 5.38.1 → 5.39.0-beta.2

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 (242) hide show
  1. package/lib/commonjs/components/Channel/Channel.js +58 -25
  2. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  3. package/lib/commonjs/components/Channel/hooks/useCreateThreadContext.js +33 -21
  4. package/lib/commonjs/components/Channel/hooks/useCreateThreadContext.js.map +1 -1
  5. package/lib/commonjs/components/Chat/Chat.js +7 -0
  6. package/lib/commonjs/components/Chat/Chat.js.map +1 -1
  7. package/lib/commonjs/components/Indicators/EmptyStateIndicator.js +14 -0
  8. package/lib/commonjs/components/Indicators/EmptyStateIndicator.js.map +1 -1
  9. package/lib/commonjs/components/Indicators/LoadingIndicator.js +4 -0
  10. package/lib/commonjs/components/Indicators/LoadingIndicator.js.map +1 -1
  11. package/lib/commonjs/components/Message/hooks/useProcessReactions.js +13 -7
  12. package/lib/commonjs/components/Message/hooks/useProcessReactions.js.map +1 -1
  13. package/lib/commonjs/components/MessageList/InlineLoadingMoreRecentThreadIndicator.js +52 -0
  14. package/lib/commonjs/components/MessageList/InlineLoadingMoreRecentThreadIndicator.js.map +1 -0
  15. package/lib/commonjs/components/MessageList/MessageList.js +14 -6
  16. package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
  17. package/lib/commonjs/components/Thread/Thread.js +12 -5
  18. package/lib/commonjs/components/Thread/Thread.js.map +1 -1
  19. package/lib/commonjs/components/Thread/components/ThreadFooterComponent.js +41 -18
  20. package/lib/commonjs/components/Thread/components/ThreadFooterComponent.js.map +1 -1
  21. package/lib/commonjs/components/ThreadList/ThreadList.js +132 -0
  22. package/lib/commonjs/components/ThreadList/ThreadList.js.map +1 -0
  23. package/lib/commonjs/components/ThreadList/ThreadListItem.js +246 -0
  24. package/lib/commonjs/components/ThreadList/ThreadListItem.js.map +1 -0
  25. package/lib/commonjs/components/ThreadList/ThreadListUnreadBanner.js +66 -0
  26. package/lib/commonjs/components/ThreadList/ThreadListUnreadBanner.js.map +1 -0
  27. package/lib/commonjs/components/index.js +11 -11
  28. package/lib/commonjs/components/index.js.map +1 -1
  29. package/lib/commonjs/contexts/index.js +22 -0
  30. package/lib/commonjs/contexts/index.js.map +1 -1
  31. package/lib/commonjs/contexts/themeContext/utils/theme.js +19 -0
  32. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  33. package/lib/commonjs/contexts/threadContext/ThreadContext.js.map +1 -1
  34. package/lib/commonjs/contexts/threadsContext/ThreadListItemContext.js +28 -0
  35. package/lib/commonjs/contexts/threadsContext/ThreadListItemContext.js.map +1 -0
  36. package/lib/commonjs/contexts/threadsContext/ThreadsContext.js +33 -0
  37. package/lib/commonjs/contexts/threadsContext/ThreadsContext.js.map +1 -0
  38. package/lib/commonjs/hooks/index.js +11 -0
  39. package/lib/commonjs/hooks/index.js.map +1 -1
  40. package/lib/commonjs/hooks/useStateStore.js +23 -0
  41. package/lib/commonjs/hooks/useStateStore.js.map +1 -0
  42. package/lib/commonjs/i18n/en.json +7 -0
  43. package/lib/commonjs/i18n/es.json +7 -0
  44. package/lib/commonjs/i18n/fr.json +7 -0
  45. package/lib/commonjs/i18n/he.json +7 -0
  46. package/lib/commonjs/i18n/hi.json +7 -0
  47. package/lib/commonjs/i18n/it.json +7 -0
  48. package/lib/commonjs/i18n/ja.json +7 -0
  49. package/lib/commonjs/i18n/ko.json +7 -0
  50. package/lib/commonjs/i18n/nl.json +7 -0
  51. package/lib/commonjs/i18n/pt-br.json +7 -0
  52. package/lib/commonjs/i18n/ru.json +7 -0
  53. package/lib/commonjs/i18n/tr.json +7 -0
  54. package/lib/commonjs/icons/MessageBubble.js +19 -0
  55. package/lib/commonjs/icons/MessageBubble.js.map +1 -0
  56. package/lib/commonjs/icons/MessageBubbleEmpty.js +19 -0
  57. package/lib/commonjs/icons/MessageBubbleEmpty.js.map +1 -0
  58. package/lib/commonjs/icons/Reload.js +19 -0
  59. package/lib/commonjs/icons/Reload.js.map +1 -0
  60. package/lib/commonjs/icons/index.js +33 -0
  61. package/lib/commonjs/icons/index.js.map +1 -1
  62. package/lib/commonjs/store/mappers/mapDateTimeToStorable.js.map +1 -1
  63. package/lib/commonjs/version.json +1 -1
  64. package/lib/module/components/Channel/Channel.js +58 -25
  65. package/lib/module/components/Channel/Channel.js.map +1 -1
  66. package/lib/module/components/Channel/hooks/useCreateThreadContext.js +33 -21
  67. package/lib/module/components/Channel/hooks/useCreateThreadContext.js.map +1 -1
  68. package/lib/module/components/Chat/Chat.js +7 -0
  69. package/lib/module/components/Chat/Chat.js.map +1 -1
  70. package/lib/module/components/Indicators/EmptyStateIndicator.js +14 -0
  71. package/lib/module/components/Indicators/EmptyStateIndicator.js.map +1 -1
  72. package/lib/module/components/Indicators/LoadingIndicator.js +4 -0
  73. package/lib/module/components/Indicators/LoadingIndicator.js.map +1 -1
  74. package/lib/module/components/Message/hooks/useProcessReactions.js +13 -7
  75. package/lib/module/components/Message/hooks/useProcessReactions.js.map +1 -1
  76. package/lib/module/components/MessageList/InlineLoadingMoreRecentThreadIndicator.js +52 -0
  77. package/lib/module/components/MessageList/InlineLoadingMoreRecentThreadIndicator.js.map +1 -0
  78. package/lib/module/components/MessageList/MessageList.js +14 -6
  79. package/lib/module/components/MessageList/MessageList.js.map +1 -1
  80. package/lib/module/components/Thread/Thread.js +12 -5
  81. package/lib/module/components/Thread/Thread.js.map +1 -1
  82. package/lib/module/components/Thread/components/ThreadFooterComponent.js +41 -18
  83. package/lib/module/components/Thread/components/ThreadFooterComponent.js.map +1 -1
  84. package/lib/module/components/ThreadList/ThreadList.js +132 -0
  85. package/lib/module/components/ThreadList/ThreadList.js.map +1 -0
  86. package/lib/module/components/ThreadList/ThreadListItem.js +246 -0
  87. package/lib/module/components/ThreadList/ThreadListItem.js.map +1 -0
  88. package/lib/module/components/ThreadList/ThreadListUnreadBanner.js +66 -0
  89. package/lib/module/components/ThreadList/ThreadListUnreadBanner.js.map +1 -0
  90. package/lib/module/components/index.js +11 -11
  91. package/lib/module/components/index.js.map +1 -1
  92. package/lib/module/contexts/index.js +22 -0
  93. package/lib/module/contexts/index.js.map +1 -1
  94. package/lib/module/contexts/themeContext/utils/theme.js +19 -0
  95. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  96. package/lib/module/contexts/threadContext/ThreadContext.js.map +1 -1
  97. package/lib/module/contexts/threadsContext/ThreadListItemContext.js +28 -0
  98. package/lib/module/contexts/threadsContext/ThreadListItemContext.js.map +1 -0
  99. package/lib/module/contexts/threadsContext/ThreadsContext.js +33 -0
  100. package/lib/module/contexts/threadsContext/ThreadsContext.js.map +1 -0
  101. package/lib/module/hooks/index.js +11 -0
  102. package/lib/module/hooks/index.js.map +1 -1
  103. package/lib/module/hooks/useStateStore.js +23 -0
  104. package/lib/module/hooks/useStateStore.js.map +1 -0
  105. package/lib/module/i18n/en.json +7 -0
  106. package/lib/module/i18n/es.json +7 -0
  107. package/lib/module/i18n/fr.json +7 -0
  108. package/lib/module/i18n/he.json +7 -0
  109. package/lib/module/i18n/hi.json +7 -0
  110. package/lib/module/i18n/it.json +7 -0
  111. package/lib/module/i18n/ja.json +7 -0
  112. package/lib/module/i18n/ko.json +7 -0
  113. package/lib/module/i18n/nl.json +7 -0
  114. package/lib/module/i18n/pt-br.json +7 -0
  115. package/lib/module/i18n/ru.json +7 -0
  116. package/lib/module/i18n/tr.json +7 -0
  117. package/lib/module/icons/MessageBubble.js +19 -0
  118. package/lib/module/icons/MessageBubble.js.map +1 -0
  119. package/lib/module/icons/MessageBubbleEmpty.js +19 -0
  120. package/lib/module/icons/MessageBubbleEmpty.js.map +1 -0
  121. package/lib/module/icons/Reload.js +19 -0
  122. package/lib/module/icons/Reload.js.map +1 -0
  123. package/lib/module/icons/index.js +33 -0
  124. package/lib/module/icons/index.js.map +1 -1
  125. package/lib/module/store/mappers/mapDateTimeToStorable.js.map +1 -1
  126. package/lib/module/version.json +1 -1
  127. package/lib/typescript/components/AttachmentPicker/AttachmentPicker.d.ts +1 -1
  128. package/lib/typescript/components/Channel/Channel.d.ts +3 -2
  129. package/lib/typescript/components/Channel/Channel.d.ts.map +1 -1
  130. package/lib/typescript/components/Channel/hooks/useCreateThreadContext.d.ts +34 -1
  131. package/lib/typescript/components/Channel/hooks/useCreateThreadContext.d.ts.map +1 -1
  132. package/lib/typescript/components/Chat/Chat.d.ts.map +1 -1
  133. package/lib/typescript/components/Indicators/EmptyStateIndicator.d.ts +1 -1
  134. package/lib/typescript/components/Indicators/EmptyStateIndicator.d.ts.map +1 -1
  135. package/lib/typescript/components/Indicators/LoadingIndicator.d.ts +1 -1
  136. package/lib/typescript/components/Indicators/LoadingIndicator.d.ts.map +1 -1
  137. package/lib/typescript/components/Message/hooks/useProcessReactions.d.ts.map +1 -1
  138. package/lib/typescript/components/MessageList/InlineLoadingMoreRecentThreadIndicator.d.ts +8 -0
  139. package/lib/typescript/components/MessageList/InlineLoadingMoreRecentThreadIndicator.d.ts.map +1 -0
  140. package/lib/typescript/components/MessageList/MessageList.d.ts +1 -1
  141. package/lib/typescript/components/MessageList/MessageList.d.ts.map +1 -1
  142. package/lib/typescript/components/Thread/Thread.d.ts +1 -1
  143. package/lib/typescript/components/Thread/Thread.d.ts.map +1 -1
  144. package/lib/typescript/components/Thread/components/ThreadFooterComponent.d.ts +1 -0
  145. package/lib/typescript/components/Thread/components/ThreadFooterComponent.d.ts.map +1 -1
  146. package/lib/typescript/components/ThreadList/ThreadList.d.ts +11 -0
  147. package/lib/typescript/components/ThreadList/ThreadList.d.ts.map +1 -0
  148. package/lib/typescript/components/ThreadList/ThreadListItem.d.ts +16 -0
  149. package/lib/typescript/components/ThreadList/ThreadListItem.d.ts.map +1 -0
  150. package/lib/typescript/components/ThreadList/ThreadListUnreadBanner.d.ts +3 -0
  151. package/lib/typescript/components/ThreadList/ThreadListUnreadBanner.d.ts.map +1 -0
  152. package/lib/typescript/components/index.d.ts +1 -1
  153. package/lib/typescript/components/index.d.ts.map +1 -1
  154. package/lib/typescript/contexts/attachmentPickerContext/AttachmentPickerContext.d.ts +1 -1
  155. package/lib/typescript/contexts/index.d.ts +2 -0
  156. package/lib/typescript/contexts/index.d.ts.map +1 -1
  157. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +1 -1
  158. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +1 -1
  159. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +19 -0
  160. package/lib/typescript/contexts/themeContext/utils/theme.d.ts.map +1 -1
  161. package/lib/typescript/contexts/threadContext/ThreadContext.d.ts +11 -2
  162. package/lib/typescript/contexts/threadContext/ThreadContext.d.ts.map +1 -1
  163. package/lib/typescript/contexts/threadsContext/ThreadListItemContext.d.ts +19 -0
  164. package/lib/typescript/contexts/threadsContext/ThreadListItemContext.d.ts.map +1 -0
  165. package/lib/typescript/contexts/threadsContext/ThreadsContext.d.ts +25 -0
  166. package/lib/typescript/contexts/threadsContext/ThreadsContext.d.ts.map +1 -0
  167. package/lib/typescript/hooks/index.d.ts +1 -0
  168. package/lib/typescript/hooks/index.d.ts.map +1 -1
  169. package/lib/typescript/hooks/useStateStore.d.ts +4 -0
  170. package/lib/typescript/hooks/useStateStore.d.ts.map +1 -0
  171. package/lib/typescript/i18n/en.json +7 -0
  172. package/lib/typescript/i18n/es.json +7 -0
  173. package/lib/typescript/i18n/fr.json +7 -0
  174. package/lib/typescript/i18n/he.json +7 -0
  175. package/lib/typescript/i18n/hi.json +7 -0
  176. package/lib/typescript/i18n/it.json +7 -0
  177. package/lib/typescript/i18n/ja.json +7 -0
  178. package/lib/typescript/i18n/ko.json +7 -0
  179. package/lib/typescript/i18n/nl.json +7 -0
  180. package/lib/typescript/i18n/pt-br.json +7 -0
  181. package/lib/typescript/i18n/ru.json +7 -0
  182. package/lib/typescript/i18n/tr.json +7 -0
  183. package/lib/typescript/icons/MessageBubble.d.ts +4 -0
  184. package/lib/typescript/icons/MessageBubble.d.ts.map +1 -0
  185. package/lib/typescript/icons/MessageBubbleEmpty.d.ts +4 -0
  186. package/lib/typescript/icons/MessageBubbleEmpty.d.ts.map +1 -0
  187. package/lib/typescript/icons/Reload.d.ts +4 -0
  188. package/lib/typescript/icons/Reload.d.ts.map +1 -0
  189. package/lib/typescript/icons/index.d.ts +3 -0
  190. package/lib/typescript/icons/index.d.ts.map +1 -1
  191. package/lib/typescript/store/mappers/mapDateTimeToStorable.d.ts +1 -1
  192. package/lib/typescript/store/mappers/mapDateTimeToStorable.d.ts.map +1 -1
  193. package/lib/typescript/utils/i18n/Streami18n.d.ts +7 -0
  194. package/lib/typescript/utils/i18n/Streami18n.d.ts.map +1 -1
  195. package/package.json +2 -2
  196. package/src/components/Channel/Channel.tsx +54 -20
  197. package/src/components/Channel/hooks/useCreateThreadContext.ts +36 -31
  198. package/src/components/Chat/Chat.tsx +10 -0
  199. package/src/components/Indicators/EmptyStateIndicator.tsx +9 -2
  200. package/src/components/Indicators/LoadingIndicator.tsx +3 -1
  201. package/src/components/Message/hooks/useProcessReactions.ts +25 -4
  202. package/src/components/MessageList/InlineLoadingMoreRecentThreadIndicator.tsx +64 -0
  203. package/src/components/MessageList/MessageList.tsx +23 -9
  204. package/src/components/Thread/Thread.tsx +18 -9
  205. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +6 -0
  206. package/src/components/Thread/components/ThreadFooterComponent.tsx +28 -2
  207. package/src/components/ThreadList/ThreadList.tsx +119 -0
  208. package/src/components/ThreadList/ThreadListItem.tsx +268 -0
  209. package/src/components/ThreadList/ThreadListUnreadBanner.tsx +52 -0
  210. package/src/components/index.ts +1 -1
  211. package/src/contexts/index.ts +2 -0
  212. package/src/contexts/themeContext/utils/theme.ts +36 -0
  213. package/src/contexts/threadContext/ThreadContext.tsx +9 -2
  214. package/src/contexts/threadsContext/ThreadListItemContext.tsx +41 -0
  215. package/src/contexts/threadsContext/ThreadsContext.tsx +62 -0
  216. package/src/hooks/index.ts +1 -0
  217. package/src/hooks/useStateStore.ts +31 -0
  218. package/src/i18n/en.json +7 -0
  219. package/src/i18n/es.json +7 -0
  220. package/src/i18n/fr.json +7 -0
  221. package/src/i18n/he.json +7 -0
  222. package/src/i18n/hi.json +7 -0
  223. package/src/i18n/it.json +7 -0
  224. package/src/i18n/ja.json +7 -0
  225. package/src/i18n/ko.json +7 -0
  226. package/src/i18n/nl.json +7 -0
  227. package/src/i18n/pt-br.json +7 -0
  228. package/src/i18n/ru.json +7 -0
  229. package/src/i18n/tr.json +7 -0
  230. package/src/icons/MessageBubble.tsx +12 -0
  231. package/src/icons/MessageBubbleEmpty.tsx +12 -0
  232. package/src/icons/Reload.tsx +12 -0
  233. package/src/icons/index.ts +3 -0
  234. package/src/store/mappers/mapDateTimeToStorable.ts +1 -1
  235. package/src/version.json +1 -1
  236. package/lib/commonjs/components/MessageList/InlineLoadingMoreThreadIndicator.js +0 -52
  237. package/lib/commonjs/components/MessageList/InlineLoadingMoreThreadIndicator.js.map +0 -1
  238. package/lib/module/components/MessageList/InlineLoadingMoreThreadIndicator.js +0 -52
  239. package/lib/module/components/MessageList/InlineLoadingMoreThreadIndicator.js.map +0 -1
  240. package/lib/typescript/components/MessageList/InlineLoadingMoreThreadIndicator.d.ts +0 -8
  241. package/lib/typescript/components/MessageList/InlineLoadingMoreThreadIndicator.d.ts.map +0 -1
  242. package/src/components/MessageList/InlineLoadingMoreThreadIndicator.tsx +0 -64
@@ -18,6 +18,7 @@ import {
18
18
  StreamChat,
19
19
  Event as StreamEvent,
20
20
  Message as StreamMessage,
21
+ Thread,
21
22
  } from 'stream-chat';
22
23
 
23
24
  import { useCreateChannelContext } from './hooks/useCreateChannelContext';
@@ -60,7 +61,11 @@ import {
60
61
  SuggestionsProvider,
61
62
  } from '../../contexts/suggestionsContext/SuggestionsContext';
62
63
  import { useTheme } from '../../contexts/themeContext/ThemeContext';
63
- import { ThreadContextValue, ThreadProvider } from '../../contexts/threadContext/ThreadContext';
64
+ import {
65
+ ThreadContextValue,
66
+ ThreadProvider,
67
+ ThreadType,
68
+ } from '../../contexts/threadContext/ThreadContext';
64
69
  import {
65
70
  TranslationContextValue,
66
71
  useTranslationContext,
@@ -326,10 +331,9 @@ export type ChannelPropsWithContext<
326
331
  | 'VideoThumbnail'
327
332
  >
328
333
  > &
329
- Partial<
330
- Pick<ThreadContextValue<StreamChatGenerics>, 'allowThreadMessagesInChannel' | 'thread'>
331
- > & {
334
+ Partial<Pick<ThreadContextValue<StreamChatGenerics>, 'allowThreadMessagesInChannel'>> & {
332
335
  shouldSyncChannel: boolean;
336
+ thread: ThreadType<StreamChatGenerics>;
333
337
  /**
334
338
  * Additional props passed to keyboard avoiding view
335
339
  */
@@ -585,7 +589,7 @@ const ChannelWithContext = <
585
589
  StickyHeader = StickyHeaderDefault,
586
590
  supportedReactions = reactionData,
587
591
  t,
588
- thread: threadProps,
592
+ thread: threadFromProps,
589
593
  threadList,
590
594
  threadMessages,
591
595
  typing,
@@ -598,6 +602,8 @@ const ChannelWithContext = <
598
602
  watchers,
599
603
  } = props;
600
604
 
605
+ const { thread: threadProps, threadInstance } = threadFromProps;
606
+
601
607
  const {
602
608
  theme: {
603
609
  channel: { selectChannel },
@@ -616,9 +622,7 @@ const ChannelWithContext = <
616
622
  const [quotedMessage, setQuotedMessage] = useState<boolean | MessageType<StreamChatGenerics>>(
617
623
  false,
618
624
  );
619
- const [thread, setThread] = useState<ThreadContextValue<StreamChatGenerics>['thread']>(
620
- threadProps || null,
621
- );
625
+ const [thread, setThread] = useState<MessageType<StreamChatGenerics> | null>(threadProps || null);
622
626
  const [threadHasMore, setThreadHasMore] = useState(true);
623
627
  const [threadLoadingMore, setThreadLoadingMore] = useState(false);
624
628
 
@@ -830,7 +834,7 @@ const ChannelWithContext = <
830
834
  setThreadMessages(updatedThreadMessages);
831
835
  }
832
836
 
833
- if (channel && thread?.id && event.message?.id === thread.id) {
837
+ if (channel && thread?.id && event.message?.id === thread.id && !threadInstance) {
834
838
  const updatedThread = channel.state.formatMessage(event.message);
835
839
  setThread(updatedThread);
836
840
  }
@@ -1219,7 +1223,7 @@ const ChannelWithContext = <
1219
1223
  loadMoreThreadFinished(updatedHasMore, updatedThreadMessages);
1220
1224
  const { messages } = await channel.getMessagesById([parentID]);
1221
1225
  const [threadMessage] = messages;
1222
- if (threadMessage) {
1226
+ if (threadMessage && !threadInstance) {
1223
1227
  const formattedMessage = channel.state.formatMessage(threadMessage);
1224
1228
  setThread(formattedMessage);
1225
1229
  }
@@ -1711,11 +1715,15 @@ const ChannelWithContext = <
1711
1715
  } else {
1712
1716
  updateMessage(messageResponse.message);
1713
1717
  }
1718
+
1719
+ threadInstance?.upsertReplyLocally?.({ message: messageResponse.message });
1714
1720
  }
1715
1721
  } catch (err) {
1716
1722
  console.log(err);
1717
1723
  message.status = MessageStatusTypes.FAILED;
1718
- updateMessage({ ...message, cid: channel.cid });
1724
+ const updatedMessage = { ...message, cid: channel.cid };
1725
+ updateMessage(updatedMessage);
1726
+ threadInstance?.upsertReplyLocally?.({ message: updatedMessage });
1719
1727
 
1720
1728
  if (enableOfflineSupport) {
1721
1729
  dbApi.updateMessage({
@@ -1743,6 +1751,7 @@ const ChannelWithContext = <
1743
1751
  commands: [],
1744
1752
  messageInput: '',
1745
1753
  });
1754
+ threadInstance?.upsertReplyLocally?.({ message: messagePreview });
1746
1755
 
1747
1756
  if (enableOfflineSupport) {
1748
1757
  // While sending a message, we add the message to local db with failed status, so that
@@ -2004,7 +2013,7 @@ const ChannelWithContext = <
2004
2013
 
2005
2014
  setMessages(channel.state.messages);
2006
2015
 
2007
- await DBSyncManager.queueTask<StreamChatGenerics>({
2016
+ const sendReactionResponse = await DBSyncManager.queueTask<StreamChatGenerics>({
2008
2017
  client,
2009
2018
  task: {
2010
2019
  channelId: channel.id,
@@ -2014,6 +2023,9 @@ const ChannelWithContext = <
2014
2023
  type: 'send-reaction',
2015
2024
  },
2016
2025
  });
2026
+ if (sendReactionResponse?.message) {
2027
+ threadInstance?.upsertReplyLocally?.({ message: sendReactionResponse.message });
2028
+ }
2017
2029
  };
2018
2030
 
2019
2031
  const deleteMessage: MessagesContextValue<StreamChatGenerics>['deleteMessage'] = async (
@@ -2036,12 +2048,15 @@ const ChannelWithContext = <
2036
2048
  DBSyncManager.dropPendingTasks({ messageId: message.id });
2037
2049
  removeMessage(message);
2038
2050
  } else {
2039
- updateMessage({
2051
+ const updatedMessage = {
2040
2052
  ...message,
2041
2053
  cid: channel.cid,
2042
2054
  deleted_at: new Date().toISOString(),
2043
2055
  type: 'deleted',
2044
- });
2056
+ };
2057
+ updateMessage(updatedMessage);
2058
+
2059
+ threadInstance?.upsertReplyLocally({ message: updatedMessage });
2045
2060
 
2046
2061
  const data = await DBSyncManager.queueTask<StreamChatGenerics>({
2047
2062
  client,
@@ -2101,12 +2116,18 @@ const ChannelWithContext = <
2101
2116
  */
2102
2117
  const openThread: ThreadContextValue<StreamChatGenerics>['openThread'] = useCallback(
2103
2118
  (message) => {
2104
- const newThreadMessages = message?.id ? channel?.state?.threads[message.id] || [] : [];
2105
2119
  setThread(message);
2106
- setThreadMessages(newThreadMessages);
2120
+
2121
+ if (channel.initialized) {
2122
+ channel.markRead({ thread_id: message.id });
2123
+ }
2124
+ // This was causing inconsistencies within the thread state as well as being responsible
2125
+ // of threads essentially never unloading (due to all of the previous threads + 50 loading
2126
+ // every time we'd run this). It seemingly has no impact (other than a performance boost)
2127
+ // and having it was causing issues with the Threads V2 architecture.
2128
+ // setThreadMessages(newThreadMessages);
2107
2129
  },
2108
- // eslint-disable-next-line react-hooks/exhaustive-deps
2109
- [setThread, setThreadMessages],
2130
+ [channel, setThread],
2110
2131
  );
2111
2132
 
2112
2133
  const closeThread: ThreadContextValue<StreamChatGenerics>['closeThread'] = useCallback(() => {
@@ -2407,6 +2428,7 @@ const ChannelWithContext = <
2407
2428
  setThreadLoadingMore,
2408
2429
  thread,
2409
2430
  threadHasMore,
2431
+ threadInstance,
2410
2432
  threadLoadingMore,
2411
2433
  threadMessages,
2412
2434
  });
@@ -2479,7 +2501,18 @@ export const Channel = <
2479
2501
  const { client, enableOfflineSupport } = useChatContext<StreamChatGenerics>();
2480
2502
  const { t } = useTranslationContext();
2481
2503
 
2482
- const shouldSyncChannel = props.thread?.id ? !!props.threadList : true;
2504
+ const threadFromProps = props?.thread;
2505
+ const threadMessage = (
2506
+ threadFromProps?.threadInstance ? threadFromProps.thread : threadFromProps
2507
+ ) as MessageType<StreamChatGenerics>;
2508
+ const threadInstance = threadFromProps?.threadInstance as Thread;
2509
+
2510
+ const thread: ThreadType<StreamChatGenerics> = {
2511
+ thread: threadMessage,
2512
+ threadInstance,
2513
+ };
2514
+
2515
+ const shouldSyncChannel = threadMessage?.id ? !!props.threadList : true;
2483
2516
 
2484
2517
  const {
2485
2518
  members,
@@ -2498,7 +2531,7 @@ export const Channel = <
2498
2531
  watchers,
2499
2532
  } = useChannelState<StreamChatGenerics>(
2500
2533
  props.channel,
2501
- props.threadList ? props.thread?.id : undefined,
2534
+ props.threadList ? threadMessage?.id : undefined,
2502
2535
  );
2503
2536
 
2504
2537
  return (
@@ -2521,6 +2554,7 @@ export const Channel = <
2521
2554
  setTyping,
2522
2555
  setWatcherCount,
2523
2556
  setWatchers,
2557
+ thread,
2524
2558
  threadMessages,
2525
2559
  typing,
2526
2560
  watcherCount,
@@ -1,8 +1,16 @@
1
- import { useMemo } from 'react';
1
+ import { ThreadState } from 'stream-chat';
2
2
 
3
3
  import type { ThreadContextValue } from '../../../contexts/threadContext/ThreadContext';
4
+ import { useStateStore } from '../../../hooks';
4
5
  import type { DefaultStreamChatGenerics } from '../../../types/types';
5
- import { reduceMessagesToString } from '../../../utils/utils';
6
+
7
+ const selector = (nextValue: ThreadState) =>
8
+ [
9
+ nextValue.replies,
10
+ nextValue.pagination.isLoadingPrev,
11
+ nextValue.pagination.isLoadingNext,
12
+ nextValue.parentMessage,
13
+ ] as const;
6
14
 
7
15
  export const useCreateThreadContext = <
8
16
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
@@ -15,38 +23,35 @@ export const useCreateThreadContext = <
15
23
  setThreadLoadingMore,
16
24
  thread,
17
25
  threadHasMore,
26
+ threadInstance,
18
27
  threadLoadingMore,
19
28
  threadMessages,
20
29
  }: ThreadContextValue<StreamChatGenerics>) => {
21
- const threadId = thread?.id;
22
- const threadReplyCount = thread?.reply_count;
23
- const threadLatestReactions = thread?.latest_reactions;
24
- const threadMessagesStr = reduceMessagesToString(threadMessages);
30
+ const [latestReplies, isLoadingPrev, isLoadingNext] =
31
+ useStateStore(threadInstance?.state, selector) ?? [];
25
32
 
26
- const threadContext: ThreadContextValue<StreamChatGenerics> = useMemo(
27
- () => ({
28
- allowThreadMessagesInChannel,
29
- closeThread,
30
- loadMoreThread,
31
- openThread,
32
- reloadThread,
33
- setThreadLoadingMore,
34
- thread,
35
- threadHasMore,
36
- threadLoadingMore,
37
- threadMessages,
38
- }),
39
- // eslint-disable-next-line react-hooks/exhaustive-deps
40
- [
41
- allowThreadMessagesInChannel,
42
- threadHasMore,
43
- threadId,
44
- threadLoadingMore,
45
- threadMessagesStr,
46
- threadReplyCount,
47
- threadLatestReactions,
48
- ],
49
- );
33
+ const contextAdapter = threadInstance
34
+ ? {
35
+ loadMoreRecentThread: threadInstance.loadNextPage,
36
+ loadMoreThread: threadInstance.loadPrevPage,
37
+ threadInstance,
38
+ threadLoadingMore: isLoadingPrev,
39
+ threadLoadingMoreRecent: isLoadingNext,
40
+ threadMessages: latestReplies ?? [],
41
+ }
42
+ : {};
50
43
 
51
- return threadContext;
44
+ return {
45
+ allowThreadMessagesInChannel,
46
+ closeThread,
47
+ loadMoreThread,
48
+ openThread,
49
+ reloadThread,
50
+ setThreadLoadingMore,
51
+ thread,
52
+ threadHasMore,
53
+ threadLoadingMore,
54
+ threadMessages,
55
+ ...contextAdapter,
56
+ };
52
57
  };
@@ -215,6 +215,16 @@ const ChatWithContext = <
215
215
  // eslint-disable-next-line react-hooks/exhaustive-deps
216
216
  }, [userID, enableOfflineSupport]);
217
217
 
218
+ useEffect(() => {
219
+ if (!client) return;
220
+
221
+ client.threads.registerSubscriptions();
222
+
223
+ return () => {
224
+ client.threads.unregisterSubscriptions();
225
+ };
226
+ }, [client]);
227
+
218
228
  // In case something went wrong, make sure to also unsubscribe the listener
219
229
  // on unmount if it exists to prevent a memory leak.
220
230
  useEffect(() => () => DBSyncManager.connectionChangedListener?.unsubscribe(), []);
@@ -4,10 +4,10 @@ import { StyleSheet, Text, View } from 'react-native';
4
4
  import { useTheme } from '../../contexts/themeContext/ThemeContext';
5
5
  import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
6
6
  import { useViewport } from '../../hooks/useViewport';
7
- import { ChatIcon, MessageIcon } from '../../icons';
7
+ import { ChatIcon, MessageBubbleEmpty, MessageIcon } from '../../icons';
8
8
 
9
9
  export type EmptyStateProps = {
10
- listType?: 'channel' | 'message' | 'default';
10
+ listType?: 'channel' | 'message' | 'threads' | 'default';
11
11
  };
12
12
 
13
13
  export const EmptyStateIndicator = ({ listType }: EmptyStateProps) => {
@@ -55,6 +55,13 @@ export const EmptyStateIndicator = ({ listType }: EmptyStateProps) => {
55
55
  </Text>
56
56
  </View>
57
57
  );
58
+ case 'threads':
59
+ return (
60
+ <View style={[styles.container]}>
61
+ <MessageBubbleEmpty height={width} pathFill={'#B4BBBA'} width={width} />
62
+ <Text style={{ color: '#7E828B' }}>{t<string>('No threads here yet')}...</Text>
63
+ </View>
64
+ );
58
65
  default:
59
66
  return <Text style={[{ color: black }, messageContainer]}>No items exist</Text>;
60
67
  }
@@ -26,7 +26,7 @@ const LoadingIndicatorWrapper = ({ text }: LoadingIndicatorWrapperProps) => {
26
26
  };
27
27
 
28
28
  export type LoadingProps = {
29
- listType?: 'channel' | 'message' | 'default';
29
+ listType?: 'channel' | 'message' | 'threads' | 'default';
30
30
  loadingText?: string;
31
31
  };
32
32
 
@@ -47,6 +47,8 @@ export const LoadingIndicator = (props: LoadingProps) => {
47
47
  return <LoadingIndicatorWrapper text={t('Loading channels...')} />;
48
48
  case 'message':
49
49
  return <LoadingIndicatorWrapper text={t('Loading messages...')} />;
50
+ case 'threads':
51
+ return <LoadingIndicatorWrapper text={t('Loading threads...')} />;
50
52
  default:
51
53
  return <LoadingIndicatorWrapper text={t('Loading...')} />;
52
54
  }
@@ -2,6 +2,7 @@ import { ComponentType, useMemo } from 'react';
2
2
 
3
3
  import { ReactionResponse } from 'stream-chat';
4
4
 
5
+ import { useChatContext } from '../../../contexts';
5
6
  import {
6
7
  MessagesContextValue,
7
8
  useMessagesContext,
@@ -46,7 +47,15 @@ const isOwnReaction = <
46
47
  >(
47
48
  reactionType: string,
48
49
  ownReactions?: ReactionResponse<StreamChatGenerics>[] | null,
49
- ) => (ownReactions ? ownReactions.some((reaction) => reaction.type === reactionType) : false);
50
+ latestReactions?: ReactionResponse<StreamChatGenerics>[] | null,
51
+ userID?: string,
52
+ ) =>
53
+ (ownReactions ? ownReactions.some((reaction) => reaction.type === reactionType) : false) ||
54
+ (latestReactions
55
+ ? latestReactions.some(
56
+ (reaction) => reaction?.user?.id === userID && reaction.type === reactionType,
57
+ )
58
+ : false);
50
59
 
51
60
  const isSupportedReaction = (reactionType: string, supportedReactions: ReactionData[]) =>
52
61
  supportedReactions
@@ -76,6 +85,7 @@ export const useProcessReactions = <
76
85
  props: UseProcessReactionsParams<StreamChatGenerics>,
77
86
  ) => {
78
87
  const { supportedReactions: contextSupportedReactions } = useMessagesContext();
88
+ const { client } = useChatContext<StreamChatGenerics>();
79
89
 
80
90
  const {
81
91
  latest_reactions,
@@ -100,7 +110,12 @@ export const useProcessReactions = <
100
110
  Icon: getEmojiByReactionType(reactionType, supportedReactions),
101
111
  lastReactionAt: last_reaction_at ? new Date(last_reaction_at) : null,
102
112
  latestReactedUserNames,
103
- own: isOwnReaction<StreamChatGenerics>(reactionType, own_reactions),
113
+ own: isOwnReaction<StreamChatGenerics>(
114
+ reactionType,
115
+ own_reactions,
116
+ latest_reactions,
117
+ client.userID,
118
+ ),
104
119
  type: reactionType,
105
120
  unlistedReactedUserCount: count - latestReactedUserNames.length,
106
121
  };
@@ -112,6 +127,12 @@ export const useProcessReactions = <
112
127
  hasReactions: unsortedReactions.length > 0,
113
128
  totalReactionCount: unsortedReactions.reduce((total, { count }) => total + count, 0),
114
129
  };
115
- // eslint-disable-next-line react-hooks/exhaustive-deps
116
- }, [reaction_groups, own_reactions?.length, latest_reactions?.length, sortReactions]);
130
+ }, [
131
+ client.userID,
132
+ reaction_groups,
133
+ own_reactions,
134
+ latest_reactions,
135
+ supportedReactions,
136
+ sortReactions,
137
+ ]);
117
138
  };
@@ -0,0 +1,64 @@
1
+ import React from 'react';
2
+ import { ActivityIndicator, StyleSheet, View } from 'react-native';
3
+
4
+ import { useThreadContext } from '../../contexts';
5
+ import { useTheme } from '../../contexts/themeContext/ThemeContext';
6
+
7
+ import type { DefaultStreamChatGenerics } from '../../types/types';
8
+
9
+ const styles = StyleSheet.create({
10
+ activityIndicatorContainer: {
11
+ padding: 10,
12
+ width: '100%',
13
+ },
14
+ });
15
+
16
+ export type InlineLoadingMoreRecentThreadIndicatorPropsWithContext = {
17
+ loadingMoreRecent?: boolean;
18
+ };
19
+
20
+ export const InlineLoadingMoreRecentIndicatorWithContext = ({
21
+ loadingMoreRecent,
22
+ }: InlineLoadingMoreRecentThreadIndicatorPropsWithContext) => {
23
+ const { theme } = useTheme();
24
+
25
+ const {
26
+ colors: { accent_blue },
27
+ } = theme;
28
+
29
+ if (!loadingMoreRecent) {
30
+ return null;
31
+ }
32
+
33
+ return (
34
+ <View style={styles.activityIndicatorContainer}>
35
+ <ActivityIndicator color={accent_blue} size='small' />
36
+ </View>
37
+ );
38
+ };
39
+
40
+ const areEqual = (
41
+ prevProps: InlineLoadingMoreRecentThreadIndicatorPropsWithContext,
42
+ nextProps: InlineLoadingMoreRecentThreadIndicatorPropsWithContext,
43
+ ) => {
44
+ const { loadingMoreRecent: prevLoadingMoreRecent } = prevProps;
45
+ const { loadingMoreRecent: nextLoadingMoreRecent } = nextProps;
46
+
47
+ const loadingMoreRecentEqual = prevLoadingMoreRecent === nextLoadingMoreRecent;
48
+ if (!loadingMoreRecentEqual) return false;
49
+
50
+ return true;
51
+ };
52
+
53
+ const MemoizedInlineLoadingMoreRecentIndicator = React.memo(
54
+ InlineLoadingMoreRecentIndicatorWithContext,
55
+ areEqual,
56
+ ) as typeof InlineLoadingMoreRecentIndicatorWithContext;
57
+
58
+ export const InlineLoadingMoreRecentThreadIndicator = <
59
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
60
+ >() => {
61
+ const { threadLoadingMoreRecent } = useThreadContext<StreamChatGenerics>();
62
+
63
+ return <MemoizedInlineLoadingMoreRecentIndicator loadingMoreRecent={threadLoadingMoreRecent} />;
64
+ };
@@ -20,7 +20,7 @@ import { useShouldScrollToRecentOnNewOwnMessage } from './hooks/useShouldScrollT
20
20
 
21
21
  import { InlineLoadingMoreIndicator } from './InlineLoadingMoreIndicator';
22
22
  import { InlineLoadingMoreRecentIndicator } from './InlineLoadingMoreRecentIndicator';
23
- import { InlineLoadingMoreThreadIndicator } from './InlineLoadingMoreThreadIndicator';
23
+ import { InlineLoadingMoreRecentThreadIndicator } from './InlineLoadingMoreRecentThreadIndicator';
24
24
  import { getLastReceivedMessage } from './utils/getLastReceivedMessage';
25
25
 
26
26
  import {
@@ -147,7 +147,10 @@ type MessageListPropsWithContext<
147
147
  | 'TypingIndicator'
148
148
  | 'TypingIndicatorContainer'
149
149
  > &
150
- Pick<ThreadContextValue<StreamChatGenerics>, 'loadMoreThread' | 'thread'> & {
150
+ Pick<
151
+ ThreadContextValue<StreamChatGenerics>,
152
+ 'loadMoreRecentThread' | 'loadMoreThread' | 'thread' | 'threadInstance'
153
+ > & {
151
154
  /**
152
155
  * Besides existing (default) UX behavior of underlying FlatList of MessageList component, if you want
153
156
  * to attach some additional props to underlying FlatList, you can add it to following prop.
@@ -221,9 +224,9 @@ const MessageListWithContext = <
221
224
  >(
222
225
  props: MessageListPropsWithContext<StreamChatGenerics>,
223
226
  ) => {
224
- const LoadingMoreIndicator = props.threadList
225
- ? InlineLoadingMoreThreadIndicator
226
- : InlineLoadingMoreIndicator;
227
+ const LoadingMoreRecentIndicator = props.threadList
228
+ ? InlineLoadingMoreRecentThreadIndicator
229
+ : InlineLoadingMoreRecentIndicator;
227
230
  const {
228
231
  additionalFlatListProps,
229
232
  channel,
@@ -234,9 +237,9 @@ const MessageListWithContext = <
234
237
  disableTypingIndicator,
235
238
  EmptyStateIndicator,
236
239
  FlatList,
237
- FooterComponent = LoadingMoreIndicator,
240
+ FooterComponent = InlineLoadingMoreIndicator,
238
241
  hasNoMoreRecentMessagesToLoad,
239
- HeaderComponent = InlineLoadingMoreRecentIndicator,
242
+ HeaderComponent = LoadingMoreRecentIndicator,
240
243
  hideStickyDateHeader,
241
244
  initialScrollToFirstUnreadMessage,
242
245
  InlineDateSeparator,
@@ -249,6 +252,7 @@ const MessageListWithContext = <
249
252
  LoadingIndicator,
250
253
  loadMore,
251
254
  loadMoreRecent,
255
+ loadMoreRecentThread,
252
256
  loadMoreThread,
253
257
  markRead,
254
258
  Message,
@@ -269,6 +273,7 @@ const MessageListWithContext = <
269
273
  StickyHeader,
270
274
  targetedMessage,
271
275
  thread,
276
+ threadInstance,
272
277
  threadList = false,
273
278
  TypingIndicator,
274
279
  TypingIndicatorContainer,
@@ -744,7 +749,13 @@ const MessageListWithContext = <
744
749
  if (onEndReachedInPromise.current) {
745
750
  await onEndReachedInPromise.current;
746
751
  }
747
- onStartReachedInPromise.current = loadMoreRecent(limit).then(callback).catch(onError);
752
+ onStartReachedInPromise.current = (
753
+ threadList && !!threadInstance && loadMoreRecentThread
754
+ ? loadMoreRecentThread({ limit })
755
+ : loadMoreRecent(limit)
756
+ )
757
+ .then(callback)
758
+ .catch(onError);
748
759
  };
749
760
 
750
761
  /**
@@ -1253,7 +1264,8 @@ export const MessageList = <
1253
1264
  const { hasNoMoreRecentMessagesToLoad, loadMore, loadMoreRecent } =
1254
1265
  usePaginatedMessageListContext<StreamChatGenerics>();
1255
1266
  const { overlay } = useOverlayContext();
1256
- const { loadMoreThread, thread } = useThreadContext<StreamChatGenerics>();
1267
+ const { loadMoreRecentThread, loadMoreThread, thread, threadInstance } =
1268
+ useThreadContext<StreamChatGenerics>();
1257
1269
 
1258
1270
  return (
1259
1271
  <MessageListWithContext
@@ -1280,6 +1292,7 @@ export const MessageList = <
1280
1292
  LoadingIndicator,
1281
1293
  loadMore,
1282
1294
  loadMoreRecent,
1295
+ loadMoreRecentThread,
1283
1296
  loadMoreThread,
1284
1297
  markRead,
1285
1298
  Message,
@@ -1297,6 +1310,7 @@ export const MessageList = <
1297
1310
  StickyHeader,
1298
1311
  targetedMessage,
1299
1312
  thread,
1313
+ threadInstance,
1300
1314
  threadList,
1301
1315
  TypingIndicator,
1302
1316
  TypingIndicatorContainer,
@@ -23,7 +23,12 @@ type ThreadPropsWithContext<
23
23
  Pick<MessagesContextValue<StreamChatGenerics>, 'MessageList'> &
24
24
  Pick<
25
25
  ThreadContextValue<StreamChatGenerics>,
26
- 'closeThread' | 'loadMoreThread' | 'parentMessagePreventPress' | 'reloadThread' | 'thread'
26
+ | 'closeThread'
27
+ | 'loadMoreThread'
28
+ | 'parentMessagePreventPress'
29
+ | 'reloadThread'
30
+ | 'thread'
31
+ | 'threadInstance'
27
32
  > & {
28
33
  /**
29
34
  * Additional props for underlying MessageInput component.
@@ -70,9 +75,13 @@ const ThreadWithContext = <
70
75
  onThreadDismount,
71
76
  parentMessagePreventPress = true,
72
77
  thread,
78
+ threadInstance,
73
79
  } = props;
74
80
 
75
81
  useEffect(() => {
82
+ if (threadInstance?.activate) {
83
+ threadInstance.activate();
84
+ }
76
85
  const loadMoreThreadAsync = async () => {
77
86
  await loadMoreThread();
78
87
  };
@@ -80,21 +89,20 @@ const ThreadWithContext = <
80
89
  if (thread?.id && thread.reply_count) {
81
90
  loadMoreThreadAsync();
82
91
  }
83
- // eslint-disable-next-line react-hooks/exhaustive-deps
84
- }, []);
85
92
 
86
- useEffect(
87
- () => () => {
93
+ return () => {
94
+ if (threadInstance?.deactivate) {
95
+ threadInstance.deactivate();
96
+ }
88
97
  if (closeThreadOnDismount) {
89
98
  closeThread();
90
99
  }
91
100
  if (onThreadDismount) {
92
101
  onThreadDismount();
93
102
  }
94
- },
103
+ };
95
104
  // eslint-disable-next-line react-hooks/exhaustive-deps
96
- [],
97
- );
105
+ }, []);
98
106
 
99
107
  if (!thread) return null;
100
108
 
@@ -137,7 +145,7 @@ export const Thread = <
137
145
  const { client } = useChatContext<StreamChatGenerics>();
138
146
  const { threadList } = useChannelContext<StreamChatGenerics>();
139
147
  const { MessageList } = useMessagesContext<StreamChatGenerics>();
140
- const { closeThread, loadMoreThread, reloadThread, thread } =
148
+ const { closeThread, loadMoreThread, reloadThread, thread, threadInstance } =
141
149
  useThreadContext<StreamChatGenerics>();
142
150
 
143
151
  if (thread?.id && !threadList) {
@@ -155,6 +163,7 @@ export const Thread = <
155
163
  MessageList,
156
164
  reloadThread,
157
165
  thread,
166
+ threadInstance,
158
167
  }}
159
168
  {...props}
160
169
  />