stream-chat-react-native-core 5.5.1 → 5.6.0-beta.1

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 (321) hide show
  1. package/lib/commonjs/components/Attachment/Gallery.js +21 -16
  2. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/GalleryImage.js +19 -3
  4. package/lib/commonjs/components/Attachment/GalleryImage.js.map +1 -1
  5. package/lib/commonjs/components/Channel/Channel.js +535 -149
  6. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  7. package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js +6 -0
  8. package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
  9. package/lib/commonjs/components/ChannelList/ChannelList.js +4 -15
  10. package/lib/commonjs/components/ChannelList/ChannelList.js.map +1 -1
  11. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js +112 -38
  12. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  13. package/lib/commonjs/components/Chat/Chat.js +16 -20
  14. package/lib/commonjs/components/Chat/Chat.js.map +1 -1
  15. package/lib/commonjs/components/Chat/hooks/useCreateChatContext.js +2 -4
  16. package/lib/commonjs/components/Chat/hooks/useCreateChatContext.js.map +1 -1
  17. package/lib/commonjs/components/Message/Message.js +21 -10
  18. package/lib/commonjs/components/Message/Message.js.map +1 -1
  19. package/lib/commonjs/components/Message/MessageSimple/MessageFooter.js +14 -12
  20. package/lib/commonjs/components/Message/MessageSimple/MessageFooter.js.map +1 -1
  21. package/lib/commonjs/components/Message/hooks/useMessageActionHandlers.js +9 -30
  22. package/lib/commonjs/components/Message/hooks/useMessageActionHandlers.js.map +1 -1
  23. package/lib/commonjs/components/Message/hooks/useMessageActions.js +21 -19
  24. package/lib/commonjs/components/Message/hooks/useMessageActions.js.map +1 -1
  25. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +28 -21
  26. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  27. package/lib/commonjs/components/MessageInput/ImageUploadPreview.js +23 -16
  28. package/lib/commonjs/components/MessageInput/ImageUploadPreview.js.map +1 -1
  29. package/lib/commonjs/components/MessageInput/MessageInput.js +39 -27
  30. package/lib/commonjs/components/MessageInput/MessageInput.js.map +1 -1
  31. package/lib/commonjs/components/MessageInput/SendButton.js +1 -1
  32. package/lib/commonjs/components/MessageInput/SendButton.js.map +1 -1
  33. package/lib/commonjs/components/index.js +1 -14
  34. package/lib/commonjs/components/index.js.map +1 -1
  35. package/lib/commonjs/contexts/chatContext/ChatContext.js +2 -2
  36. package/lib/commonjs/contexts/chatContext/ChatContext.js.map +1 -1
  37. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +134 -86
  38. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  39. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js +1 -0
  40. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  41. package/lib/commonjs/contexts/messagesContext/MessagesContext.js +2 -2
  42. package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
  43. package/lib/commonjs/hooks/useTranslatedMessage.js +1 -1
  44. package/lib/commonjs/hooks/useTranslatedMessage.js.map +1 -1
  45. package/lib/commonjs/mock-builders/DB/mock.js +2 -2
  46. package/lib/commonjs/mock-builders/DB/mock.js.map +1 -1
  47. package/lib/commonjs/mock-builders/api/deleteMessage.js +20 -0
  48. package/lib/commonjs/mock-builders/api/deleteMessage.js.map +1 -0
  49. package/lib/commonjs/mock-builders/api/deleteReaction.js +21 -0
  50. package/lib/commonjs/mock-builders/api/deleteReaction.js.map +1 -0
  51. package/lib/commonjs/mock-builders/api/sendReaction.js +21 -0
  52. package/lib/commonjs/mock-builders/api/sendReaction.js.map +1 -0
  53. package/lib/commonjs/mock-builders/event/connectionChanged.js +2 -0
  54. package/lib/commonjs/mock-builders/event/connectionChanged.js.map +1 -1
  55. package/lib/commonjs/store/QuickSqliteClient.js +40 -51
  56. package/lib/commonjs/store/QuickSqliteClient.js.map +1 -1
  57. package/lib/commonjs/store/apis/addPendingTask.js +37 -0
  58. package/lib/commonjs/store/apis/addPendingTask.js.map +1 -0
  59. package/lib/commonjs/store/apis/deleteMessage.js +26 -0
  60. package/lib/commonjs/store/apis/deleteMessage.js.map +1 -0
  61. package/lib/commonjs/store/apis/deletePendingTask.js +22 -0
  62. package/lib/commonjs/store/apis/deletePendingTask.js.map +1 -0
  63. package/lib/commonjs/store/apis/deleteReaction.js +30 -0
  64. package/lib/commonjs/store/apis/deleteReaction.js.map +1 -0
  65. package/lib/commonjs/store/apis/getChannelMessages.js +3 -3
  66. package/lib/commonjs/store/apis/getChannelMessages.js.map +1 -1
  67. package/lib/commonjs/store/apis/getChannels.js +1 -1
  68. package/lib/commonjs/store/apis/getChannels.js.map +1 -1
  69. package/lib/commonjs/store/apis/getPendingTasks.js +26 -0
  70. package/lib/commonjs/store/apis/getPendingTasks.js.map +1 -0
  71. package/lib/commonjs/store/apis/index.js +13 -0
  72. package/lib/commonjs/store/apis/index.js.map +1 -1
  73. package/lib/commonjs/store/apis/insertReaction.js +28 -0
  74. package/lib/commonjs/store/apis/insertReaction.js.map +1 -0
  75. package/lib/commonjs/store/apis/updateMessage.js.map +1 -1
  76. package/lib/commonjs/store/apis/updateReaction.js.map +1 -1
  77. package/lib/commonjs/store/mappers/mapDateTimeToStorable.js.map +1 -1
  78. package/lib/commonjs/store/mappers/mapMessageToStorable.js +3 -1
  79. package/lib/commonjs/store/mappers/mapMessageToStorable.js.map +1 -1
  80. package/lib/commonjs/store/mappers/mapStorableToTask.js +23 -0
  81. package/lib/commonjs/store/mappers/mapStorableToTask.js.map +1 -0
  82. package/lib/commonjs/store/mappers/mapTaskToStorable.js +18 -0
  83. package/lib/commonjs/store/mappers/mapTaskToStorable.js.map +1 -0
  84. package/lib/commonjs/store/schema.js +11 -0
  85. package/lib/commonjs/store/schema.js.map +1 -1
  86. package/lib/commonjs/store/sqlite-utils/appendOrderByClause.js +24 -0
  87. package/lib/commonjs/store/sqlite-utils/appendOrderByClause.js.map +1 -0
  88. package/lib/commonjs/store/sqlite-utils/createCreateTableQuery.js +1 -1
  89. package/lib/commonjs/store/sqlite-utils/createCreateTableQuery.js.map +1 -1
  90. package/lib/commonjs/store/sqlite-utils/createSelectQuery.js +8 -1
  91. package/lib/commonjs/store/sqlite-utils/createSelectQuery.js.map +1 -1
  92. package/lib/commonjs/store/sqlite-utils/createUpdateQuery.js +2 -2
  93. package/lib/commonjs/store/sqlite-utils/createUpdateQuery.js.map +1 -1
  94. package/lib/commonjs/store/sqlite-utils/createUpsertQuery.js +1 -1
  95. package/lib/commonjs/store/sqlite-utils/createUpsertQuery.js.map +1 -1
  96. package/lib/commonjs/utils/DBSyncManager.js +436 -0
  97. package/lib/commonjs/utils/DBSyncManager.js.map +1 -0
  98. package/lib/commonjs/utils/addReactionToLocalState.js +92 -0
  99. package/lib/commonjs/utils/addReactionToLocalState.js.map +1 -0
  100. package/lib/commonjs/utils/removeReactionFromLocalState.js +39 -0
  101. package/lib/commonjs/utils/removeReactionFromLocalState.js.map +1 -0
  102. package/lib/{module/components/Message → commonjs}/utils/removeReservedFields.js +1 -1
  103. package/lib/commonjs/utils/removeReservedFields.js.map +1 -0
  104. package/lib/commonjs/utils/utils.js +9 -3
  105. package/lib/commonjs/utils/utils.js.map +1 -1
  106. package/lib/commonjs/version.json +1 -1
  107. package/lib/module/components/Attachment/Gallery.js +21 -16
  108. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  109. package/lib/module/components/Attachment/GalleryImage.js +19 -3
  110. package/lib/module/components/Attachment/GalleryImage.js.map +1 -1
  111. package/lib/module/components/Channel/Channel.js +535 -149
  112. package/lib/module/components/Channel/Channel.js.map +1 -1
  113. package/lib/module/components/Channel/hooks/useCreateMessagesContext.js +6 -0
  114. package/lib/module/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
  115. package/lib/module/components/ChannelList/ChannelList.js +4 -15
  116. package/lib/module/components/ChannelList/ChannelList.js.map +1 -1
  117. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js +112 -38
  118. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  119. package/lib/module/components/Chat/Chat.js +16 -20
  120. package/lib/module/components/Chat/Chat.js.map +1 -1
  121. package/lib/module/components/Chat/hooks/useCreateChatContext.js +2 -4
  122. package/lib/module/components/Chat/hooks/useCreateChatContext.js.map +1 -1
  123. package/lib/module/components/Message/Message.js +21 -10
  124. package/lib/module/components/Message/Message.js.map +1 -1
  125. package/lib/module/components/Message/MessageSimple/MessageFooter.js +14 -12
  126. package/lib/module/components/Message/MessageSimple/MessageFooter.js.map +1 -1
  127. package/lib/module/components/Message/hooks/useMessageActionHandlers.js +9 -30
  128. package/lib/module/components/Message/hooks/useMessageActionHandlers.js.map +1 -1
  129. package/lib/module/components/Message/hooks/useMessageActions.js +21 -19
  130. package/lib/module/components/Message/hooks/useMessageActions.js.map +1 -1
  131. package/lib/module/components/MessageInput/FileUploadPreview.js +28 -21
  132. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  133. package/lib/module/components/MessageInput/ImageUploadPreview.js +23 -16
  134. package/lib/module/components/MessageInput/ImageUploadPreview.js.map +1 -1
  135. package/lib/module/components/MessageInput/MessageInput.js +39 -27
  136. package/lib/module/components/MessageInput/MessageInput.js.map +1 -1
  137. package/lib/module/components/MessageInput/SendButton.js +1 -1
  138. package/lib/module/components/MessageInput/SendButton.js.map +1 -1
  139. package/lib/module/components/index.js +1 -14
  140. package/lib/module/components/index.js.map +1 -1
  141. package/lib/module/contexts/chatContext/ChatContext.js +2 -2
  142. package/lib/module/contexts/chatContext/ChatContext.js.map +1 -1
  143. package/lib/module/contexts/messageInputContext/MessageInputContext.js +134 -86
  144. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  145. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js +1 -0
  146. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  147. package/lib/module/contexts/messagesContext/MessagesContext.js +2 -2
  148. package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
  149. package/lib/module/hooks/useTranslatedMessage.js +1 -1
  150. package/lib/module/hooks/useTranslatedMessage.js.map +1 -1
  151. package/lib/module/mock-builders/DB/mock.js +2 -2
  152. package/lib/module/mock-builders/DB/mock.js.map +1 -1
  153. package/lib/module/mock-builders/api/deleteMessage.js +20 -0
  154. package/lib/module/mock-builders/api/deleteMessage.js.map +1 -0
  155. package/lib/module/mock-builders/api/deleteReaction.js +21 -0
  156. package/lib/module/mock-builders/api/deleteReaction.js.map +1 -0
  157. package/lib/module/mock-builders/api/sendReaction.js +21 -0
  158. package/lib/module/mock-builders/api/sendReaction.js.map +1 -0
  159. package/lib/module/mock-builders/event/connectionChanged.js +2 -0
  160. package/lib/module/mock-builders/event/connectionChanged.js.map +1 -1
  161. package/lib/module/store/QuickSqliteClient.js +40 -51
  162. package/lib/module/store/QuickSqliteClient.js.map +1 -1
  163. package/lib/module/store/apis/addPendingTask.js +37 -0
  164. package/lib/module/store/apis/addPendingTask.js.map +1 -0
  165. package/lib/module/store/apis/deleteMessage.js +26 -0
  166. package/lib/module/store/apis/deleteMessage.js.map +1 -0
  167. package/lib/module/store/apis/deletePendingTask.js +22 -0
  168. package/lib/module/store/apis/deletePendingTask.js.map +1 -0
  169. package/lib/module/store/apis/deleteReaction.js +30 -0
  170. package/lib/module/store/apis/deleteReaction.js.map +1 -0
  171. package/lib/module/store/apis/getChannelMessages.js +3 -3
  172. package/lib/module/store/apis/getChannelMessages.js.map +1 -1
  173. package/lib/module/store/apis/getChannels.js +1 -1
  174. package/lib/module/store/apis/getChannels.js.map +1 -1
  175. package/lib/module/store/apis/getPendingTasks.js +26 -0
  176. package/lib/module/store/apis/getPendingTasks.js.map +1 -0
  177. package/lib/module/store/apis/index.js +13 -0
  178. package/lib/module/store/apis/index.js.map +1 -1
  179. package/lib/module/store/apis/insertReaction.js +28 -0
  180. package/lib/module/store/apis/insertReaction.js.map +1 -0
  181. package/lib/module/store/apis/updateMessage.js.map +1 -1
  182. package/lib/module/store/apis/updateReaction.js.map +1 -1
  183. package/lib/module/store/mappers/mapDateTimeToStorable.js.map +1 -1
  184. package/lib/module/store/mappers/mapMessageToStorable.js +3 -1
  185. package/lib/module/store/mappers/mapMessageToStorable.js.map +1 -1
  186. package/lib/module/store/mappers/mapStorableToTask.js +23 -0
  187. package/lib/module/store/mappers/mapStorableToTask.js.map +1 -0
  188. package/lib/module/store/mappers/mapTaskToStorable.js +18 -0
  189. package/lib/module/store/mappers/mapTaskToStorable.js.map +1 -0
  190. package/lib/module/store/schema.js +11 -0
  191. package/lib/module/store/schema.js.map +1 -1
  192. package/lib/module/store/sqlite-utils/appendOrderByClause.js +24 -0
  193. package/lib/module/store/sqlite-utils/appendOrderByClause.js.map +1 -0
  194. package/lib/module/store/sqlite-utils/createCreateTableQuery.js +1 -1
  195. package/lib/module/store/sqlite-utils/createCreateTableQuery.js.map +1 -1
  196. package/lib/module/store/sqlite-utils/createSelectQuery.js +8 -1
  197. package/lib/module/store/sqlite-utils/createSelectQuery.js.map +1 -1
  198. package/lib/module/store/sqlite-utils/createUpdateQuery.js +2 -2
  199. package/lib/module/store/sqlite-utils/createUpdateQuery.js.map +1 -1
  200. package/lib/module/store/sqlite-utils/createUpsertQuery.js +1 -1
  201. package/lib/module/store/sqlite-utils/createUpsertQuery.js.map +1 -1
  202. package/lib/module/utils/DBSyncManager.js +436 -0
  203. package/lib/module/utils/DBSyncManager.js.map +1 -0
  204. package/lib/module/utils/addReactionToLocalState.js +92 -0
  205. package/lib/module/utils/addReactionToLocalState.js.map +1 -0
  206. package/lib/module/utils/removeReactionFromLocalState.js +39 -0
  207. package/lib/module/utils/removeReactionFromLocalState.js.map +1 -0
  208. package/lib/{commonjs/components/Message → module}/utils/removeReservedFields.js +1 -1
  209. package/lib/module/utils/removeReservedFields.js.map +1 -0
  210. package/lib/module/utils/utils.js +9 -3
  211. package/lib/module/utils/utils.js.map +1 -1
  212. package/lib/module/version.json +1 -1
  213. package/lib/typescript/components/Channel/Channel.d.ts +1 -1
  214. package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts +1 -1
  215. package/lib/typescript/components/ChannelList/hooks/usePaginatedChannels.d.ts +2 -1
  216. package/lib/typescript/components/Chat/hooks/useCreateChatContext.d.ts +1 -1
  217. package/lib/typescript/components/Message/Message.d.ts +1 -1
  218. package/lib/typescript/components/Message/hooks/useMessageActionHandlers.d.ts +1 -1
  219. package/lib/typescript/components/Message/hooks/useMessageActions.d.ts +1 -1
  220. package/lib/typescript/components/MessageInput/FileUploadPreview.d.ts +2 -1
  221. package/lib/typescript/components/MessageInput/ImageUploadPreview.d.ts +2 -1
  222. package/lib/typescript/components/MessageInput/MessageInput.d.ts +2 -1
  223. package/lib/typescript/components/index.d.ts +1 -2
  224. package/lib/typescript/contexts/chatContext/ChatContext.d.ts +1 -2
  225. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +1 -1
  226. package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +3 -0
  227. package/lib/typescript/store/apis/addPendingTask.d.ts +2 -0
  228. package/lib/typescript/store/apis/deleteMessage.d.ts +4 -0
  229. package/lib/typescript/store/apis/deletePendingTask.d.ts +3 -0
  230. package/lib/typescript/store/apis/deleteReaction.d.ts +6 -0
  231. package/lib/typescript/store/apis/getChannelMessages.d.ts +1 -1
  232. package/lib/typescript/store/apis/getPendingTasks.d.ts +3 -0
  233. package/lib/typescript/store/apis/index.d.ts +1 -0
  234. package/lib/typescript/store/apis/insertReaction.d.ts +6 -0
  235. package/lib/typescript/store/apis/updateMessage.d.ts +2 -2
  236. package/lib/typescript/store/apis/updateReaction.d.ts +2 -2
  237. package/lib/typescript/store/mappers/mapDateTimeToStorable.d.ts +1 -1
  238. package/lib/typescript/store/mappers/mapMessageToStorable.d.ts +2 -2
  239. package/lib/typescript/store/mappers/mapStorableToTask.d.ts +2 -0
  240. package/lib/typescript/store/mappers/mapTaskToStorable.d.ts +26 -0
  241. package/lib/typescript/store/schema.d.ts +12 -1
  242. package/lib/typescript/store/sqlite-utils/appendOrderByClause.d.ts +3 -0
  243. package/lib/typescript/store/sqlite-utils/createSelectQuery.d.ts +1 -1
  244. package/lib/typescript/store/types.d.ts +21 -0
  245. package/lib/typescript/types/types.d.ts +3 -1
  246. package/lib/typescript/utils/DBSyncManager.d.ts +47 -0
  247. package/lib/typescript/utils/addReactionToLocalState.d.ts +9 -0
  248. package/lib/typescript/utils/removeReactionFromLocalState.d.ts +8 -0
  249. package/lib/typescript/{components/Message/utils → utils}/removeReservedFields.d.ts +2 -2
  250. package/lib/typescript/utils/utils.d.ts +3 -3
  251. package/package.json +4 -3
  252. package/src/__tests__/offline-feature.test.js +19 -2
  253. package/src/__tests__/optimistic-update.test.js +368 -0
  254. package/src/components/Attachment/Gallery.tsx +5 -1
  255. package/src/components/Attachment/GalleryImage.tsx +16 -2
  256. package/src/components/Channel/Channel.tsx +266 -57
  257. package/src/components/Channel/hooks/useCreateMessagesContext.ts +6 -0
  258. package/src/components/ChannelList/ChannelList.tsx +2 -10
  259. package/src/components/ChannelList/hooks/listeners/__tests__/useChannelUpdated.test.tsx +0 -1
  260. package/src/components/ChannelList/hooks/usePaginatedChannels.ts +76 -26
  261. package/src/components/Chat/Chat.tsx +5 -9
  262. package/src/components/Chat/__tests__/Chat.test.js +1 -1
  263. package/src/components/Chat/hooks/useCreateChatContext.ts +0 -2
  264. package/src/components/Message/Message.tsx +18 -2
  265. package/src/components/Message/MessageSimple/MessageFooter.tsx +2 -1
  266. package/src/components/Message/hooks/useMessageActionHandlers.ts +10 -21
  267. package/src/components/Message/hooks/useMessageActions.tsx +10 -5
  268. package/src/components/MessageInput/FileUploadPreview.tsx +7 -2
  269. package/src/components/MessageInput/ImageUploadPreview.tsx +7 -3
  270. package/src/components/MessageInput/MessageInput.tsx +17 -3
  271. package/src/components/MessageInput/SendButton.tsx +1 -1
  272. package/src/components/index.ts +1 -2
  273. package/src/contexts/chatContext/ChatContext.tsx +1 -2
  274. package/src/contexts/messageInputContext/MessageInputContext.tsx +95 -57
  275. package/src/contexts/messageInputContext/__tests__/__snapshots__/sendMessage.test.tsx.snap +29 -3
  276. package/src/contexts/messageInputContext/hooks/useMessageDetailsForState.ts +1 -0
  277. package/src/contexts/messagesContext/MessagesContext.tsx +4 -1
  278. package/src/hooks/useTranslatedMessage.ts +1 -1
  279. package/src/mock-builders/DB/mock.ts +2 -2
  280. package/src/mock-builders/api/deleteMessage.js +18 -0
  281. package/src/mock-builders/api/deleteReaction.js +19 -0
  282. package/src/mock-builders/api/sendReaction.tsx +19 -0
  283. package/src/mock-builders/event/connectionChanged.js +2 -1
  284. package/src/store/QuickSqliteClient.ts +39 -37
  285. package/src/store/apis/addPendingTask.ts +24 -0
  286. package/src/store/apis/deleteMessage.ts +13 -0
  287. package/src/store/apis/deletePendingTask.ts +12 -0
  288. package/src/store/apis/deleteReaction.ts +26 -0
  289. package/src/store/apis/getChannelMessages.ts +1 -1
  290. package/src/store/apis/getChannels.ts +2 -2
  291. package/src/store/apis/getPendingTasks.ts +13 -0
  292. package/src/store/apis/index.ts +1 -0
  293. package/src/store/apis/insertReaction.ts +29 -0
  294. package/src/store/apis/updateMessage.ts +2 -2
  295. package/src/store/apis/updateReaction.ts +2 -2
  296. package/src/store/mappers/mapDateTimeToStorable.ts +1 -1
  297. package/src/store/mappers/mapMessageToStorable.ts +8 -2
  298. package/src/store/mappers/mapStorableToTask.ts +13 -0
  299. package/src/store/mappers/mapTaskToStorable.ts +7 -0
  300. package/src/store/schema.ts +25 -1
  301. package/src/store/sqlite-utils/appendOrderByClause.ts +24 -0
  302. package/src/store/sqlite-utils/createCreateTableQuery.ts +2 -2
  303. package/src/store/sqlite-utils/createSelectQuery.ts +4 -1
  304. package/src/store/sqlite-utils/createUpdateQuery.ts +3 -2
  305. package/src/store/sqlite-utils/createUpsertQuery.ts +1 -1
  306. package/src/store/types.ts +28 -0
  307. package/src/types/types.ts +4 -1
  308. package/src/utils/DBSyncManager.ts +222 -0
  309. package/src/utils/addReactionToLocalState.ts +87 -0
  310. package/src/utils/removeReactionFromLocalState.ts +39 -0
  311. package/src/{components/Message/utils → utils}/removeReservedFields.ts +7 -3
  312. package/src/utils/utils.ts +14 -5
  313. package/src/version.json +1 -1
  314. package/lib/commonjs/components/Chat/hooks/useConnectionRecovered.js +0 -171
  315. package/lib/commonjs/components/Chat/hooks/useConnectionRecovered.js.map +0 -1
  316. package/lib/commonjs/components/Message/utils/removeReservedFields.js.map +0 -1
  317. package/lib/module/components/Chat/hooks/useConnectionRecovered.js +0 -171
  318. package/lib/module/components/Chat/hooks/useConnectionRecovered.js.map +0 -1
  319. package/lib/module/components/Message/utils/removeReservedFields.js.map +0 -1
  320. package/lib/typescript/components/Chat/hooks/useConnectionRecovered.d.ts +0 -10
  321. package/src/components/Chat/hooks/useConnectionRecovered.ts +0 -92
