@ethora/chat-component-rn 26.8.5 → 26.8.6

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 (373) hide show
  1. package/README.md +55 -0
  2. package/lib/commonjs/assets/emojiData.js +40 -0
  3. package/lib/commonjs/assets/emojiData.js.map +1 -0
  4. package/lib/commonjs/assets/icons.js +1 -1
  5. package/lib/commonjs/assets/icons.js.map +1 -1
  6. package/lib/commonjs/components/MainComponents/ChatHeader.js +7 -9
  7. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  8. package/lib/commonjs/components/MainComponents/ChatRoom.js +24 -23
  9. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  10. package/lib/commonjs/components/MainComponents/ChatWrapper.js +22 -16
  11. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  12. package/lib/commonjs/components/MainComponents/MessageContainer.js +4 -12
  13. package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
  14. package/lib/commonjs/components/MainComponents/MessageList.js +110 -35
  15. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  16. package/lib/commonjs/components/MainComponents/RoomList.js +32 -29
  17. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  18. package/lib/commonjs/components/MainComponents/RoomStack.js +133 -65
  19. package/lib/commonjs/components/MainComponents/RoomStack.js.map +1 -1
  20. package/lib/commonjs/components/MainComponents/SystemMessage.js +6 -2
  21. package/lib/commonjs/components/MainComponents/SystemMessage.js.map +1 -1
  22. package/lib/commonjs/components/MessageBubble/Avatar.js +5 -1
  23. package/lib/commonjs/components/MessageBubble/Avatar.js.map +1 -1
  24. package/lib/commonjs/components/MessageBubble/BottomReplyContainer.js +17 -21
  25. package/lib/commonjs/components/MessageBubble/BottomReplyContainer.js.map +1 -1
  26. package/lib/commonjs/components/MessageBubble/EmojiPickerSheet.js +447 -0
  27. package/lib/commonjs/components/MessageBubble/EmojiPickerSheet.js.map +1 -0
  28. package/lib/commonjs/components/MessageBubble/Message.js +200 -132
  29. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  30. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +213 -12
  31. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  32. package/lib/commonjs/components/MessageBubble/MessageReaction.js +113 -94
  33. package/lib/commonjs/components/MessageBubble/MessageReaction.js.map +1 -1
  34. package/lib/commonjs/components/MessageBubble/MessageReply.js +66 -24
  35. package/lib/commonjs/components/MessageBubble/MessageReply.js.map +1 -1
  36. package/lib/commonjs/components/Modals/Modal/SwipeBackLayer.js +76 -44
  37. package/lib/commonjs/components/Modals/Modal/SwipeBackLayer.js.map +1 -1
  38. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +5 -4
  39. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  40. package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js +8 -9
  41. package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
  42. package/lib/commonjs/components/Thread/ThreadWrapper.js +265 -152
  43. package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
  44. package/lib/commonjs/components/styled/DateLabel.js +6 -3
  45. package/lib/commonjs/components/styled/DateLabel.js.map +1 -1
  46. package/lib/commonjs/context/MessageNotificationContext.js +188 -9
  47. package/lib/commonjs/context/MessageNotificationContext.js.map +1 -1
  48. package/lib/commonjs/context/xmppProvider.js +22 -7
  49. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  50. package/lib/commonjs/helpers/createRoomFromApi.js +36 -2
  51. package/lib/commonjs/helpers/createRoomFromApi.js.map +1 -1
  52. package/lib/commonjs/helpers/emoji.js +51 -0
  53. package/lib/commonjs/helpers/emoji.js.map +1 -0
  54. package/lib/commonjs/helpers/haptics.js +29 -0
  55. package/lib/commonjs/helpers/haptics.js.map +1 -0
  56. package/lib/commonjs/helpers/historyPreloadScheduler.js +32 -66
  57. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  58. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +21 -12
  59. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  60. package/lib/commonjs/helpers/mamReactions.js +57 -0
  61. package/lib/commonjs/helpers/mamReactions.js.map +1 -0
  62. package/lib/commonjs/helpers/parseMessageReference.js +42 -0
  63. package/lib/commonjs/helpers/parseMessageReference.js.map +1 -0
  64. package/lib/commonjs/helpers/reactionsConfig.js +17 -0
  65. package/lib/commonjs/helpers/reactionsConfig.js.map +1 -0
  66. package/lib/commonjs/helpers/updateMessagesTillLast.js +17 -2
  67. package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
  68. package/lib/commonjs/hooks/useHeapSender.js +3 -1
  69. package/lib/commonjs/hooks/useHeapSender.js.map +1 -1
  70. package/lib/commonjs/hooks/useMessageHeapState.js +3 -2
  71. package/lib/commonjs/hooks/useMessageHeapState.js.map +1 -1
  72. package/lib/commonjs/hooks/useRoomInitialization.js +16 -7
  73. package/lib/commonjs/hooks/useRoomInitialization.js.map +1 -1
  74. package/lib/commonjs/hooks/useSendMessage.js +14 -8
  75. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  76. package/lib/commonjs/hooks/useUnreadMessagesCounter.js +1 -1
  77. package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
  78. package/lib/commonjs/networking/stanzaHandlers.js +106 -50
  79. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  80. package/lib/commonjs/networking/xmpp/getHistory.xmpp.js +29 -74
  81. package/lib/commonjs/networking/xmpp/getHistory.xmpp.js.map +1 -1
  82. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +4 -0
  83. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  84. package/lib/commonjs/networking/xmpp/mamRouter.js +186 -0
  85. package/lib/commonjs/networking/xmpp/mamRouter.js.map +1 -0
  86. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +41 -4
  87. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  88. package/lib/commonjs/networking/xmppClient.js +98 -23
  89. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  90. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js +29 -34
  91. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  92. package/lib/commonjs/roomStore/Middleware/perfMiddleware.js +51 -0
  93. package/lib/commonjs/roomStore/Middleware/perfMiddleware.js.map +1 -0
  94. package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js +66 -43
  95. package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
  96. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js +88 -68
  97. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  98. package/lib/commonjs/roomStore/index.js +18 -14
  99. package/lib/commonjs/roomStore/index.js.map +1 -1
  100. package/lib/commonjs/roomStore/persistBackend.js +96 -0
  101. package/lib/commonjs/roomStore/persistBackend.js.map +1 -0
  102. package/lib/commonjs/roomStore/persistence.js +245 -50
  103. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  104. package/lib/commonjs/roomStore/roomsSlice.js +282 -136
  105. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  106. package/lib/commonjs/theme/theme.js +3 -0
  107. package/lib/commonjs/theme/theme.js.map +1 -1
  108. package/lib/commonjs/utils/devLogger.js +14 -0
  109. package/lib/commonjs/utils/devLogger.js.map +1 -1
  110. package/lib/commonjs/version.js +1 -1
  111. package/lib/module/assets/emojiData.js +36 -0
  112. package/lib/module/assets/emojiData.js.map +1 -0
  113. package/lib/module/assets/icons.js +1 -1
  114. package/lib/module/assets/icons.js.map +1 -1
  115. package/lib/module/components/MainComponents/ChatHeader.js +8 -10
  116. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  117. package/lib/module/components/MainComponents/ChatRoom.js +25 -24
  118. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  119. package/lib/module/components/MainComponents/ChatWrapper.js +23 -17
  120. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  121. package/lib/module/components/MainComponents/MessageContainer.js +7 -14
  122. package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
  123. package/lib/module/components/MainComponents/MessageList.js +110 -35
  124. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  125. package/lib/module/components/MainComponents/RoomList.js +32 -29
  126. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  127. package/lib/module/components/MainComponents/RoomStack.js +131 -63
  128. package/lib/module/components/MainComponents/RoomStack.js.map +1 -1
  129. package/lib/module/components/MainComponents/SystemMessage.js +6 -2
  130. package/lib/module/components/MainComponents/SystemMessage.js.map +1 -1
  131. package/lib/module/components/MessageBubble/Avatar.js +5 -1
  132. package/lib/module/components/MessageBubble/Avatar.js.map +1 -1
  133. package/lib/module/components/MessageBubble/BottomReplyContainer.js +18 -22
  134. package/lib/module/components/MessageBubble/BottomReplyContainer.js.map +1 -1
  135. package/lib/module/components/MessageBubble/EmojiPickerSheet.js +438 -0
  136. package/lib/module/components/MessageBubble/EmojiPickerSheet.js.map +1 -0
  137. package/lib/module/components/MessageBubble/Message.js +203 -134
  138. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  139. package/lib/module/components/MessageBubble/MessageInteractions.js +215 -14
  140. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  141. package/lib/module/components/MessageBubble/MessageReaction.js +115 -94
  142. package/lib/module/components/MessageBubble/MessageReaction.js.map +1 -1
  143. package/lib/module/components/MessageBubble/MessageReply.js +65 -24
  144. package/lib/module/components/MessageBubble/MessageReply.js.map +1 -1
  145. package/lib/module/components/Modals/Modal/SwipeBackLayer.js +76 -44
  146. package/lib/module/components/Modals/Modal/SwipeBackLayer.js.map +1 -1
  147. package/lib/module/components/RoomComponents/ChatRoomItem.js +5 -4
  148. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  149. package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js +8 -9
  150. package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
  151. package/lib/module/components/Thread/ThreadWrapper.js +264 -152
  152. package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
  153. package/lib/module/components/styled/DateLabel.js +6 -3
  154. package/lib/module/components/styled/DateLabel.js.map +1 -1
  155. package/lib/module/context/MessageNotificationContext.js +190 -11
  156. package/lib/module/context/MessageNotificationContext.js.map +1 -1
  157. package/lib/module/context/xmppProvider.js +22 -7
  158. package/lib/module/context/xmppProvider.js.map +1 -1
  159. package/lib/module/helpers/createRoomFromApi.js +36 -2
  160. package/lib/module/helpers/createRoomFromApi.js.map +1 -1
  161. package/lib/module/helpers/emoji.js +44 -0
  162. package/lib/module/helpers/emoji.js.map +1 -0
  163. package/lib/module/helpers/haptics.js +24 -0
  164. package/lib/module/helpers/haptics.js.map +1 -0
  165. package/lib/module/helpers/historyPreloadScheduler.js +32 -66
  166. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  167. package/lib/module/helpers/insertMessageWithDelimiter.js +21 -12
  168. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  169. package/lib/module/helpers/mamReactions.js +51 -0
  170. package/lib/module/helpers/mamReactions.js.map +1 -0
  171. package/lib/module/helpers/parseMessageReference.js +37 -0
  172. package/lib/module/helpers/parseMessageReference.js.map +1 -0
  173. package/lib/module/helpers/reactionsConfig.js +10 -0
  174. package/lib/module/helpers/reactionsConfig.js.map +1 -0
  175. package/lib/module/helpers/updateMessagesTillLast.js +17 -2
  176. package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
  177. package/lib/module/hooks/useHeapSender.js +3 -1
  178. package/lib/module/hooks/useHeapSender.js.map +1 -1
  179. package/lib/module/hooks/useMessageHeapState.js +3 -2
  180. package/lib/module/hooks/useMessageHeapState.js.map +1 -1
  181. package/lib/module/hooks/useRoomInitialization.js +17 -8
  182. package/lib/module/hooks/useRoomInitialization.js.map +1 -1
  183. package/lib/module/hooks/useSendMessage.js +14 -8
  184. package/lib/module/hooks/useSendMessage.js.map +1 -1
  185. package/lib/module/hooks/useUnreadMessagesCounter.js +1 -1
  186. package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
  187. package/lib/module/networking/stanzaHandlers.js +107 -51
  188. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  189. package/lib/module/networking/xmpp/getHistory.xmpp.js +29 -74
  190. package/lib/module/networking/xmpp/getHistory.xmpp.js.map +1 -1
  191. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +4 -0
  192. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  193. package/lib/module/networking/xmpp/mamRouter.js +175 -0
  194. package/lib/module/networking/xmpp/mamRouter.js.map +1 -0
  195. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +38 -2
  196. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  197. package/lib/module/networking/xmppClient.js +99 -24
  198. package/lib/module/networking/xmppClient.js.map +1 -1
  199. package/lib/module/roomStore/Middleware/newMessageMidlleware.js +29 -34
  200. package/lib/module/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  201. package/lib/module/roomStore/Middleware/perfMiddleware.js +45 -0
  202. package/lib/module/roomStore/Middleware/perfMiddleware.js.map +1 -0
  203. package/lib/module/roomStore/Middleware/reactionsMiddleware.js +66 -43
  204. package/lib/module/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
  205. package/lib/module/roomStore/Middleware/unreadMidlleware.js +89 -69
  206. package/lib/module/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  207. package/lib/module/roomStore/index.js +19 -15
  208. package/lib/module/roomStore/index.js.map +1 -1
  209. package/lib/module/roomStore/persistBackend.js +89 -0
  210. package/lib/module/roomStore/persistBackend.js.map +1 -0
  211. package/lib/module/roomStore/persistence.js +245 -48
  212. package/lib/module/roomStore/persistence.js.map +1 -1
  213. package/lib/module/roomStore/roomsSlice.js +275 -134
  214. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  215. package/lib/module/theme/theme.js +3 -0
  216. package/lib/module/theme/theme.js.map +1 -1
  217. package/lib/module/utils/devLogger.js +13 -0
  218. package/lib/module/utils/devLogger.js.map +1 -1
  219. package/lib/module/version.js +1 -1
  220. package/lib/typescript/assets/emojiData.d.ts +8 -0
  221. package/lib/typescript/assets/emojiData.d.ts.map +1 -0
  222. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  223. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  224. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  225. package/lib/typescript/components/MainComponents/MessageContainer.d.ts +2 -2
  226. package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
  227. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  228. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  229. package/lib/typescript/components/MainComponents/RoomStack.d.ts +7 -2
  230. package/lib/typescript/components/MainComponents/RoomStack.d.ts.map +1 -1
  231. package/lib/typescript/components/MainComponents/SystemMessage.d.ts.map +1 -1
  232. package/lib/typescript/components/MessageBubble/Avatar.d.ts +2 -0
  233. package/lib/typescript/components/MessageBubble/Avatar.d.ts.map +1 -1
  234. package/lib/typescript/components/MessageBubble/BottomReplyContainer.d.ts.map +1 -1
  235. package/lib/typescript/components/MessageBubble/EmojiPickerSheet.d.ts +11 -0
  236. package/lib/typescript/components/MessageBubble/EmojiPickerSheet.d.ts.map +1 -0
  237. package/lib/typescript/components/MessageBubble/Message.d.ts +2 -2
  238. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  239. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts +2 -0
  240. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  241. package/lib/typescript/components/MessageBubble/MessageReaction.d.ts +1 -0
  242. package/lib/typescript/components/MessageBubble/MessageReaction.d.ts.map +1 -1
  243. package/lib/typescript/components/MessageBubble/MessageReply.d.ts +7 -7
  244. package/lib/typescript/components/MessageBubble/MessageReply.d.ts.map +1 -1
  245. package/lib/typescript/components/Modals/Modal/SwipeBackLayer.d.ts +2 -1
  246. package/lib/typescript/components/Modals/Modal/SwipeBackLayer.d.ts.map +1 -1
  247. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts +2 -2
  248. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  249. package/lib/typescript/components/RoomComponents/styled/LastMessageEmoji.d.ts +3 -6
  250. package/lib/typescript/components/RoomComponents/styled/LastMessageEmoji.d.ts.map +1 -1
  251. package/lib/typescript/components/Thread/ThreadWrapper.d.ts +7 -1
  252. package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
  253. package/lib/typescript/components/styled/DateLabel.d.ts +1 -0
  254. package/lib/typescript/components/styled/DateLabel.d.ts.map +1 -1
  255. package/lib/typescript/context/MessageNotificationContext.d.ts.map +1 -1
  256. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  257. package/lib/typescript/helpers/createRoomFromApi.d.ts.map +1 -1
  258. package/lib/typescript/helpers/emoji.d.ts +6 -0
  259. package/lib/typescript/helpers/emoji.d.ts.map +1 -0
  260. package/lib/typescript/helpers/haptics.d.ts +3 -0
  261. package/lib/typescript/helpers/haptics.d.ts.map +1 -0
  262. package/lib/typescript/helpers/historyPreloadScheduler.d.ts +1 -0
  263. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  264. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  265. package/lib/typescript/helpers/mamReactions.d.ts +13 -0
  266. package/lib/typescript/helpers/mamReactions.d.ts.map +1 -0
  267. package/lib/typescript/helpers/parseMessageReference.d.ts +16 -0
  268. package/lib/typescript/helpers/parseMessageReference.d.ts.map +1 -0
  269. package/lib/typescript/helpers/reactionsConfig.d.ts +5 -0
  270. package/lib/typescript/helpers/reactionsConfig.d.ts.map +1 -0
  271. package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
  272. package/lib/typescript/hooks/useHeapSender.d.ts.map +1 -1
  273. package/lib/typescript/hooks/useMessageHeapState.d.ts.map +1 -1
  274. package/lib/typescript/hooks/useRoomInitialization.d.ts +2 -2
  275. package/lib/typescript/hooks/useRoomInitialization.d.ts.map +1 -1
  276. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  277. package/lib/typescript/networking/stanzaHandlers.d.ts +4 -2
  278. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  279. package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts +3 -1
  280. package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts.map +1 -1
  281. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  282. package/lib/typescript/networking/xmpp/mamRouter.d.ts +23 -0
  283. package/lib/typescript/networking/xmpp/mamRouter.d.ts.map +1 -0
  284. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts +1 -0
  285. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
  286. package/lib/typescript/networking/xmppClient.d.ts +22 -1
  287. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  288. package/lib/typescript/roomStore/Middleware/newMessageMidlleware.d.ts.map +1 -1
  289. package/lib/typescript/roomStore/Middleware/perfMiddleware.d.ts +4 -0
  290. package/lib/typescript/roomStore/Middleware/perfMiddleware.d.ts.map +1 -0
  291. package/lib/typescript/roomStore/Middleware/reactionsMiddleware.d.ts +9 -0
  292. package/lib/typescript/roomStore/Middleware/reactionsMiddleware.d.ts.map +1 -1
  293. package/lib/typescript/roomStore/Middleware/unreadMidlleware.d.ts.map +1 -1
  294. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  295. package/lib/typescript/roomStore/persistBackend.d.ts +11 -0
  296. package/lib/typescript/roomStore/persistBackend.d.ts.map +1 -0
  297. package/lib/typescript/roomStore/persistence.d.ts +5 -6
  298. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  299. package/lib/typescript/roomStore/roomsSlice.d.ts +41 -1
  300. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  301. package/lib/typescript/theme/theme.d.ts +4 -1
  302. package/lib/typescript/theme/theme.d.ts.map +1 -1
  303. package/lib/typescript/types/models/message.model.d.ts +4 -0
  304. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  305. package/lib/typescript/types/models/room.model.d.ts +16 -0
  306. package/lib/typescript/types/models/room.model.d.ts.map +1 -1
  307. package/lib/typescript/types/models/xmpp.model.d.ts +6 -1
  308. package/lib/typescript/types/models/xmpp.model.d.ts.map +1 -1
  309. package/lib/typescript/types/types.d.ts +15 -3
  310. package/lib/typescript/types/types.d.ts.map +1 -1
  311. package/lib/typescript/utils/devLogger.d.ts +8 -0
  312. package/lib/typescript/utils/devLogger.d.ts.map +1 -1
  313. package/lib/typescript/version.d.ts +1 -1
  314. package/package.json +10 -1
  315. package/src/assets/emojiData.ts +2146 -0
  316. package/src/assets/icons.tsx +5 -5
  317. package/src/components/MainComponents/ChatHeader.tsx +16 -7
  318. package/src/components/MainComponents/ChatRoom.tsx +35 -29
  319. package/src/components/MainComponents/ChatWrapper.tsx +28 -10
  320. package/src/components/MainComponents/MessageContainer.tsx +7 -15
  321. package/src/components/MainComponents/MessageList.tsx +96 -43
  322. package/src/components/MainComponents/RoomList.tsx +28 -29
  323. package/src/components/MainComponents/RoomStack.tsx +156 -83
  324. package/src/components/MainComponents/SystemMessage.tsx +6 -2
  325. package/src/components/MessageBubble/Avatar.tsx +7 -1
  326. package/src/components/MessageBubble/BottomReplyContainer.tsx +19 -21
  327. package/src/components/MessageBubble/EmojiPickerSheet.tsx +468 -0
  328. package/src/components/MessageBubble/Message.tsx +146 -87
  329. package/src/components/MessageBubble/MessageInteractions.tsx +213 -12
  330. package/src/components/MessageBubble/MessageReaction.tsx +120 -96
  331. package/src/components/MessageBubble/MessageReply.tsx +65 -32
  332. package/src/components/Modals/Modal/SwipeBackLayer.tsx +114 -63
  333. package/src/components/RoomComponents/ChatRoomItem.tsx +11 -4
  334. package/src/components/RoomComponents/styled/LastMessageEmoji.tsx +7 -8
  335. package/src/components/Thread/ThreadWrapper.tsx +274 -198
  336. package/src/components/styled/DateLabel.tsx +7 -3
  337. package/src/context/MessageNotificationContext.tsx +205 -7
  338. package/src/context/xmppProvider.tsx +29 -9
  339. package/src/helpers/createRoomFromApi.tsx +37 -1
  340. package/src/helpers/emoji.ts +39 -0
  341. package/src/helpers/haptics.ts +19 -0
  342. package/src/helpers/historyPreloadScheduler.ts +37 -69
  343. package/src/helpers/insertMessageWithDelimiter.ts +23 -16
  344. package/src/helpers/mamReactions.ts +59 -0
  345. package/src/helpers/parseMessageReference.ts +38 -0
  346. package/src/helpers/reactionsConfig.ts +13 -0
  347. package/src/helpers/updateMessagesTillLast.tsx +14 -2
  348. package/src/hooks/useHeapSender.tsx +3 -2
  349. package/src/hooks/useMessageHeapState.tsx +6 -2
  350. package/src/hooks/useRoomInitialization.tsx +32 -15
  351. package/src/hooks/useSendMessage.tsx +18 -11
  352. package/src/hooks/useUnreadMessagesCounter.ts +1 -1
  353. package/src/networking/stanzaHandlers.ts +116 -60
  354. package/src/networking/xmpp/getHistory.xmpp.ts +44 -106
  355. package/src/networking/xmpp/handleStanzas.xmpp.ts +2 -0
  356. package/src/networking/xmpp/mamRouter.ts +176 -0
  357. package/src/networking/xmpp/presenceInRoom.xmpp.ts +46 -3
  358. package/src/networking/xmppClient.ts +105 -20
  359. package/src/roomStore/Middleware/newMessageMidlleware.tsx +35 -38
  360. package/src/roomStore/Middleware/perfMiddleware.ts +50 -0
  361. package/src/roomStore/Middleware/reactionsMiddleware.tsx +53 -52
  362. package/src/roomStore/Middleware/unreadMidlleware.tsx +92 -80
  363. package/src/roomStore/index.ts +28 -27
  364. package/src/roomStore/persistBackend.ts +96 -0
  365. package/src/roomStore/persistence.ts +280 -73
  366. package/src/roomStore/roomsSlice.ts +304 -155
  367. package/src/theme/theme.ts +10 -1
  368. package/src/types/models/message.model.ts +4 -0
  369. package/src/types/models/room.model.ts +17 -0
  370. package/src/types/models/xmpp.model.ts +4 -2
  371. package/src/types/types.ts +15 -3
  372. package/src/utils/devLogger.ts +16 -0
  373. package/src/version.ts +1 -1
