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
@@ -8,7 +8,7 @@ import type { DefaultStreamChatGenerics } from '../../types/types';
8
8
  import { mapStorableToMessage } from '../mappers/mapStorableToMessage';
9
9
  import type { TableRowJoinedUser } from '../types';
10
10
 
11
- export const getMessages = <
11
+ export const getChannelMessages = <
12
12
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
13
13
  >({
14
14
  channelIds,
@@ -1,6 +1,6 @@
1
1
  import type { ChannelAPIResponse } from 'stream-chat';
2
2
 
3
- import { getMessages } from './getChannelMessages';
3
+ import { getChannelMessages } from './getChannelMessages';
4
4
  import { getMembers } from './getMembers';
5
5
  import { getReads } from './getReads';
6
6
  import { selectChannels } from './queries/selectChannels';
@@ -30,7 +30,7 @@ export const getChannels = <
30
30
 
31
31
  const cidVsMembers = getMembers<StreamChatGenerics>({ channelIds });
32
32
  const cidVsReads = getReads<StreamChatGenerics>({ channelIds });
33
- const cidVsMessages = getMessages<StreamChatGenerics>({
33
+ const cidVsMessages = getChannelMessages<StreamChatGenerics>({
34
34
  channelIds,
35
35
  currentUserId,
36
36
  });
@@ -0,0 +1,13 @@
1
+ import { mapStorableToTask } from '../mappers/mapStorableToTask';
2
+ import { QuickSqliteClient } from '../QuickSqliteClient';
3
+ import { createSelectQuery } from '../sqlite-utils/createSelectQuery';
4
+
5
+ export const getPendingTasks = (conditions: { messageId?: string } = {}) => {
6
+ const query = createSelectQuery('pendingTasks', ['*'], conditions, {
7
+ createdAt: 1,
8
+ });
9
+
10
+ const result = QuickSqliteClient.executeSql.apply(null, query);
11
+
12
+ return result.map((r) => mapStorableToTask(r));
13
+ };
@@ -1,5 +1,6 @@
1
1
  export * from './deleteChannel';
2
2
  export * from './deleteMember';
3
+ export * from './deleteMessage';
3
4
  export * from './deleteMessagesForChannel';
4
5
  export * from './deleteReactions';
5
6
  export * from './getAllChannelIds';
@@ -0,0 +1,29 @@
1
+ import type { ReactionResponse } from 'stream-chat';
2
+
3
+ import { mapReactionToStorable } from '../mappers/mapReactionToStorable';
4
+ import { QuickSqliteClient } from '../QuickSqliteClient';
5
+ import { createUpsertQuery } from '../sqlite-utils/createUpsertQuery';
6
+ import type { PreparedQueries } from '../types';
7
+
8
+ export const insertReaction = ({
9
+ flush = true,
10
+ reaction,
11
+ }: {
12
+ reaction: ReactionResponse;
13
+ flush?: boolean;
14
+ }) => {
15
+ const queries: PreparedQueries[] = [];
16
+
17
+ queries.push(createUpsertQuery('reactions', mapReactionToStorable(reaction)));
18
+
19
+ queries.push([
20
+ 'UPDATE messages SET reactionCounts = reactionCounts + 1 WHERE id = ?',
21
+ [reaction.message_id],
22
+ ]);
23
+
24
+ if (flush) {
25
+ QuickSqliteClient.executeSqlBatch(queries);
26
+ }
27
+
28
+ return queries;
29
+ };
@@ -1,4 +1,4 @@
1
- import type { MessageResponse } from 'stream-chat';
1
+ import type { FormatMessageResponse, MessageResponse } from 'stream-chat';
2
2
 
3
3
  import { mapMessageToStorable } from '../mappers/mapMessageToStorable';
4
4
  import { mapReactionToStorable } from '../mappers/mapReactionToStorable';
@@ -14,7 +14,7 @@ export const updateMessage = ({
14
14
  flush = true,
15
15
  message,
16
16
  }: {
17
- message: MessageResponse;
17
+ message: MessageResponse | FormatMessageResponse;
18
18
  flush?: boolean;
19
19
  }) => {
20
20
  const queries: PreparedQueries[] = [];
@@ -1,4 +1,4 @@
1
- import type { MessageResponse, ReactionResponse } from 'stream-chat';
1
+ import type { FormatMessageResponse, MessageResponse, ReactionResponse } from 'stream-chat';
2
2
 
3
3
  import { mapMessageToStorable } from '../mappers/mapMessageToStorable';
4
4
  import { mapReactionToStorable } from '../mappers/mapReactionToStorable';
@@ -13,7 +13,7 @@ export const updateReaction = ({
13
13
  message,
14
14
  reaction,
15
15
  }: {
16
- message: MessageResponse;
16
+ message: MessageResponse | FormatMessageResponse;
17
17
  reaction: ReactionResponse;
18
18
  flush?: boolean;
19
19
  }) => {
@@ -1,4 +1,4 @@
1
- export const mapDateTimeToStorable = (datetime?: string) => {
1
+ export const mapDateTimeToStorable = (datetime?: string | Date) => {
2
2
  if (!datetime) return '';
3
3
 
4
4
  return new Date(datetime).toISOString();
@@ -1,16 +1,22 @@
1
- import type { MessageResponse } from 'stream-chat';
1
+ import type { FormatMessageResponse, MessageResponse } from 'stream-chat';
2
2
 
3
3
  import { mapDateTimeToStorable } from './mapDateTimeToStorable';
4
4
 
5
5
  import type { TableRow } from '../types';
6
6
 
7
- export const mapMessageToStorable = (message: MessageResponse): TableRow<'messages'> => {
7
+ export const mapMessageToStorable = (
8
+ message: MessageResponse | FormatMessageResponse,
9
+ ): TableRow<'messages'> => {
8
10
  const {
9
11
  attachments,
10
12
  cid,
11
13
  created_at,
12
14
  deleted_at,
13
15
  id,
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
17
+ latest_reactions,
18
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
19
+ own_reactions,
14
20
  reaction_counts,
15
21
  text,
16
22
  type,
@@ -0,0 +1,13 @@
1
+ import type { PendingTask, TableRowJoinedUser } from '../types';
2
+
3
+ export const mapStorableToTask = (row: TableRowJoinedUser<'pendingTasks'>): PendingTask => {
4
+ const { channelId, channelType, id, messageId, type } = row;
5
+ return {
6
+ channelId,
7
+ channelType,
8
+ id,
9
+ messageId,
10
+ payload: JSON.parse(row.payload),
11
+ type,
12
+ };
13
+ };
@@ -0,0 +1,7 @@
1
+ import type { PendingTask } from '../types';
2
+
3
+ export const mapTaskToStorable = (task: PendingTask) => ({
4
+ ...task,
5
+ createdAt: new Date().toISOString(),
6
+ payload: JSON.stringify(task.payload),
7
+ });
@@ -1,11 +1,14 @@
1
1
  import type { MessageLabel, Role } from 'stream-chat';
2
2
 
3
+ import type { PendingTaskTypes } from './types';
4
+
5
+ import type { ValueOf } from '../types/types';
6
+
3
7
  type Tables = {
4
8
  [P in keyof Schema]: {
5
9
  columns: {
6
10
  [K in keyof Schema[P]]: string;
7
11
  };
8
- primaryKey: Array<keyof Schema[P]>;
9
12
  foreignKeys?: Array<{
10
13
  column: `${Exclude<keyof Schema[P], symbol>}`;
11
14
  referenceTable: `${keyof Schema}`;
@@ -18,6 +21,7 @@ type Tables = {
18
21
  name: string;
19
22
  unique: boolean;
20
23
  }>;
24
+ primaryKey?: Array<keyof Schema[P]>;
21
25
  };
22
26
  };
23
27
 
@@ -121,6 +125,17 @@ export const tables: Tables = {
121
125
  ],
122
126
  primaryKey: ['id'],
123
127
  },
128
+ pendingTasks: {
129
+ columns: {
130
+ channelId: 'TEXT',
131
+ channelType: 'TEXT',
132
+ createdAt: 'TEXT',
133
+ id: 'INTEGER PRIMARY KEY AUTOINCREMENT',
134
+ messageId: 'TEXT',
135
+ payload: 'TEXT',
136
+ type: 'TEXT',
137
+ },
138
+ },
124
139
  reactions: {
125
140
  columns: {
126
141
  createdAt: 'TEXT',
@@ -252,6 +267,15 @@ export type Schema = {
252
267
  text?: string;
253
268
  userId?: string;
254
269
  };
270
+ pendingTasks: {
271
+ channelId: string;
272
+ channelType: string;
273
+ createdAt: string;
274
+ id: number;
275
+ messageId: string;
276
+ payload: string;
277
+ type: ValueOf<PendingTaskTypes>;
278
+ };
255
279
  reactions: {
256
280
  createdAt: string;
257
281
  messageId: string;
@@ -0,0 +1,24 @@
1
+ import type { Schema } from '../schema';
2
+ import type { PreparedQueries, TableColumnNames } from '../types';
3
+
4
+ export const appendOrderByClause = <T extends keyof Schema>(
5
+ selectQuery: string,
6
+ orderBy?: Partial<{ [k in TableColumnNames<T>]: 1 | -1 }>,
7
+ ): PreparedQueries => {
8
+ if (!orderBy) return [selectQuery, []];
9
+
10
+ const orderByClause = [];
11
+
12
+ for (const key in orderBy) {
13
+ const order = orderBy[key];
14
+ if (order === undefined) continue;
15
+
16
+ orderByClause.push(`${key} ${order === 1 ? 'ASC' : 'DESC'}`);
17
+ }
18
+
19
+ if (!orderByClause.length) {
20
+ return [selectQuery, []];
21
+ }
22
+
23
+ return [`${selectQuery} ORDER BY ${orderByClause.join(', ')}`];
24
+ };
@@ -8,8 +8,8 @@ export const createCreateTableQuery = (tableName: Table): PreparedQueries[] => {
8
8
  });
9
9
 
10
10
  const primaryKeyConstraints =
11
- tables[tableName].primaryKey.length > 0
12
- ? [`PRIMARY KEY (${tables[tableName].primaryKey.join(', ')})`]
11
+ (tables[tableName].primaryKey || []).length > 0
12
+ ? [`PRIMARY KEY (${(tables[tableName].primaryKey || []).join(', ')})`]
13
13
  : [];
14
14
  const foreignKeysConstraints =
15
15
  tables[tableName].foreignKeys?.map(
@@ -1,3 +1,4 @@
1
+ import { appendOrderByClause } from './appendOrderByClause';
1
2
  import { appendWhereClause } from './appendWhereCluase';
2
3
 
3
4
  import type { Schema } from '../schema';
@@ -17,9 +18,11 @@ export const createSelectQuery = <T extends keyof Schema>(
17
18
  table: T,
18
19
  fields: Array<'*'> | Array<TableColumnNames<T>> = ['*'],
19
20
  whereCondition?: Partial<{ [k in TableColumnNames<T>]: TableColumnValue | TableColumnValue[] }>,
21
+ orderBy?: Partial<{ [k in TableColumnNames<T>]: 1 | -1 }>,
20
22
  ): PreparedQueries => {
21
23
  const selectQuery = `SELECT ${fields.join(', ')} FROM ${table}`;
22
24
  const [selectQueryWithWhere, whereParams] = appendWhereClause(selectQuery, whereCondition);
25
+ const [selectQueryWithOrderBy] = appendOrderByClause(selectQueryWithWhere, orderBy);
23
26
 
24
- return [`${selectQueryWithWhere}`, whereParams || []];
27
+ return [`${selectQueryWithOrderBy}`, whereParams || []];
25
28
  };
@@ -19,9 +19,10 @@ export const createUpdateQuery = <T extends keyof Schema>(
19
19
  whereCondition: Partial<{ [k in TableColumnNames<T>]: TableColumnValue | TableColumnValue[] }>,
20
20
  ): PreparedQueries => {
21
21
  const fields = Object.keys(set).map((key) => `${key} = ?`);
22
- const updateQuery = `UPDATE ${table} SET ${fields.join(',')}`;
22
+
23
+ const updateQuery = `UPDATE OR IGNORE ${table} SET ${fields.join(',')}`;
23
24
 
24
25
  const [updateQueryWithWhere, whereParams] = appendWhereClause(updateQuery, whereCondition);
25
26
 
26
- return [updateQueryWithWhere, [...Object.values(set), ...(whereParams || [])]];
27
+ return [`${updateQueryWithWhere}`, [...Object.values(set), ...(whereParams || [])]];
27
28
  };
@@ -30,7 +30,7 @@ export const createUpsertQuery = <T extends keyof Schema>(
30
30
  const fields = Object.keys(filteredRow) as (keyof typeof row)[];
31
31
 
32
32
  const questionMarks = Array(Object.keys(fields).length).fill('?').join(',');
33
- const conflictKeys = conflictCheckKeys || tables[table].primaryKey;
33
+ const conflictKeys = conflictCheckKeys || tables[table].primaryKey || [];
34
34
  const conflictMatchersWithoutPK: string[] = (fields as string[])
35
35
  .filter((f) => !(conflictKeys as string[]).includes(f))
36
36
  .map((f) => `${f}=excluded.${f}`);
@@ -1,3 +1,5 @@
1
+ import type { Channel, StreamChat } from 'stream-chat';
2
+
1
3
  import type { Schema } from './schema';
2
4
 
3
5
  export type Table = keyof Schema;
@@ -10,3 +12,29 @@ export type TableColumnNames<T extends Table> = keyof Schema[T];
10
12
  export type TableColumnValue = string | boolean | number | undefined;
11
13
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
14
  export type PreparedQueries = [string] | [string, Array<any>];
15
+
16
+ export type PendingTaskTypes = {
17
+ deleteMessage: 'delete-message';
18
+ deleteReaction: 'delete-reaction';
19
+ sendReaction: 'send-reaction';
20
+ };
21
+
22
+ export type PendingTask = {
23
+ channelId: string;
24
+ channelType: string;
25
+ messageId: string;
26
+ id?: number;
27
+ } & (
28
+ | {
29
+ payload: Parameters<Channel['sendReaction']>;
30
+ type: PendingTaskTypes['sendReaction'];
31
+ }
32
+ | {
33
+ payload: Parameters<StreamChat['deleteMessage']>;
34
+ type: PendingTaskTypes['deleteMessage'];
35
+ }
36
+ | {
37
+ payload: Parameters<Channel['deleteReaction']>;
38
+ type: PendingTaskTypes['deleteReaction'];
39
+ }
40
+ );
@@ -25,6 +25,7 @@ export type File = {
25
25
  export type DefaultAttachmentType = UnknownType & {
26
26
  file_size?: number | string;
27
27
  mime_type?: string;
28
+ originalFile?: File;
28
29
  };
29
30
 
30
31
  interface DefaultUserType extends UnknownType {
@@ -37,7 +38,7 @@ interface DefaultChannelType extends UnknownType {
37
38
  }
38
39
 
39
40
  export interface DefaultStreamChatGenerics extends ExtendableGenerics {
40
- attachmentType: UnknownType;
41
+ attachmentType: DefaultAttachmentType;
41
42
  channelType: DefaultChannelType;
42
43
  commandType: LiteralStringForUnion;
43
44
  eventType: UnknownType;
@@ -47,3 +48,5 @@ export interface DefaultStreamChatGenerics extends ExtendableGenerics {
47
48
  }
48
49
 
49
50
  export type UnknownType = Record<string, unknown>;
51
+
52
+ export type ValueOf<T> = T[keyof T];
@@ -0,0 +1,222 @@
1
+ import type { AxiosError } from 'axios';
2
+ import type { APIErrorResponse, StreamChat } from 'stream-chat';
3
+
4
+ import { handleEventToSyncDB } from '../components/Chat/hooks/handleEventToSyncDB';
5
+ import { getAllChannelIds, getLastSyncedAt, upsertLastSyncedAt } from '../store/apis';
6
+
7
+ import { addPendingTask } from '../store/apis/addPendingTask';
8
+
9
+ import { deletePendingTask } from '../store/apis/deletePendingTask';
10
+ import { getPendingTasks } from '../store/apis/getPendingTasks';
11
+ import { QuickSqliteClient } from '../store/QuickSqliteClient';
12
+ import type { PendingTask, PreparedQueries } from '../store/types';
13
+ import type { DefaultStreamChatGenerics } from '../types/types';
14
+ /**
15
+ * DBSyncManager has the responsibility to sync the channel states
16
+ * within local database whenever possible.
17
+ *
18
+ * Components can get the current sync status using DBSyncManager.getCurrentStatus().
19
+ * Or components can attach a listener for status change as following:
20
+ *
21
+ * ```tsx
22
+ * useEffect(() => {
23
+ * const unsubscribe = DBSyncManager.onSyncStatusChange((syncStatus) => {
24
+ * if (syncStatus) {
25
+ * doSomething();
26
+ * }
27
+ * })
28
+ *
29
+ * return () => unsubscribe();
30
+ * })
31
+ * ```
32
+ */
33
+ const restBeforeNextTask = () => new Promise((resolve) => setTimeout(resolve, 500));
34
+
35
+ export class DBSyncManager {
36
+ static syncStatus = false;
37
+ static listeners: Array<(status: boolean) => void> = [];
38
+ static client: StreamChat | null = null;
39
+
40
+ /**
41
+ * Returns weather channel states in local DB are synced with backend or not.
42
+ * @returns boolean
43
+ */
44
+ static getSyncStatus = () => this.syncStatus;
45
+
46
+ /**
47
+ * Initializes the DBSyncManager. This function should be called only once
48
+ * throughout the lifetime of SDK.
49
+ *
50
+ * @param client
51
+ */
52
+ static init = async (client: StreamChat) => {
53
+ this.client = client;
54
+ // If the websocket connection is already active, then straightaway
55
+ // call the sync api and also execute pending api calls.
56
+ // Otherwise wait for `connection.changed` event.
57
+ if (client.user?.id && client.wsConnection?.isHealthy) {
58
+ await this.syncAndExecutePendingTasks();
59
+ this.syncStatus = true;
60
+ this.listeners.forEach((l) => l(true));
61
+ }
62
+
63
+ this.client.on('connection.changed', async (event) => {
64
+ if (event.online) {
65
+ await this.syncAndExecutePendingTasks();
66
+ this.listeners.forEach((l) => l(true));
67
+ } else {
68
+ this.listeners.forEach((l) => l(false));
69
+ }
70
+ });
71
+ };
72
+
73
+ /**
74
+ * Subscribes a listener for sync status change.
75
+ *
76
+ * @param listener {function}
77
+ * @returns {function} to unsubscribe the listener.
78
+ */
79
+ static onSyncStatusChange = (listener: (status: boolean) => void) => {
80
+ this.listeners.push(listener);
81
+
82
+ return {
83
+ unsubscribe: () => {
84
+ this.listeners = this.listeners.filter((el) => el !== listener);
85
+ },
86
+ };
87
+ };
88
+
89
+ static sync = async () => {
90
+ if (!this.client?.user) return;
91
+
92
+ const lastSyncedAt = getLastSyncedAt({
93
+ currentUserId: this.client.user.id,
94
+ });
95
+ const cids = getAllChannelIds();
96
+
97
+ if (lastSyncedAt) {
98
+ try {
99
+ const result = await this.client.sync(cids, new Date(lastSyncedAt).toISOString());
100
+ const queries = result.events.reduce<PreparedQueries[]>((queries, event) => {
101
+ queries = queries.concat(handleEventToSyncDB(event, false));
102
+ return queries;
103
+ }, []);
104
+
105
+ if (queries.length) {
106
+ QuickSqliteClient.executeSqlBatch(queries);
107
+ }
108
+ } catch (e) {
109
+ // Error will be raised by the sync API if there are too many events.
110
+ // In that case reset the entire DB and start fresh.
111
+ QuickSqliteClient.resetDB();
112
+ }
113
+ }
114
+ upsertLastSyncedAt({
115
+ currentUserId: this.client.user.id,
116
+ lastSyncedAt: new Date().toString(),
117
+ });
118
+ };
119
+
120
+ static syncAndExecutePendingTasks = async () => {
121
+ if (!this.client) return;
122
+
123
+ await this.executePendingTasks(this.client);
124
+ await this.sync();
125
+ };
126
+
127
+ static queueTask = async <
128
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
129
+ >({
130
+ client,
131
+ task,
132
+ }: {
133
+ client: StreamChat<StreamChatGenerics>;
134
+ task: PendingTask;
135
+ }) => {
136
+ const removeFromApi = addPendingTask(task);
137
+
138
+ let response;
139
+ try {
140
+ response = await this.executeTask<StreamChatGenerics>({ client, task });
141
+ } catch (e) {
142
+ if ((e as AxiosError<APIErrorResponse>)?.response?.data?.code === 4) {
143
+ // Error code 16 - message already exists
144
+ // ignore
145
+ } else {
146
+ throw e;
147
+ }
148
+ }
149
+
150
+ removeFromApi();
151
+
152
+ return response;
153
+ };
154
+
155
+ static executeTask = async <
156
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
157
+ >({
158
+ client,
159
+ task,
160
+ }: {
161
+ client: StreamChat<StreamChatGenerics>;
162
+ task: PendingTask;
163
+ }) => {
164
+ const channel = client.channel(task.channelType, task.channelId);
165
+
166
+ if (task.type === 'send-reaction') {
167
+ return await channel.sendReaction(...task.payload);
168
+ }
169
+
170
+ if (task.type === 'delete-reaction') {
171
+ return await channel.deleteReaction(...task.payload);
172
+ }
173
+
174
+ if (task.type === 'delete-message') {
175
+ return await client.deleteMessage(...task.payload);
176
+ }
177
+
178
+ throw new Error('Invalid task type');
179
+ };
180
+
181
+ static executePendingTasks = async <
182
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
183
+ >(
184
+ client: StreamChat<StreamChatGenerics>,
185
+ ) => {
186
+ const queue = getPendingTasks();
187
+ for (const task of queue) {
188
+ if (!task.id) continue;
189
+
190
+ try {
191
+ await this.executeTask<StreamChatGenerics>({
192
+ client,
193
+ task,
194
+ });
195
+ } catch (e) {
196
+ if ((e as AxiosError<APIErrorResponse>)?.response?.data?.code === 4) {
197
+ // Error code 16 - message already exists
198
+ // ignore
199
+ } else {
200
+ throw e;
201
+ }
202
+ }
203
+
204
+ deletePendingTask({
205
+ id: task.id,
206
+ });
207
+ await restBeforeNextTask();
208
+ }
209
+ };
210
+
211
+ static dropPendingTasks = (conditions: { messageId: string }) => {
212
+ const tasks = getPendingTasks(conditions);
213
+
214
+ for (const task of tasks) {
215
+ if (!task.id) continue;
216
+
217
+ deletePendingTask({
218
+ id: task.id,
219
+ });
220
+ }
221
+ };
222
+ }
@@ -0,0 +1,87 @@
1
+ import type { Channel, ReactionResponse, UserResponse } from 'stream-chat';
2
+
3
+ import { updateReaction } from '../store/apis';
4
+ import { insertReaction } from '../store/apis/insertReaction';
5
+
6
+ import type { DefaultStreamChatGenerics } from '../types/types';
7
+
8
+ export const addReactionToLocalState = <
9
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
10
+ >({
11
+ channel,
12
+ enforceUniqueReaction,
13
+ messageId,
14
+ reactionType,
15
+ user,
16
+ }: {
17
+ channel: Channel<StreamChatGenerics>;
18
+ enforceUniqueReaction: boolean;
19
+ messageId: string;
20
+ reactionType: string;
21
+ user: UserResponse<StreamChatGenerics>;
22
+ }) => {
23
+ const message = channel.state.messages.find(({ id }) => id === messageId);
24
+
25
+ if (!message) return;
26
+
27
+ const reaction: ReactionResponse = {
28
+ created_at: new Date().toISOString(),
29
+ message_id: messageId,
30
+ type: reactionType,
31
+ updated_at: new Date().toISOString(),
32
+ user,
33
+ user_id: user?.id,
34
+ };
35
+
36
+ const hasOwnReaction = message.own_reactions && message.own_reactions.length > 0;
37
+ if (!message.own_reactions) {
38
+ message.own_reactions = [];
39
+ }
40
+
41
+ if (!message.latest_reactions) {
42
+ message.latest_reactions = [];
43
+ }
44
+
45
+ if (enforceUniqueReaction) {
46
+ const currentReaction = message.own_reactions[0];
47
+ message.own_reactions = [];
48
+ if (!message.latest_reactions) {
49
+ message.latest_reactions = [];
50
+ }
51
+ message.latest_reactions = message.latest_reactions.filter((r) => r.user_id !== user.id);
52
+ if (currentReaction && message.reaction_counts) {
53
+ message.reaction_counts[currentReaction.type] =
54
+ message.reaction_counts[currentReaction.type] - 1;
55
+ }
56
+
57
+ if (!message.reaction_counts) {
58
+ message.reaction_counts = {
59
+ [reactionType]: 1,
60
+ };
61
+ } else {
62
+ message.reaction_counts[reactionType] = (message.reaction_counts?.[reactionType] || 0) + 1;
63
+ }
64
+ } else {
65
+ if (!message.reaction_counts) {
66
+ message.reaction_counts = {
67
+ [reactionType]: 1,
68
+ };
69
+ } else {
70
+ message.reaction_counts[reactionType] = message.reaction_counts[reactionType] + 1;
71
+ }
72
+ }
73
+
74
+ message.own_reactions = [...message.own_reactions, reaction];
75
+ message.latest_reactions = [...message.latest_reactions, reaction];
76
+
77
+ if (enforceUniqueReaction && hasOwnReaction) {
78
+ updateReaction({
79
+ message,
80
+ reaction,
81
+ });
82
+ } else {
83
+ insertReaction({
84
+ reaction,
85
+ });
86
+ }
87
+ };