@@ -3,13 +3,16 @@ import { KeyboardAvoidingViewProps, StyleSheet, Text, View } from 'react-native'
3
3
 
4
4
  import debounce from 'lodash/debounce';
5
5
  import throttle from 'lodash/throttle';
6
+
7
+ import { lookup } from 'mime-types';
6
8
  import {
9
+ Channel as ChannelClass,
7
10
  ChannelState,
8
11
  Channel as ChannelType,
9
- ConnectionChangeEvent,
10
12
  EventHandler,
11
13
  logChatPromiseExecution,
12
14
  MessageResponse,
15
+ Reaction,
13
16
  SendMessageAPIResponse,
14
17
  StreamChat,
15
18
  Event as StreamEvent,
@@ -72,8 +75,12 @@ import {
72
75
  WutReaction,
73
76
  } from '../../icons';
74
77
  import { FlatList as FlatListDefault } from '../../native';
78
+ import * as dbApi from '../../store/apis';
75
79
  import type { DefaultStreamChatGenerics } from '../../types/types';
76
- import { generateRandomId, MessageStatusTypes, ReactionData } from '../../utils/utils';
80
+ import { addReactionToLocalState } from '../../utils/addReactionToLocalState';
81
+ import { DBSyncManager } from '../../utils/DBSyncManager';
82
+ import { removeReactionFromLocalState } from '../../utils/removeReactionFromLocalState';
83
+ import { generateRandomId, isLocalUrl, MessageStatusTypes, ReactionData } from '../../utils/utils';
77
84
  import { Attachment as AttachmentDefault } from '../Attachment/Attachment';
78
85
  import { AttachmentActions as AttachmentActionsDefault } from '../Attachment/AttachmentActions';
79
86
  import { AudioAttachment as AudioAttachmentDefault } from '../Attachment/AudioAttachment';
@@ -196,7 +203,7 @@ export type ChannelPropsWithContext<
196
203
  | 'StickyHeader'
197
204
  >
198
205
  > &
199
- Pick<ChatContextValue<StreamChatGenerics>, 'client'> &
206
+ Pick<ChatContextValue<StreamChatGenerics>, 'client' | 'enableOfflineSupport'> &
200
207
  Partial<
201
208
  Omit<
202
209
  InputMessageInputContextValue<StreamChatGenerics>,
@@ -422,6 +429,7 @@ const ChannelWithContext = <
422
429
  doUpdateMessageRequest,
423
430
  EmptyStateIndicator = EmptyStateIndicatorDefault,
424
431
  enableMessageGroupingByUser = true,
432
+ enableOfflineSupport,
425
433
  enforceUniqueReaction = false,
426
434
  FileAttachment = FileAttachmentDefault,
427
435
  FileAttachmentGroup = FileAttachmentGroupDefault,
@@ -726,17 +734,8 @@ const ChannelWithContext = <
726
734
  ),