@@ -6,10 +6,44 @@ let presenceIdCounter = 0;
6
6
  const nextPresenceId = () =>
7
7
  `presenceInRoom-${Date.now().toString(36)}-${(++presenceIdCounter).toString(36)}`;
8
8
 
9
- export const presenceInRoom = async (
9
+ const joinedByClient = new WeakMap<Client, Map<string, Promise<Element>>>();
10
+
11
+ const joinedRooms = (client: Client): Map<string, Promise<Element>> => {
12
+ let map = joinedByClient.get(client);
13
+ if (!map) {
14
+ map = new Map();
15
+ joinedByClient.set(client, map);
16
+ const forget = () => joinedByClient.get(client)?.clear();
17
+ client.on('disconnect', forget);
18
+ client.on('offline', forget);
19
+ }
20
+ return map;
21
+ };
22
+
23
+ export const __forgetJoinedRooms = (client: Client) =>
24
+ joinedByClient.get(client)?.clear();
25
+
26
+ export const presenceInRoom = (
27
+ client: Client,
28
+ roomJID: string,
29
+ delay = 0
30
+ ): Promise<Element> => {
31
+ const joined = joinedRooms(client);
32
+ const existing = joined.get(roomJID);
33
+ if (existing) {return existing;}
34
+ const join = joinRoom(client, roomJID, delay);
35
+ joined.set(roomJID, join);
36
+ // A failed join is not a join: let the next caller try again.
37
+ join.catch(() => {
38
+ if (joined.get(roomJID) === join) {joined.delete(roomJID);}
39
+ });
40
+ return join;
41
+ };
42
+
43
+ const joinRoom = async (
10
44
  client: Client,
11
45
  roomJID: string,
12
- delay = 2000
46
+ delay: number
13
47
  ): Promise<Element> => {
14
48
  let stanzaHandler: (stanza: Element) => void;
15
49
  const unsubscribe = () => client.off('stanza', stanzaHandler);
@@ -27,6 +61,11 @@ export const presenceInRoom = async (
27
61
  if (settled) {return;}
28
62
  settled = true;
29
63
 
64
+ if (delay <= 0) {
65
+ unsubscribe();
66
+ cb(value);
67
+ return;
68
+ }
30
69
  setTimeout(() => {
31
70
  unsubscribe();
32
71
  cb(value);
@@ -52,7 +91,11 @@ export const presenceInRoom = async (
52
91
  to: `${roomJID}/${client.jid?.getLocal()}`,
53
92
  id: stanzaId,
54
93
  },
55
- xml('x', { xmlns: 'http://jabber.org/protocol/muc' })
94
+ xml(
95
+ 'x',
96
+ { xmlns: 'http://jabber.org/protocol/muc' },
97
+ xml('history', { maxstanzas: '0' })
98
+ )
56
99
  );
57
100
 
58
101
  // Side-effects sequence: send the presence (handles its own
@@ -10,6 +10,7 @@ import { sendTypingRequest } from './xmpp/sendTypingRequest.xmpp';
10
10
  import { sendPing } from './xmpp/sendPing.xmpp';
11
11
  import { getHistory } from './xmpp/getHistory.xmpp';
12
12
  import { sendTextMessage } from './xmpp/sendTextMessage.xmpp';
13
+ import { sendMessageReaction } from './xmpp/sendMessageReaction.xmpp';
13
14
  import { sendTextMessageWithTranslateTag } from './xmpp/sendTextMessageWithTranslateTag.xmpp';
14
15
  import { deleteMessage } from './xmpp/deleteMessage.xmpp';
15
16
  import { presenceInRoom } from './xmpp/presenceInRoom.xmpp';
@@ -23,7 +24,7 @@ import { editMessage } from './xmpp/editMessage.xmpp';
23
24
  import { inviteRoomRequest } from './xmpp/inviteRoomRequest.xmpp';
24
25
  import { getRooms } from './xmpp/getRooms.xmpp';
25
26
  import { handleStanza } from './xmpp/handleStanzas.xmpp';
26
- import { pushLog as devPushLog } from '../utils/devLogger';
27
+ import { pushLog as devPushLog, isDevLogActive } from '../utils/devLogger';
27
28
  import { normalizeRoomJid } from '../helpers/normalizeRoomJid';
28
29
  import { store } from '../roomStore';
29
30
  import { applyPrivateStoreMarkers } from '../roomStore/roomsSlice';
@@ -69,6 +70,11 @@ function withTimeout(promise: Promise<unknown>, ms: number): Promise<void> {
69
70
  // where it fails — XMPPError on stream:error, SASLError on SASL bind, or
70
71
  // a generic Error whose message contains "not-authorized". Match all of
71
72
  // them so we trigger the credentials refresh path consistently.
73
+ // Failed XMPP-password recoveries in a row before the session is ended.
74
+ const AUTH_RECOVERY_MAX_FAILURES = 2;
75
+ // Rejections (each with a fresh password) before the password counts as lost.
76
+ const AUTH_REJECTIONS_LIMIT = 3;
77
+
72
78
  function isNotAuthorizedError(err: any): boolean {
73
79
  if (!err) {return false;}
74
80
  const condition =
@@ -90,6 +96,10 @@ interface HistoryOptions {
90
96
  coalesceRoom?: boolean;
91
97
  skipIfPreloaded?: boolean;
92
98
  source?: HistorySource;
99
+ /** The caller merges the returned page into the store itself (the
100
+ * preload scheduler and the catch-up pass do, to detect gaps); the MAM
101
+ * router then does not apply it. Default: applied by the router. */
102
+ selfApplied?: boolean;
93
103
  }
94
104
 
95
105
  interface MamInFlightEntry {
@@ -185,6 +195,42 @@ export class XmppClient {
185
195
  * (REST JWT, /users/client, etc.) and returning the resulting
186
196
  * username + password.
187
197
  */
198
+ /**
199
+ * Called once when the session's XMPP password is lost for good: the
200
+ * server rejected it (SASL not-authorized) and the refresh chain could
201
+ * not produce a working one — the refresh request failed, came back
202
+ * without a new password, or the new one was rejected too. Network
203
+ * outages never get here (no rejection without a reachable server).
204
+ */
205
+ private authLostHandler: (() => void) | null = null;
206
+ private authRecoveryFailures = 0;
207
+ private authLostFired = false;
208
+ // Rejections since the stream was last online — catches a refresh that
209
+ // keeps returning NEW passwords the server still rejects.
210
+ private authRejectionsSinceOnline = 0;
211
+
212
+ setAuthLostHandler(handler: (() => void) | null) {
213
+ this.authLostHandler = handler;
214
+ }
215
+
216
+ private markAuthRecoveryFailed(reason: string) {
217
+ this.authRecoveryFailures += 1;
218
+ console.warn(
219
+ `[xmpp] XMPP password recovery failed (${reason}), attempt ${this.authRecoveryFailures}`
220
+ );
221
+ // One retry before giving up, so a single REST hiccup does not end the
222
+ // session; a second failure in a row means the password is gone.
223
+ if (this.authRecoveryFailures >= AUTH_RECOVERY_MAX_FAILURES && !this.authLostFired) {
224
+ this.authLostFired = true;
225
+ this.suppressReconnect = true;
226
+ try {
227
+ this.authLostHandler?.();
228
+ } catch (e) {
229
+ console.warn('[xmpp] auth-lost handler threw', e);
230
+ }
231
+ }
232
+ }
233
+
188
234
  setCredentialsProvider(provider: XmppCredentialsProvider | null) {
189
235
  this.credentialsProvider = provider;
190
236
  }
@@ -286,8 +332,9 @@ export class XmppClient {
286
332
  before?: number;
287
333
  id?: string;
288
334
  source?: HistorySource;
335
+ selfApplied?: boolean;
289
336
  }): Promise<any> {
290
- const { chatJID, max, before, id, source = 'default' } = params;
337
+ const { chatJID, max, before, id, source = 'default', selfApplied } = params;
291
338
 
292
339
  // Coalesce — if a fetch for the same room is in-flight, reuse it
293
340
  // unless the new request is higher priority.
@@ -315,7 +362,9 @@ export class XmppClient {
315
362
  const handle: { p?: Promise<any> } = {};
316
363
  handle.p = (async () => {
317
364
  try {
318
- return await getHistory(this.client, chatJID, max, before, id);
365
+ return await getHistory(this.client, chatJID, max, before, id, {
366
+ selfApplied,
367
+ });
319
368
  } finally {
320
369
  const cur = this.mamInFlightByRoom.get(chatJID);
321
370
  if (cur && cur.promise === handle.p) {
@@ -383,7 +432,7 @@ export class XmppClient {
383
432
  // Raising the cap silences the warning without masking real leaks
384
433
  // — true leaks would still grow unboundedly past this number.
385
434
  try {
386
- (this.client as any)?.setMaxListeners?.(50);
435
+ (this.client as any)?.setMaxListeners?.(120);
387
436
  } catch {}
388
437
 
389
438
  // Wrap `send` so the dev logger sees outgoing stanzas too.
@@ -395,7 +444,7 @@ export class XmppClient {
395
444
  const origSend = this.client.send?.bind(this.client);
396
445
  if (origSend) {
397
446
  const wrapped = (stanza: any) => {
398
- try {
447
+ if (isDevLogActive()) {try {
399
448
  const tag = stanza?.name || 'stanza';
400
449
  const id = stanza?.attrs?.id || '';
401
450
  const to = stanza?.attrs?.to || '';
@@ -404,7 +453,7 @@ export class XmppClient {
404
453
  `→ ${tag}${id ? ` id=${id}` : ''}${to ? ` to=${to.split('/')[0]}` : ''}`,
405
454
  stanza?.toString ? stanza.toString() : undefined
406
455
  );
407
- } catch {}
456
+ } catch {}}
408
457
  const result = origSend(stanza);
409
458
  // Most stanza helpers fire-and-forget `client.send(...)`
410
459
  // without awaiting/catching. On @xmpp/client builds where
@@ -438,6 +487,7 @@ export class XmppClient {
438
487
  console.error('Error starting xmpp client:', error);
439
488
  if (isNotAuthorizedError(error)) {
440
489
  this.lastAuthError = 'not-authorized';
490
+ this.authRejectionsSinceOnline += 1;
441
491
  }
442
492
  this.status = 'error';
443
493
  // A connect-time failure lands in 'error', which — unlike a
@@ -497,6 +547,8 @@ export class XmppClient {
497
547
  this.onOnline = () => {
498
548
  console.log('XMPP online.', new Date());
499
549
  this.status = 'online';
550
+ this.authRecoveryFailures = 0;
551
+ this.authRejectionsSinceOnline = 0;
500
552
  this.presencesReady = true;
501
553
  this.reconnectAttempts = 0;
502
554
  try {
@@ -534,6 +586,7 @@ export class XmppClient {
534
586
  console.error('XMPP client error:', error);
535
587
  if (isNotAuthorizedError(error)) {
536
588
  this.lastAuthError = 'not-authorized';
589
+ this.authRejectionsSinceOnline += 1;
537
590
  }
538
591
  try {
539
592
  devPushLog(
@@ -545,7 +598,7 @@ export class XmppClient {
545
598
  };
546
599
 
547
600
  this.onStanza = (stanza: any) => {
548
- try {
601
+ if (isDevLogActive()) {try {
549
602
  const tag = stanza?.name || 'stanza';
550
603
  const id = stanza?.attrs?.id || '';
551
604
  const from = stanza?.attrs?.from || '';
@@ -555,7 +608,7 @@ export class XmppClient {
555
608
  `← ${tag}${id ? ` id=${id}` : ''}${type ? ` type=${type}` : ''}${from ? ` from=${from.split('/')[0]}` : ''}`,
556
609
  stanza?.toString ? stanza.toString() : undefined
557
610
  );
558
- } catch {}
611
+ } catch {}}
559
612
  handleStanza.bind(this, stanza, this)();
560
613
  };
561
614
 
@@ -739,16 +792,29 @@ export class XmppClient {
739
792
  CREDENTIALS_REFRESH_MIN_INTERVAL_MS;
740
793
 
741
794
  if (this.credentialsProvider && (authFailed || staleCreds)) {
795
+ const rejectedPassword = authFailed ? this.password : null;
742
796
  try {
743
797
  await this.refreshCredentialsOnce();
798
+ // The server said this password is wrong and the refresh handed
799
+ // back nothing new: there is no working password to connect with.
800
+ if (rejectedPassword !== null && (!this.password || this.password === rejectedPassword)) {
801
+ this.markAuthRecoveryFailed('no new XMPP password after refresh');
802
+ } else if (this.authRejectionsSinceOnline >= AUTH_REJECTIONS_LIMIT) {
803
+ this.markAuthRecoveryFailed('refreshed XMPP password rejected again');
804
+ }
744
805
  } catch (err) {
745
- // Offline is the common case here — reconnect with what we
746
- // have and let the next attempt try again.
747
- console.warn(
748
- 'XMPP credential refresh failed; reconnecting with cached creds',
749
- err
750
- );
806
+ if (rejectedPassword !== null) {
807
+ this.markAuthRecoveryFailed('refresh request failed');
808
+ } else {
809
+ // Offline is the common case here — reconnect with what we
810
+ // have and let the next attempt try again.
811
+ console.warn(
812
+ 'XMPP credential refresh failed; reconnecting with cached creds',
813
+ err
814
+ );
815
+ }
751
816
  }
817
+ if (this.suppressReconnect) {return;}
752
818
  }
753
819
 
754
820
  // Tear the OLD underlying client down FULLY before spinning up a new
@@ -903,6 +969,16 @@ export class XmppClient {
903
969
  }
904
970
 
905
971
  getRoomsStanza = async () => {
972
+ // Asked while the socket is down (mid-reconnect) this used to throw
973
+ // "Cannot read property 'write' of null". Wait for the stream instead;
974
+ // if it does not come back, skip — the reconnect hook re-syncs rooms.
975
+ if (this.status !== 'online') {
976
+ try {
977
+ await this.waitForOnline(15000);
978
+ } catch {
979
+ return;
980
+ }
981
+ }
906
982
  await getRooms(this.client);
907
983
  };
908
984
 
@@ -938,9 +1014,12 @@ export class XmppClient {
938
1014
  before,
939
1015
  id,
940
1016
  source: options?.source || 'default',
1017
+ selfApplied: options?.selfApplied,
941
1018
  });
942
1019
  }
943
- return await getHistory(this.client, chatJID, max, before, id);
1020
+ return await getHistory(this.client, chatJID, max, before, id, {
1021
+ selfApplied: options?.selfApplied,
1022
+ });
944
1023
  };
945
1024
 
946
1025
  getLastMessageArchiveStanza(roomJID: string) {
@@ -1194,12 +1273,18 @@ export class XmppClient {
1194
1273
  }
1195
1274
 
1196
1275
  sendMessageReactionStanza(
1197
- _messageId: string,
1198
- _roomJid: string,
1199
- _reactionsList: string[],
1200
- _reactionSymbol?: string
1276
+ messageId: string,
1277
+ roomJid: string,
1278
+ reactionsList: string[],
1279
+ data?: { firstName?: string; lastName?: string }
1201
1280
  ) {
1202
- console.warn('sendMessageReactionStanza: not implemented in RN xmpp client');
1281
+ sendMessageReaction(
1282
+ this.client,
1283
+ messageId,
1284
+ normalizeRoomJid(roomJid, this.conference),
1285
+ reactionsList,
1286
+ data || {}
1287
+ );
1203
1288
  }
1204
1289
 
1205
1290
  // Sends a groupchat message carrying a `<translate source="xx"/>` tag so
@@ -1,8 +1,7 @@
1
1
  import { Middleware } from '@reduxjs/toolkit';
2
- import { updateRoom } from '../roomsSlice';
3
2
  import { clearMessageFailure } from '../roomHeapSlice';
4
3
  import { removeOutboundSend } from '../../networking/outboundQueue';
5
- import { IRoom } from '../../types/types';
4
+ import { IMessage } from '../../types/types';
6
5
 
7
6
  export const newMessageMidlleware: Middleware =
8
7
  (storeAPI) => (next) => (action: any) => {
@@ -11,7 +10,9 @@ export const newMessageMidlleware: Middleware =
11
10
  return next(action);
12
11
  }
13
12
 
14
- if (action.type !== 'roomMessages/addRoomMessage') {
13
+ const isSingle = action.type === 'roomMessages/addRoomMessage';
14
+ const isBatch = action.type === 'roomMessages/addRoomMessages';
15
+ if (!isSingle && !isBatch) {
15
16
  return next(action);
16
17
  }
17
18
 
@@ -22,48 +23,44 @@ export const newMessageMidlleware: Middleware =
22
23
 
23
24
  const result = next(action);
24
25
  const state = storeAPI.getState();
25
- const rooms: { [jid: string]: IRoom } = state.rooms.rooms;
26
-
27
- const { roomJID, message } = action.payload;
28
-
29
- // Un-fail on confirmed delivery. A server-confirmed copy (echo or MAM
30
- // history, never `pending`) arriving for a message we'd flagged failed
31
- // means the send actually went through — e.g. a slow send that completed
32
- // just after the 5s watchdog window, or a queued auto-resend landing on
33
- // reconnect. The failed flag is keyed by our optimistic/stanza id, which
34
- // the echo carries back as `id`/`xmppId`, so clear it here and let the
35
- // bubble flip to delivered instead of staying stuck on "Failed".
36
- if (message && !message.pending) {
37
- // The confirmed copy carries our optimistic/stanza id back as id/xmppId.
38
- // Drop any still-buffered replay for it so a later reconnect flush can't
39
- // re-send an already-delivered message.
40
- removeOutboundSend(message.id);
41
- removeOutboundSend(message.xmppId);
42
-
43
- const failedMap = state.roomHeapSlice?.failedMessages || {};
44
- const failedKey = [message.id, message.xmppId].find(
45
- (k: string | undefined) => k && failedMap[k]
46
- );
47
- if (failedKey) {
48
- storeAPI.dispatch(clearMessageFailure(failedKey as string));
49
- }
50
- }
51
26
 
52
- if ((rooms[roomJID]?.lastMessageTimestamp ?? 0) <= Number(message.id)) {
53
- storeAPI.dispatch(
54
- updateRoom({
55
- jid: roomJID,
56
- updates: { lastMessageTimestamp: Number(message.id) ?? 0 },
57
- })
58
- );
27
+ // `lastMessageTimestamp` is now bumped inside the reducer itself (no
28
+ // second `updateRoom` pass per message). What is left here are the
29
+ // side effects outside the rooms slice.
30
+ const messages: IMessage[] = isBatch
31
+ ? action.payload.messages || []
32
+ : [action.payload.message];
33
+ const failedMap = state.roomHeapSlice?.failedMessages || {};
34
+
35
+ for (const message of messages) {
36
+ // Un-fail on confirmed delivery. A server-confirmed copy (echo or MAM
37
+ // history, never `pending`) arriving for a message we'd flagged failed
38
+ // means the send actually went through — e.g. a slow send that completed
39
+ // just after the 5s watchdog window, or a queued auto-resend landing on
40
+ // reconnect. The failed flag is keyed by our optimistic/stanza id, which
41
+ // the echo carries back as `id`/`xmppId`, so clear it here and let the
42
+ // bubble flip to delivered instead of staying stuck on "Failed".
43
+ if (message && !message.pending) {
44
+ // The confirmed copy carries our optimistic/stanza id back as id/xmppId.
45
+ // Drop any still-buffered replay for it so a later reconnect flush can't
46
+ // re-send an already-delivered message.
47
+ removeOutboundSend(message.id);
48
+ if (message.xmppId) {removeOutboundSend(message.xmppId);}
49
+
50
+ const failedKey = [message.id, message.xmppId].find(
51
+ (k: string | undefined) => k && failedMap[k]
52
+ );
53
+ if (failedKey) {
54
+ storeAPI.dispatch(clearMessageFailure(failedKey as string));
55
+ }
56
+ }
59
57
  }
60
58
 
61
59
  return result;
62
60
  };
63
61
 
64
62
  // import { Middleware, PayloadAction } from '@reduxjs/toolkit';
65
- // import { updateRoom } from '../roomsSlice';
66
- // import { AddRoomMessageAction, IRoom } from '../../types/types';
63
+ // // import { AddRoomMessageAction, IRoom } from '../../types/types';
67
64
  // import { nanoToMs } from '../../helpers/nanoToMs';
68
65
 
69
66
  // export const newMessageMidlleware: Middleware =
@@ -0,0 +1,50 @@
1
+ import { Middleware } from '@reduxjs/toolkit';
2
+
3
+ declare const __DEV__: boolean | undefined;
4
+
5
+ /**
6
+ * Dev-only store profiler: counts dispatches and the time the reducer +
7
+ * middleware chain spent on them, and prints a one-line summary every
8
+ * 10 s while there was activity. Reads as
9
+ * [perf] 10s: 143 actions, 212ms in store, top: roomMessages/addRoomMessages×12 (90ms) …
10
+ * No-op (and not even installed) in release builds.
11
+ */
12
+ const WINDOW_MS = 10000;
13
+
14
+ let count = 0;
15
+ let totalMs = 0;
16
+ let byType: Record<string, { n: number; ms: number }> = {};
17
+ let timer: ReturnType<typeof setTimeout> | null = null;
18
+
19
+ const flush = () => {
20
+ timer = null;
21
+ if (count === 0) {return;}
22
+ const top = Object.entries(byType)
23
+ .sort((a, b) => b[1].ms - a[1].ms)
24
+ .slice(0, 4)
25
+ .map(([type, v]) => `${type}×${v.n} (${v.ms.toFixed(0)}ms)`)
26
+ .join(', ');
27
+ console.log(
28
+ `[perf] ${WINDOW_MS / 1000}s: ${count} actions, ${totalMs.toFixed(0)}ms in store, top: ${top}`
29
+ );
30
+ count = 0;
31
+ totalMs = 0;
32
+ byType = {};
33
+ };
34
+
35
+ export const perfMiddleware: Middleware = () => (next) => (action: any) => {
36
+ const start = Date.now();
37
+ const result = next(action);
38
+ const ms = Date.now() - start;
39
+ count += 1;
40
+ totalMs += ms;
41
+ const type = action?.type || '?';
42
+ const entry = byType[type] || (byType[type] = { n: 0, ms: 0 });
43
+ entry.n += 1;
44
+ entry.ms += ms;
45
+ if (!timer) {timer = setTimeout(flush, WINDOW_MS);}
46
+ return result;
47
+ };
48
+
49
+ export const isPerfProfilingEnabled = () =>
50
+ typeof __DEV__ !== 'undefined' && __DEV__ === true;
@@ -1,77 +1,78 @@
1
- import { Middleware, PayloadAction } from '@reduxjs/toolkit';
1
+ import { Middleware } from '@reduxjs/toolkit';
2
2
  import { updateRoom } from '../roomsSlice';
3
- import { IRoom, ReactionAction } from '../../types/types';
4
- import { nanoToMs } from '../../helpers/nanoToMs';
3
+ import { IMessage, IRoom } from '../../types/types';
5
4
 
5
+ /**
6
+ * Keeps the room-list preview in step with reactions (as on web): the
7
+ * newest event in a room being a reaction shows "Ann: 👍"; a reactor
8
+ * clearing theirs puts the last real message back.
9
+ *
10
+ * Timestamps here are the server's stanza ids, the same unit as
11
+ * `lastMessageTimestamp` (set from message ids in the reducer), so a
12
+ * reaction older than the room's latest message never takes the preview.
13
+ */
6
14
  export const reactionsMiddleware: Middleware =
7
15
  (storeAPI) => (next) => (action: any) => {
8
- if (action.type !== 'roomMessages/setReactions') {
16
+ if (action?.type !== 'roomMessages/setReactions') {
9
17
  return next(action);
10
18
  }
11
-
12
19
  if (!action.payload || typeof action.payload !== 'object') {
13
20
  console.error('Invalid action payload for setReactions:', action);
14
21
  return next(action);
15
22
  }
16
-
17
23
  const result = next(action);
18
- const state = storeAPI.getState();
19
- const rooms: { [jid: string]: IRoom } = state.rooms.rooms;
20
- const { roomJID, reactions, latestReactionTimestamp, data, ...rest } =
21
- action.payload;
24
+ try {
25
+ const payload = action.payload || {};
26
+ const { roomJID, reactions, latestReactionTimestamp, data } = payload;
27
+ const room: IRoom | undefined = storeAPI.getState().rooms?.rooms?.[roomJID];
28
+ if (!room) {return result;}
22
29
 
23
- const updLastMessage = () => {
24
- if (!reactions?.[0]) {
25
- const newLastMessage =
26
- rooms[roomJID].messages[rooms[roomJID].messages.length - 1];
30
+ const ts = Number(latestReactionTimestamp) || 0;
31
+ const roomTs = Number(room.lastMessageTimestamp) || 0;
27
32
 
33
+ if (Array.isArray(reactions) && reactions[0]) {
34
+ // Only the newest event in the room may become the preview.
35
+ if (!ts || ts < roomTs) {return result;}
36
+ const name = `${data?.senderFirstName || ''} ${data?.senderLastName || ''}`.trim();
28
37
  storeAPI.dispatch(
29
38
  updateRoom({
30
39
  jid: roomJID,
31
40
  updates: {
32
- lastMessageTimestamp: nanoToMs(
33
- rooms[roomJID].messages[rooms[roomJID].messages.length - 1].id
34
- ) ?? 0,
35
- lastMessage: newLastMessage as any,
41
+ lastMessageTimestamp: ts,
42
+ lastMessage: {
43
+ id: `reaction-${ts}`,
44
+ body: reactions[0],
45
+ emoji: reactions[0],
46
+ user: { id: `emoji-${ts}`, name },
47
+ date: new Date(Math.floor(ts / 1000)).toISOString(),
48
+ } as any,
36
49
  },
37
50
  })
38
51
  );
39
- } else {
40
- const updates = {
41
- lastMessageTimestamp: nanoToMs(latestReactionTimestamp) ?? 0,
42
- lastMessage: {
43
- ...rest,
44
- body: reactions[0],
45
- emoji: reactions[0],
46
- user: {
47
- name: `${data.senderFirstName} ${data.senderLastName}`,
48
- id: `emoji-${new Date().toString()}`,
49
- },
50
- date: new Date(nanoToMs(latestReactionTimestamp) ?? 0).toISOString(),
51
- },
52
- };
53
-
54
- storeAPI.dispatch(
55
- updateRoom({
56
- jid: roomJID,
57
- updates: updates as any,
58
- })
59
- );
52
+ return result;
60
53
  }
61
- };
62
-
63
- if (!rooms[roomJID]) {
64
- console.warn(`Room ${roomJID} not found in reactions middleware`);
65
- return result;
66
- }
67
54
 
68
- if (
69
- (rooms[roomJID]?.lastMessageTimestamp ?? 0) <= (nanoToMs(latestReactionTimestamp) ?? 0)
70
- ) {
71
- updLastMessage();
72
- } else if (!rooms[roomJID]?.lastMessageTimestamp) {
73
- updLastMessage();
55
+ // A reaction was cleared: if the preview was a reaction, fall back to
56
+ // the newest real message (the room may have none loaded yet).
57
+ if (!(room.lastMessage as any)?.emoji) {return result;}
58
+ const messages: IMessage[] = room.messages || [];
59
+ let last: IMessage | undefined;
60
+ for (let i = messages.length - 1; i >= 0; i--) {
61
+ const m = messages[i];
62
+ if (m && m.id !== 'delimiter-new' && !m.isDeleted) {
63
+ last = m;
64
+ break;
65
+ }
66
+ }
67
+ storeAPI.dispatch(
68
+ updateRoom({
69
+ jid: roomJID,
70
+ updates: { lastMessage: (last as any) ?? undefined },
71
+ })
72
+ );
73
+ } catch (e) {
74
+ // A preview update must never break the action that carried it.
75
+ console.warn('reactionsMiddleware: preview update failed', e);
74
76
  }
75
-
76
77
  return result;
77
78
  };