727
735
  ).current;
728
736
 
729
- const connectionRecoveredHandler = () => {
730
- if (channel && shouldSyncChannel) {
731
- copyChannelState();
732
- if (thread) {
733
- setThreadMessages([...channel.state.threads[thread.id]]);
734
- }
735
- }
736
- };
737
-
738
- const connectionChangedHandler = (event: ConnectionChangeEvent) => {
739
- if (event.online && shouldSyncChannel) {
737
+ const connectionChangedHandler = () => {
738
+ if (shouldSyncChannel) {
740
739
  resyncChannel();
741
740
  }
742
741
  };
@@ -777,8 +776,7 @@ const ChannelWithContext = <
777
776
  * The more complex sync logic around internet connectivity (NetInfo) is part of Chat.tsx
778
777
  * listen to client.connection.recovered and all channel events
779
778
  */
780
- clientSubscriptions.push(client.on('connection.recovered', connectionRecoveredHandler));
781
- clientSubscriptions.push(client.on('connection.changed', connectionChangedHandler));
779
+ clientSubscriptions.push(DBSyncManager.onSyncStatusChange(connectionChangedHandler));
782
780
  clientSubscriptions.push(
783
781
  client.on('channel.deleted', (event) => {
784
782
  if (event.cid === channel.cid) {
@@ -795,7 +793,7 @@ const ChannelWithContext = <
795
793
  clientSubscriptions.forEach((s) => s.unsubscribe());
796
794
  channelSubscriptions.forEach((s) => s.unsubscribe());
797
795
  };
798
- }, [channelId, connectionChangedHandler, connectionRecoveredHandler, handleEvent]);
796
+ }, [channelId, connectionChangedHandler, handleEvent]);
799
797
 
800
798
  const channelQueryCallRef = useRef(
801
799
  async (
@@ -906,7 +904,6 @@ const ChannelWithContext = <
906
904
 
907
905
  const reloadThread = async () => {
908
906
  if (!channel || !thread?.id) return;
909
-
910
907
  setThreadLoadingMore(true);
911
908
  try {
912
909
  const parentID = thread.id;
@@ -1231,56 +1228,126 @@ const ChannelWithContext = <
1231
1228
  return preview;
1232
1229
  };
1233
1230
 
1231
+ const uploadPendingAttachments = async (message: MessageResponse<StreamChatGenerics>) => {
1232
+ const updatedMessage = { ...message };
1233
+ if (updatedMessage.attachments?.length) {
1234
+ for (let i = 0; i < updatedMessage.attachments?.length; i++) {
1235
+ const attachment = updatedMessage.attachments[i];
1236
+ const file = attachment.originalFile;
1237
+ // check if image_url is not a remote url
1238
+ if (
1239
+ attachment.type === 'image' &&
1240
+ file?.uri &&
1241
+ attachment.image_url &&
1242
+ isLocalUrl(attachment.image_url)
1243
+ ) {
1244
+ const filename = file.uri.replace(/^(file:\/\/|content:\/\/|assets-library:\/\/)/, '');
1245
+ const contentType = lookup(filename) || 'multipart/form-data';
1246
+
1247
+ const uploadResponse = doImageUploadRequest
1248
+ ? await doImageUploadRequest(file, channel)
1249
+ : await channel.sendImage(file?.uri, filename, contentType);
1250
+
1251
+ attachment.image_url = uploadResponse.file;
1252
+ delete attachment.originalFile;
1253
+
1254
+ dbApi.updateMessage({
1255
+ message: { ...updatedMessage, cid: channel.cid },
1256
+ });
1257
+ }
1258
+
1259
+ if (
1260
+ (attachment.type === 'file' ||
1261
+ attachment.type === 'audio' ||
1262
+ attachment.type === 'video') &&
1263
+ attachment.asset_url &&
1264
+ isLocalUrl(attachment.asset_url) &&
1265
+ file?.uri
1266
+ ) {
1267
+ const response = doDocUploadRequest
1268
+ ? await doDocUploadRequest(file, channel)
1269
+ : await channel.sendFile(file.uri, file.name, file.type);
1270
+ attachment.asset_url = response.file;
1271
+ if (response.thumb_url) {
1272
+ attachment.thumb_url = response.thumb_url;
1273
+ }
1274
+ delete attachment.originalFile;
1275
+ dbApi.updateMessage({
1276
+ message: { ...updatedMessage, cid: channel.cid },
1277
+ });
1278
+ }
1279
+ }
1280
+ }
1281
+
1282
+ return updatedMessage;
1283
+ };
1284
+
1234
1285
  const sendMessageRequest = async (
1235
1286
  message: MessageResponse<StreamChatGenerics>,
1236
1287
  retrying?: boolean,
1237
1288
  ) => {
1238
- const {
1239
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1240
- __html,
1241
- attachments,
1242
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1243
- created_at,
1244
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1245
- html,
1246
- id,
1247
- mentioned_users,
1248
- parent_id,
1249
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1250
- quoted_message,
1251
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1252
- reactions,
1253
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1254
- status,
1255
- text,
1256
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1257
- type,
1258
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1259
- updated_at,
1260
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1261
- user,
1262
- ...extraFields
1263
- } = message;
1264
-
1265
- const messageData = {
1266
- attachments,
1267
- id: retrying ? undefined : id,
1268
- mentioned_users: mentioned_users?.map((mentionedUser) => mentionedUser.id) || [],
1269
- parent_id,
1270
- text,
1271
- ...extraFields,
1272
- } as StreamMessage<StreamChatGenerics>;
1273
-
1274
1289
  try {
1275
- let messageResponse = {} as SendMessageAPIResponse<StreamChatGenerics>;
1290
+ const updatedMessage = await uploadPendingAttachments(message);
1291
+ const {
1292
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1293
+ __html,
1294
+ attachments,
1295
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1296
+ created_at,
1297
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1298
+ deleted_at,
1299
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1300
+ html,
1301
+ id,
1302
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1303
+ latest_reactions,
1304
+ mentioned_users,
1305
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1306
+ own_reactions,
1307
+ parent_id,
1308
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1309
+ quoted_message,
1310
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1311
+ reaction_counts,
1312
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1313
+ reactions,
1314
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1315
+ status,
1316
+ text,
1317
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1318
+ type,
1319
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1320
+ updated_at,
1321
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1322
+ user,
1323
+ ...extraFields
1324
+ } = updatedMessage;
1325
+ if (!channel.id) return;
1326
+
1327
+ const messageData = {
1328
+ attachments,
1329
+ id,
1330
+ mentioned_users: mentioned_users?.map((mentionedUser) => mentionedUser.id) || [],
1331
+ parent_id,
1332
+ text,
1333
+ ...extraFields,
1334
+ } as StreamMessage<StreamChatGenerics>;
1276
1335
 
1336
+ let messageResponse = {} as SendMessageAPIResponse<StreamChatGenerics>;
1277
1337
  if (doSendMessageRequest) {
1278
1338
  messageResponse = await doSendMessageRequest(channel?.cid || '', messageData);
1279
1339
  } else if (channel) {
1280
1340
  messageResponse = await channel.sendMessage(messageData);
1281
1341
  }
1342
+
1282
1343
  if (messageResponse.message) {
1283
1344
  messageResponse.message.status = MessageStatusTypes.RECEIVED;
1345
+
1346
+ if (enableOfflineSupport) {
1347
+ dbApi.updateMessage({
1348
+ message: { ...messageResponse.message, cid: channel.cid },
1349
+ });
1350
+ }
1284
1351
  if (retrying) {
1285
1352
  replaceMessage(message, messageResponse.message);
1286
1353
  } else {
@@ -1290,7 +1357,13 @@ const ChannelWithContext = <
1290
1357
  } catch (err) {
1291
1358
  console.log(err);
1292
1359
  message.status = MessageStatusTypes.FAILED;
1293
- updateMessage(message);
1360
+ updateMessage({ ...message, cid: channel.cid });
1361
+
1362
+ if (enableOfflineSupport) {
1363
+ dbApi.updateMessage({
1364
+ message: { ...message, cid: channel.cid },
1365
+ });
1366
+ }
1294
1367
  }
1295
1368
  };
1296
1369
 
@@ -1315,6 +1388,16 @@ const ChannelWithContext = <
1315
1388
  messageInput: '',
1316
1389
  });
1317
1390
 
1391
+ if (enableOfflineSupport) {
1392
+ // While sending a message, we add the message to local db with failed status, so that
1393
+ // if app gets closed before message gets sent and next time user opens the app
1394
+ // then user can see that message in failed state and can retry.
1395
+ // If succesfull, it will be updated with received status.
1396
+ dbApi.upsertMessages({
1397
+ messages: [{ ...messagePreview, cid: channel.cid, status: MessageStatusTypes.FAILED }],
1398
+ });
1399
+ }
1400
+
1318
1401
  await sendMessageRequest(messagePreview);
1319
1402
  };
1320
1403
 
@@ -1327,6 +1410,7 @@ const ChannelWithContext = <
1327
1410
  };
1328
1411
 
1329
1412
  updateMessage(statusPendingMessage);
1413
+
1330
1414
  await sendMessageRequest(statusPendingMessage, true);
1331
1415
  };
1332
1416
 
@@ -1469,6 +1553,127 @@ const ChannelWithContext = <
1469
1553
  setThreadMessages(channel.state.threads[thread.id] || []);
1470
1554
  }
1471
1555
  }
1556
+
1557
+ if (enableOfflineSupport) {
1558
+ dbApi.deleteMessage({
1559
+ id: message.id,
1560
+ });
1561
+ }
1562
+ };
1563
+
1564
+ const sendReaction = async (type: string, messageId: string) => {
1565
+ if (!channel?.id || !client.user) {
1566
+ throw new Error('Channel has not been initialized');
1567
+ }
1568
+
1569
+ const payload: Parameters<ChannelClass<StreamChatGenerics>['sendReaction']> = [
1570
+ messageId,
1571
+ {
1572
+ type,
1573
+ } as Reaction<StreamChatGenerics>,
1574
+ { enforce_unique: enforceUniqueReaction },
1575
+ ];
1576
+
1577
+ if (!enableOfflineSupport) {
1578
+ await channel.sendReaction(...payload);
1579
+ return;
1580
+ }
1581
+
1582
+ addReactionToLocalState<StreamChatGenerics>({
1583
+ channel,
1584
+ enforceUniqueReaction,
1585
+ messageId,
1586
+ reactionType: type,
1587
+ user: client.user,
1588
+ });
1589
+
1590
+ setMessages(channel.state.messages);
1591
+
1592
+ await DBSyncManager.queueTask<StreamChatGenerics>({
1593
+ client,
1594
+ task: {
1595
+ channelId: channel.id,
1596
+ channelType: channel.type,
1597
+ messageId,
1598
+ payload,
1599
+ type: 'send-reaction',
1600
+ },
1601
+ });
1602
+ };
1603
+ const deleteMessage: MessagesContextValue<StreamChatGenerics>['deleteMessage'] = async (
1604
+ message,
1605
+ ) => {
1606
+ if (!channel.id) {
1607
+ throw new Error('Channel has not been initialized yet');
1608
+ }
1609
+
1610
+ if (!enableOfflineSupport) {
1611
+ await client.deleteMessage(message.id);
1612
+ return;
1613
+ }
1614
+
1615
+ if (message.status === MessageStatusTypes.FAILED) {
1616
+ DBSyncManager.dropPendingTasks({ messageId: message.id });
1617
+ removeMessage(message);
1618
+ } else {
1619
+ updateMessage({
1620
+ ...message,
1621
+ cid: channel.cid,
1622
+ deleted_at: new Date().toISOString(),
1623
+ type: 'deleted',
1624
+ });
1625
+
1626
+ const data = await DBSyncManager.queueTask<StreamChatGenerics>({
1627
+ client,
1628
+ task: {
1629
+ channelId: channel.id,
1630
+ channelType: channel.type,
1631
+ messageId: message.id,
1632
+ payload: [message.id],
1633
+ type: 'delete-message',
1634
+ },
1635
+ });
1636
+
1637
+ if (data?.message) {
1638
+ updateMessage({ ...data.message });
1639
+ }
1640
+ }
1641
+ };
1642
+
1643
+ const deleteReaction: MessagesContextValue<StreamChatGenerics>['deleteReaction'] = async (
1644
+ type: string,
1645
+ messageId: string,
1646
+ ) => {
1647
+ if (!channel?.id || !client.user) {
1648
+ throw new Error('Channel has not been initialized');
1649
+ }
1650
+
1651
+ const payload: Parameters<ChannelClass['deleteReaction']> = [messageId, type];
1652
+
1653
+ if (!enableOfflineSupport) {
1654
+ await channel.deleteReaction(...payload);
1655
+ return;
1656
+ }
1657
+
1658
+ removeReactionFromLocalState({
1659
+ channel,
1660
+ messageId,
1661
+ reactionType: type,
1662
+ user: client.user,
1663
+ });
1664
+
1665
+ setMessages(channel.state.messages);
1666
+
1667
+ await DBSyncManager.queueTask<StreamChatGenerics>({
1668
+ client,
1669
+ task: {
1670
+ channelId: channel.id,
1671
+ channelType: channel.type,
1672
+ messageId,
1673
+ payload,
1674
+ type: 'delete-reaction',
1675
+ },
1676
+ });
1472
1677
  };
1473
1678
 
1474
1679
  /**
@@ -1654,6 +1859,8 @@ const ChannelWithContext = <
1654
1859
  channelId,
1655
1860
  DateHeader,
1656
1861
  deletedMessagesVisibilityType,
1862
+ deleteMessage,
1863
+ deleteReaction,
1657
1864
  disableTypingIndicator,
1658
1865
  dismissKeyboardOnMessageTouch,
1659
1866
  enableMessageGroupingByUser,
@@ -1713,6 +1920,7 @@ const ChannelWithContext = <
1713
1920
  retrySendMessage,
1714
1921
  ScrollToBottomButton,
1715
1922
  selectReaction,
1923
+ sendReaction,
1716
1924
  setEditingState,
1717
1925
  setQuotedMessageState,
1718
1926
  supportedReactions,
@@ -1808,7 +2016,7 @@ export const Channel = <
1808
2016
  >(
1809
2017
  props: PropsWithChildren<ChannelProps<StreamChatGenerics>>,
1810
2018
  ) => {
1811
- const { client } = useChatContext<StreamChatGenerics>();
2019
+ const { client, enableOfflineSupport } = useChatContext<StreamChatGenerics>();
1812
2020
  const { t } = useTranslationContext();
1813
2021
 
1814
2022
  const shouldSyncChannel = props.thread?.id ? !!props.threadList : true;
@@ -1837,6 +2045,7 @@ export const Channel = <
1837
2045
  <ChannelWithContext<StreamChatGenerics>
1838
2046
  {...{
1839
2047
  client,
2048
+ enableOfflineSupport,
1840
2049
  t,
1841
2050
  }}
1842
2051
  {...props}
@@ -17,6 +17,8 @@ export const useCreateMessagesContext = <
17
17
  channelId,
18
18
  DateHeader,
19
19
  deletedMessagesVisibilityType,
20
+ deleteMessage,
21
+ deleteReaction,
20
22
  disableTypingIndicator,
21
23
  dismissKeyboardOnMessageTouch,
22
24
  enableMessageGroupingByUser,
@@ -76,6 +78,7 @@ export const useCreateMessagesContext = <
76
78
  retrySendMessage,
77
79
  ScrollToBottomButton,
78
80
  selectReaction,
81
+ sendReaction,
79
82
  setEditingState,
80
83
  setQuotedMessageState,
81
84
  supportedReactions,
@@ -108,6 +111,8 @@ export const useCreateMessagesContext = <
108
111
  CardHeader,
109
112
  DateHeader,
110
113
  deletedMessagesVisibilityType,
114
+ deleteMessage,
115
+ deleteReaction,
111
116
  disableTypingIndicator,
112
117
  dismissKeyboardOnMessageTouch,
113
118
  enableMessageGroupingByUser,
@@ -167,6 +172,7 @@ export const useCreateMessagesContext = <
167
172
  retrySendMessage,
168
173
  ScrollToBottomButton,
169
174
  selectReaction,
175
+ sendReaction,
170
176
  setEditingState,
171
177
  setQuotedMessageState,
172
178
  supportedReactions,
@@ -242,7 +242,7 @@ export const ChannelList = <
242
242
  } = props;
243
243
 
244
244
  const [forceUpdate, setForceUpdate] = useState(0);
245
- const { enableOfflineSupport, subscribeConnectionRecoveredCallback } = useChatContext();
245
+ const { enableOfflineSupport } = useChatContext<StreamChatGenerics>();
246
246
  const {
247
247
  channels,
248
248
  error,
@@ -259,6 +259,7 @@ export const ChannelList = <
259
259
  enableOfflineSupport,
260
260
  filters,
261
261
  options,
262
+ setForceUpdate,
262
263
  sort,
263
264
  });
264
265
 
@@ -328,15 +329,6 @@ export const ChannelList = <
328
329
  });
329
330
  }, [channelIdsStr, staticChannelsActive]);
330
331
 
331
- useEffect(() => {
332
- const unsubscribe = subscribeConnectionRecoveredCallback(() => {
333
- refreshList();
334
- setForceUpdate((count) => count + 1);
335
- });
336
-
337
- return () => unsubscribe();
338
- });
339
-
340
332
  const channelsContext = useCreateChannelsContext({
341
333
  additionalFlatListProps,
342
334
  channels,
@@ -64,7 +64,6 @@ describe('useChannelUpdated', () => {
64
64
  isOnline: true,
65
65
  mutedUsers: [],
66
66
  setActiveChannel: () => null,
67
- subscribeConnectionRecoveredCallback: () => () => null,
68
67
  }}
69
68
  >
70
69
  <TestComponent />
@@ -3,12 +3,14 @@ import { useEffect, useMemo, useRef, useState } from 'react';
3
3
  import type { Channel, ChannelFilters, ChannelOptions, ChannelSort } from 'stream-chat';
4
4
 
5
5
  import { useActiveChannelsRefContext } from '../../../contexts/activeChannelsRefContext/ActiveChannelsRefContext';
6
+
6
7
  import { useChatContext } from '../../../contexts/chatContext/ChatContext';
7
8
  import { useIsMountedRef } from '../../../hooks/useIsMountedRef';
8
9
 
9
10
  import { getChannelsForFilterSort } from '../../../store/apis/getChannelsForFilterSort';
10
11
  import type { DefaultStreamChatGenerics } from '../../../types/types';
11
12
  import { ONE_SECOND_IN_MS } from '../../../utils/date';
13
+ import { DBSyncManager } from '../../../utils/DBSyncManager';
12
14
  import { MAX_QUERY_CHANNELS_LIMIT } from '../utils';
13
15
 
14
16
  const waitSeconds = (seconds: number) =>
@@ -21,6 +23,7 @@ type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultSt
21
23
  enableOfflineSupport: boolean;
22
24
  filters: ChannelFilters<StreamChatGenerics>;
23
25
  options: ChannelOptions;
26
+ setForceUpdate: React.Dispatch<React.SetStateAction<number>>;
24
27
  sort: ChannelSort<StreamChatGenerics>;
25
28
  };
26
29
 
@@ -41,13 +44,13 @@ export const usePaginatedChannels = <
41
44
  enableOfflineSupport,
42
45
  filters = {},
43
46
  options = DEFAULT_OPTIONS,
47
+ setForceUpdate,
44
48
  sort = {},
45
49
  }: Parameters<StreamChatGenerics>) => {
46
50
  const { client } = useChatContext<StreamChatGenerics>();
47
51
  const [channels, setChannels] = useState<Channel<StreamChatGenerics>[] | null>(null);
48
52
  const [staticChannelsActive, setStaticChannelsActive] = useState<boolean>(false);
49
53
  const activeChannels = useActiveChannelsRefContext();
50
-
51
54
  const [error, setError] = useState<Error>();
52
55
  const [hasNextPage, setHasNextPage] = useState(true);
53
56
  const lastRefresh = useRef(Date.now());
@@ -98,17 +101,33 @@ export const usePaginatedChannels = <
98
101
  };
99
102
 
100
103
  try {
104
+ const activeChannelIds: string[] = [];
105
+ for (const cid in client.activeChannels) {
106
+ if (client.activeChannels[cid].id) {
107
+ // @ts-ignore
108
+ activeChannelIds.push(client.activeChannels[cid].id);
109
+ }
110
+ }
111
+
112
+ // TODO: Think about the implications of this.
101
113
  const channelQueryResponse = await client.queryChannels(filters, sort, newOptions, {
102
- skipInitialization: activeChannels.current,
114
+ skipInitialization: enableOfflineSupport ? activeChannelIds : activeChannels.current,
103
115
  });
104
-
105
116
  if (isQueryStale() || !isMountedRef.current) {
106
117
  return;
107
118
  }
119
+
108
120
  const newChannels =
109
121
  queryType === 'loadChannels' && !staticChannelsActive && channels
110
122
  ? [...channels, ...channelQueryResponse]
111
- : channelQueryResponse;
123
+ : channelQueryResponse.map((c) => {
124
+ const existingChannel = client.activeChannels[c.cid];
125
+ if (existingChannel) {
126
+ return existingChannel;
127
+ }
128
+
129
+ return c;
130
+ });
112
131
 
113
132
  setChannels(newChannels);
114
133
  setStaticChannelsActive(false);
@@ -177,33 +196,62 @@ export const usePaginatedChannels = <
177
196
  const sortStr = useMemo(() => JSON.stringify(sort), [sort]);
178
197
 
179
198
  useEffect(() => {
180
- const loadChannels = () => {
199
+ const loadOfflineChannels = () => {
181
200
  if (!client?.user?.id) return;
182
- if (enableOfflineSupport) {
183
- try {
184
- const channelsFromDB = getChannelsForFilterSort({
185
- currentUserId: client.user.id,
186
- filters,
187
- sort,
188
- });
189
-
190
- if (channelsFromDB) {
191
- setChannels(
192
- client.hydrateActiveChannels(channelsFromDB, {
193
- offlineMode: true,
194
- }),
195
- );
196
- setStaticChannelsActive(true);
197
- }
198
- } catch (e) {
199
- console.warn('Failed to get channels from database: ', e);
201
+
202
+ try {
203
+ const channelsFromDB = getChannelsForFilterSort({
204
+ currentUserId: client.user.id,
205
+ filters,
206
+ sort,
207
+ });
208
+
209
+ if (channelsFromDB) {
210
+ setChannels(
211
+ client.hydrateActiveChannels(channelsFromDB, {
212
+ offlineMode: true,
213
+ }),
214
+ );
215
+ setStaticChannelsActive(true);
200
216
  }
217
+ } catch (e) {
218
+ console.warn('Failed to get channels from database: ', e);
201
219
  }
202
220
 
203
- reloadList();
221
+ setActiveQueryType(null);
204
222
  };
205
223
 
206
- loadChannels();
224
+ let listener: ReturnType<typeof DBSyncManager.onSyncStatusChange>;
225
+ if (enableOfflineSupport) {
226
+ // Any time DB is synced, we need to update the UI with local DB channels first,
227
+ // and then call queryChannels to ensure any new channels are added to UI.
228
+ listener = DBSyncManager.onSyncStatusChange((syncStatus) => {
229
+ if (syncStatus) {
230
+ loadOfflineChannels();
231
+ reloadList();
232
+ }
233
+ });
234
+ // On start, load the channels from local db.
235
+ loadOfflineChannels();
236
+
237
+ // If db is already synced (sync api and pending api calls), then
238
+ // right away call queryChannels.
239
+ const dbSyncStatus = DBSyncManager.getSyncStatus();
240
+ if (dbSyncStatus) {
241
+ reloadList();
242
+ }
243
+ } else {
244
+ listener = client.on('connection.changed', async (event) => {
245
+ if (event.online) {
246
+ await refreshList();
247
+ setForceUpdate((u) => u + 1);
248
+ }
249
+ });
250
+
251
+ reloadList();
252
+ }
253
+
254
+ return () => listener?.unsubscribe?.();
207
255
  }, [filterStr, sortStr]);
208
256
 
209
257
  return {
@@ -211,7 +259,9 @@ export const usePaginatedChannels = <
211
259
  error,
212
260
  hasNextPage,
213
261
  loadingChannels:
214
- activeQueryType === 'queryLocalDB' ? true : activeQueryType === 'reload' && channels === null,
262
+ activeQueryType === 'queryLocalDB'
263
+ ? true
264
+ : (activeQueryType === 'reload' || activeQueryType === null) && channels === null,
215
265
  loadingNextPage: activeQueryType === 'loadChannels',
216
266
  loadNextPage,
217
267
  refreshing: activeQueryType === 'refresh',