@ethora/chat-component-rn 26.5.7 → 26.5.10

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 (371) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/README.md +67 -10
  3. package/index.js +24 -0
  4. package/lib/commonjs/assets/icons.js +5 -1
  5. package/lib/commonjs/assets/icons.js.map +1 -1
  6. package/lib/commonjs/components/ContextMenu/ContextMenuComponents.js +11 -5
  7. package/lib/commonjs/components/ContextMenu/ContextMenuComponents.js.map +1 -1
  8. package/lib/commonjs/components/MainComponents/ChatRoom.js +64 -38
  9. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  10. package/lib/commonjs/components/MainComponents/ChatWrapper.js +57 -13
  11. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  12. package/lib/commonjs/components/MainComponents/MediaMessage.js +4 -2
  13. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  14. package/lib/commonjs/components/MainComponents/MessageContainer.js +2 -2
  15. package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
  16. package/lib/commonjs/components/MainComponents/MessageList.js +165 -28
  17. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  18. package/lib/commonjs/components/MainComponents/ReduxWrapper.js +17 -8
  19. package/lib/commonjs/components/MainComponents/ReduxWrapper.js.map +1 -1
  20. package/lib/commonjs/components/MainComponents/SystemMessage.js +34 -22
  21. package/lib/commonjs/components/MainComponents/SystemMessage.js.map +1 -1
  22. package/lib/commonjs/components/MessageBubble/Message.js +84 -39
  23. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  24. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +82 -22
  25. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  26. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +16 -4
  27. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  28. package/lib/commonjs/components/Modals/FilePreviewModal/DocumentViewer.js +104 -0
  29. package/lib/commonjs/components/Modals/FilePreviewModal/DocumentViewer.js.map +1 -0
  30. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +140 -24
  31. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  32. package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js +29 -1
  33. package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
  34. package/lib/commonjs/components/Modals/Modal/Modal.js +5 -1
  35. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  36. package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js +77 -47
  37. package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
  38. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +3 -3
  39. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  40. package/lib/commonjs/components/Modals/styledModalComponents.js +4 -9
  41. package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
  42. package/lib/commonjs/components/styled/MediaFilePreview.js +47 -28
  43. package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
  44. package/lib/commonjs/components/styled/MessageImage.js +49 -9
  45. package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
  46. package/lib/commonjs/components/styled/NewMessageLabel.js +8 -6
  47. package/lib/commonjs/components/styled/NewMessageLabel.js.map +1 -1
  48. package/lib/commonjs/components/styled/SendInput.js +49 -27
  49. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  50. package/lib/commonjs/components/styled/StyledInputComponents/MediaComponents.js +14 -4
  51. package/lib/commonjs/components/styled/StyledInputComponents/MediaComponents.js.map +1 -1
  52. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +7 -2
  53. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  54. package/lib/commonjs/components/styled/UnsupportedType.js +5 -1
  55. package/lib/commonjs/components/styled/UnsupportedType.js.map +1 -1
  56. package/lib/commonjs/components/styled/VideoMessage.js +60 -14
  57. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  58. package/lib/commonjs/context/MessageNotificationContext.js +7 -7
  59. package/lib/commonjs/context/MessageNotificationContext.js.map +1 -1
  60. package/lib/commonjs/context/xmppProvider.js +244 -32
  61. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  62. package/lib/commonjs/helpers/chatAutoEnterer.js +2 -7
  63. package/lib/commonjs/helpers/chatAutoEnterer.js.map +1 -1
  64. package/lib/commonjs/helpers/historyPreloadScheduler.js +4 -1
  65. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  66. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +15 -5
  67. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  68. package/lib/commonjs/helpers/keyboardLayout.js +18 -0
  69. package/lib/commonjs/helpers/keyboardLayout.js.map +1 -0
  70. package/lib/commonjs/helpers/mediaDimensions.js +51 -0
  71. package/lib/commonjs/helpers/mediaDimensions.js.map +1 -0
  72. package/lib/commonjs/helpers/normalizeRoomJid.js +20 -0
  73. package/lib/commonjs/helpers/normalizeRoomJid.js.map +1 -0
  74. package/lib/commonjs/hooks/useChatRoomFocus.js +87 -0
  75. package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -0
  76. package/lib/commonjs/hooks/useHeapSender.js +1 -1
  77. package/lib/commonjs/hooks/useHeapSender.js.map +1 -1
  78. package/lib/commonjs/hooks/useLogout.js +3 -3
  79. package/lib/commonjs/hooks/useLogout.js.map +1 -1
  80. package/lib/commonjs/hooks/usePushNotifications.js +6 -2
  81. package/lib/commonjs/hooks/usePushNotifications.js.map +1 -1
  82. package/lib/commonjs/hooks/useRoomState.js +2 -0
  83. package/lib/commonjs/hooks/useRoomState.js.map +1 -1
  84. package/lib/commonjs/hooks/useSendMessage.js +201 -10
  85. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  86. package/lib/commonjs/hooks/useUnreadMessagesCounter.js +12 -14
  87. package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
  88. package/lib/commonjs/main.js +7 -0
  89. package/lib/commonjs/main.js.map +1 -1
  90. package/lib/commonjs/networking/api-requests/auth.api.js +67 -0
  91. package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
  92. package/lib/commonjs/networking/apiClient.js +2 -1
  93. package/lib/commonjs/networking/apiClient.js.map +1 -1
  94. package/lib/commonjs/networking/outboundQueue.js +92 -0
  95. package/lib/commonjs/networking/outboundQueue.js.map +1 -0
  96. package/lib/commonjs/networking/xmpp/createTimeoutPromise.xmpp.js +4 -1
  97. package/lib/commonjs/networking/xmpp/createTimeoutPromise.xmpp.js.map +1 -1
  98. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +7 -8
  99. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  100. package/lib/commonjs/networking/xmpp/getRoomsPaged.xmpp.js +26 -3
  101. package/lib/commonjs/networking/xmpp/getRoomsPaged.xmpp.js.map +1 -1
  102. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +26 -8
  103. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  104. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js +2 -1
  105. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  106. package/lib/commonjs/networking/xmppClient.js +294 -35
  107. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  108. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js +22 -6
  109. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  110. package/lib/commonjs/roomStore/roomsSlice.js +157 -23
  111. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  112. package/lib/commonjs/utils/installPromiseRejectionTracker.js +83 -0
  113. package/lib/commonjs/utils/installPromiseRejectionTracker.js.map +1 -0
  114. package/lib/commonjs/utils/resendMessage.js +1 -1
  115. package/lib/commonjs/utils/resendMessage.js.map +1 -1
  116. package/lib/module/assets/icons.js +5 -1
  117. package/lib/module/assets/icons.js.map +1 -1
  118. package/lib/module/components/ContextMenu/ContextMenuComponents.js +11 -5
  119. package/lib/module/components/ContextMenu/ContextMenuComponents.js.map +1 -1
  120. package/lib/module/components/MainComponents/ChatRoom.js +65 -39
  121. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  122. package/lib/module/components/MainComponents/ChatWrapper.js +57 -13
  123. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  124. package/lib/module/components/MainComponents/MediaMessage.js +4 -2
  125. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  126. package/lib/module/components/MainComponents/MessageContainer.js +2 -2
  127. package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
  128. package/lib/module/components/MainComponents/MessageList.js +166 -29
  129. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  130. package/lib/module/components/MainComponents/ReduxWrapper.js +18 -8
  131. package/lib/module/components/MainComponents/ReduxWrapper.js.map +1 -1
  132. package/lib/module/components/MainComponents/SystemMessage.js +33 -21
  133. package/lib/module/components/MainComponents/SystemMessage.js.map +1 -1
  134. package/lib/module/components/MessageBubble/Message.js +85 -40
  135. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  136. package/lib/module/components/MessageBubble/MessageInteractions.js +84 -24
  137. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  138. package/lib/module/components/Modals/AttachSheet/AttachSheet.js +15 -3
  139. package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  140. package/lib/module/components/Modals/FilePreviewModal/DocumentViewer.js +99 -0
  141. package/lib/module/components/Modals/FilePreviewModal/DocumentViewer.js.map +1 -0
  142. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +143 -25
  143. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  144. package/lib/module/components/Modals/FilePreviewModal/PdfView.js +31 -3
  145. package/lib/module/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
  146. package/lib/module/components/Modals/Modal/Modal.js +5 -1
  147. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  148. package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js +79 -49
  149. package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
  150. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +3 -3
  151. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  152. package/lib/module/components/Modals/styledModalComponents.js +4 -9
  153. package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
  154. package/lib/module/components/styled/MediaFilePreview.js +47 -28
  155. package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
  156. package/lib/module/components/styled/MessageImage.js +51 -11
  157. package/lib/module/components/styled/MessageImage.js.map +1 -1
  158. package/lib/module/components/styled/NewMessageLabel.js +8 -6
  159. package/lib/module/components/styled/NewMessageLabel.js.map +1 -1
  160. package/lib/module/components/styled/SendInput.js +50 -28
  161. package/lib/module/components/styled/SendInput.js.map +1 -1
  162. package/lib/module/components/styled/StyledInputComponents/MediaComponents.js +14 -4
  163. package/lib/module/components/styled/StyledInputComponents/MediaComponents.js.map +1 -1
  164. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +7 -2
  165. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  166. package/lib/module/components/styled/UnsupportedType.js +5 -1
  167. package/lib/module/components/styled/UnsupportedType.js.map +1 -1
  168. package/lib/module/components/styled/VideoMessage.js +61 -15
  169. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  170. package/lib/module/context/MessageNotificationContext.js +7 -7
  171. package/lib/module/context/MessageNotificationContext.js.map +1 -1
  172. package/lib/module/context/xmppProvider.js +246 -34
  173. package/lib/module/context/xmppProvider.js.map +1 -1
  174. package/lib/module/helpers/chatAutoEnterer.js +2 -7
  175. package/lib/module/helpers/chatAutoEnterer.js.map +1 -1
  176. package/lib/module/helpers/historyPreloadScheduler.js +4 -1
  177. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  178. package/lib/module/helpers/insertMessageWithDelimiter.js +15 -5
  179. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  180. package/lib/module/helpers/keyboardLayout.js +12 -0
  181. package/lib/module/helpers/keyboardLayout.js.map +1 -0
  182. package/lib/module/helpers/mediaDimensions.js +46 -0
  183. package/lib/module/helpers/mediaDimensions.js.map +1 -0
  184. package/lib/module/helpers/normalizeRoomJid.js +15 -0
  185. package/lib/module/helpers/normalizeRoomJid.js.map +1 -0
  186. package/lib/module/hooks/useChatRoomFocus.js +82 -0
  187. package/lib/module/hooks/useChatRoomFocus.js.map +1 -0
  188. package/lib/module/hooks/useHeapSender.js +1 -1
  189. package/lib/module/hooks/useHeapSender.js.map +1 -1
  190. package/lib/module/hooks/useLogout.js +3 -3
  191. package/lib/module/hooks/useLogout.js.map +1 -1
  192. package/lib/module/hooks/usePushNotifications.js +6 -2
  193. package/lib/module/hooks/usePushNotifications.js.map +1 -1
  194. package/lib/module/hooks/useRoomState.js +2 -0
  195. package/lib/module/hooks/useRoomState.js.map +1 -1
  196. package/lib/module/hooks/useSendMessage.js +203 -12
  197. package/lib/module/hooks/useSendMessage.js.map +1 -1
  198. package/lib/module/hooks/useUnreadMessagesCounter.js +12 -14
  199. package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
  200. package/lib/module/main.js +1 -0
  201. package/lib/module/main.js.map +1 -1
  202. package/lib/module/networking/api-requests/auth.api.js +67 -1
  203. package/lib/module/networking/api-requests/auth.api.js.map +1 -1
  204. package/lib/module/networking/apiClient.js +2 -1
  205. package/lib/module/networking/apiClient.js.map +1 -1
  206. package/lib/module/networking/outboundQueue.js +84 -0
  207. package/lib/module/networking/outboundQueue.js.map +1 -0
  208. package/lib/module/networking/xmpp/createTimeoutPromise.xmpp.js +4 -1
  209. package/lib/module/networking/xmpp/createTimeoutPromise.xmpp.js.map +1 -1
  210. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +7 -8
  211. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  212. package/lib/module/networking/xmpp/getRoomsPaged.xmpp.js +26 -3
  213. package/lib/module/networking/xmpp/getRoomsPaged.xmpp.js.map +1 -1
  214. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +26 -8
  215. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  216. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js +2 -1
  217. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  218. package/lib/module/networking/xmppClient.js +294 -35
  219. package/lib/module/networking/xmppClient.js.map +1 -1
  220. package/lib/module/roomStore/Middleware/unreadMidlleware.js +22 -6
  221. package/lib/module/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  222. package/lib/module/roomStore/roomsSlice.js +154 -22
  223. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  224. package/lib/module/utils/installPromiseRejectionTracker.js +78 -0
  225. package/lib/module/utils/installPromiseRejectionTracker.js.map +1 -0
  226. package/lib/module/utils/resendMessage.js +1 -1
  227. package/lib/module/utils/resendMessage.js.map +1 -1
  228. package/lib/typescript/assets/icons.d.ts +8 -4
  229. package/lib/typescript/assets/icons.d.ts.map +1 -1
  230. package/lib/typescript/components/ContextMenu/ContextMenuComponents.d.ts.map +1 -1
  231. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  232. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  233. package/lib/typescript/components/MainComponents/MediaMessage.d.ts +1 -0
  234. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  235. package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
  236. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  237. package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts +1 -0
  238. package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts.map +1 -1
  239. package/lib/typescript/components/MainComponents/SystemMessage.d.ts +0 -7
  240. package/lib/typescript/components/MainComponents/SystemMessage.d.ts.map +1 -1
  241. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  242. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts +4 -2
  243. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  244. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
  245. package/lib/typescript/components/Modals/FilePreviewModal/DocumentViewer.d.ts +29 -0
  246. package/lib/typescript/components/Modals/FilePreviewModal/DocumentViewer.d.ts.map +1 -0
  247. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts +0 -1
  248. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  249. package/lib/typescript/components/Modals/FilePreviewModal/PdfView.d.ts.map +1 -1
  250. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  251. package/lib/typescript/components/Modals/ModalWrapper/ModalWrapper.d.ts.map +1 -1
  252. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  253. package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
  254. package/lib/typescript/components/styled/MediaFilePreview.d.ts.map +1 -1
  255. package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
  256. package/lib/typescript/components/styled/NewMessageLabel.d.ts +1 -5
  257. package/lib/typescript/components/styled/NewMessageLabel.d.ts.map +1 -1
  258. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  259. package/lib/typescript/components/styled/StyledInputComponents/MediaComponents.d.ts +9 -1
  260. package/lib/typescript/components/styled/StyledInputComponents/MediaComponents.d.ts.map +1 -1
  261. package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
  262. package/lib/typescript/components/styled/UnsupportedType.d.ts +1 -0
  263. package/lib/typescript/components/styled/UnsupportedType.d.ts.map +1 -1
  264. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  265. package/lib/typescript/context/xmppProvider.d.ts +1 -0
  266. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  267. package/lib/typescript/helpers/chatAutoEnterer.d.ts.map +1 -1
  268. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  269. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  270. package/lib/typescript/helpers/keyboardLayout.d.ts +9 -0
  271. package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -0
  272. package/lib/typescript/helpers/mediaDimensions.d.ts +9 -0
  273. package/lib/typescript/helpers/mediaDimensions.d.ts.map +1 -0
  274. package/lib/typescript/helpers/normalizeRoomJid.d.ts +2 -0
  275. package/lib/typescript/helpers/normalizeRoomJid.d.ts.map +1 -0
  276. package/lib/typescript/hooks/useChatRoomFocus.d.ts +42 -0
  277. package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -0
  278. package/lib/typescript/hooks/useHeapSender.d.ts.map +1 -1
  279. package/lib/typescript/hooks/usePushNotifications.d.ts.map +1 -1
  280. package/lib/typescript/hooks/useRoomState.d.ts +1 -0
  281. package/lib/typescript/hooks/useRoomState.d.ts.map +1 -1
  282. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  283. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
  284. package/lib/typescript/main.d.ts +1 -0
  285. package/lib/typescript/main.d.ts.map +1 -1
  286. package/lib/typescript/networking/api-requests/auth.api.d.ts +3 -0
  287. package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
  288. package/lib/typescript/networking/apiClient.d.ts.map +1 -1
  289. package/lib/typescript/networking/outboundQueue.d.ts +57 -0
  290. package/lib/typescript/networking/outboundQueue.d.ts.map +1 -0
  291. package/lib/typescript/networking/xmpp/createTimeoutPromise.xmpp.d.ts.map +1 -1
  292. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +1 -1
  293. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
  294. package/lib/typescript/networking/xmpp/getRoomsPaged.xmpp.d.ts +1 -1
  295. package/lib/typescript/networking/xmpp/getRoomsPaged.xmpp.d.ts.map +1 -1
  296. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
  297. package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts.map +1 -1
  298. package/lib/typescript/networking/xmppClient.d.ts +33 -4
  299. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  300. package/lib/typescript/roomStore/Middleware/unreadMidlleware.d.ts.map +1 -1
  301. package/lib/typescript/roomStore/roomsSlice.d.ts +8 -1
  302. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  303. package/lib/typescript/types/models/media.model.d.ts +1 -0
  304. package/lib/typescript/types/models/media.model.d.ts.map +1 -1
  305. package/lib/typescript/types/models/xmpp.model.d.ts +1 -1
  306. package/lib/typescript/types/models/xmpp.model.d.ts.map +1 -1
  307. package/lib/typescript/types/types.d.ts +4 -0
  308. package/lib/typescript/types/types.d.ts.map +1 -1
  309. package/lib/typescript/utils/installPromiseRejectionTracker.d.ts +20 -0
  310. package/lib/typescript/utils/installPromiseRejectionTracker.d.ts.map +1 -0
  311. package/lib/typescript/utils/resendMessage.d.ts.map +1 -1
  312. package/package.json +18 -2
  313. package/src/assets/icons.tsx +23 -14
  314. package/src/components/ContextMenu/ContextMenuComponents.tsx +10 -5
  315. package/src/components/MainComponents/ChatRoom.tsx +81 -66
  316. package/src/components/MainComponents/ChatWrapper.tsx +99 -21
  317. package/src/components/MainComponents/MediaMessage.tsx +3 -0
  318. package/src/components/MainComponents/MessageContainer.tsx +4 -2
  319. package/src/components/MainComponents/MessageList.tsx +175 -28
  320. package/src/components/MainComponents/ReduxWrapper.tsx +19 -9
  321. package/src/components/MainComponents/SystemMessage.tsx +38 -26
  322. package/src/components/MessageBubble/Message.tsx +91 -62
  323. package/src/components/MessageBubble/MessageInteractions.tsx +98 -29
  324. package/src/components/Modals/AttachSheet/AttachSheet.tsx +17 -3
  325. package/src/components/Modals/FilePreviewModal/DocumentViewer.tsx +93 -0
  326. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +152 -25
  327. package/src/components/Modals/FilePreviewModal/PdfView.tsx +32 -4
  328. package/src/components/Modals/Modal/Modal.tsx +4 -1
  329. package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +70 -58
  330. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +19 -15
  331. package/src/components/Modals/styledModalComponents.tsx +4 -9
  332. package/src/components/styled/MediaFilePreview.tsx +46 -26
  333. package/src/components/styled/MessageImage.tsx +58 -13
  334. package/src/components/styled/NewMessageLabel.tsx +8 -5
  335. package/src/components/styled/SendInput.tsx +64 -29
  336. package/src/components/styled/StyledInputComponents/MediaComponents.tsx +15 -5
  337. package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +7 -2
  338. package/src/components/styled/UnsupportedType.tsx +7 -1
  339. package/src/components/styled/VideoMessage.tsx +59 -11
  340. package/src/context/MessageNotificationContext.tsx +8 -8
  341. package/src/context/xmppProvider.tsx +247 -30
  342. package/src/helpers/chatAutoEnterer.ts +2 -8
  343. package/src/helpers/historyPreloadScheduler.ts +4 -1
  344. package/src/helpers/insertMessageWithDelimiter.ts +22 -15
  345. package/src/helpers/keyboardLayout.ts +18 -0
  346. package/src/helpers/mediaDimensions.ts +47 -0
  347. package/src/helpers/normalizeRoomJid.ts +6 -0
  348. package/src/hooks/useChatRoomFocus.ts +95 -0
  349. package/src/hooks/useHeapSender.tsx +2 -1
  350. package/src/hooks/useLogout.tsx +3 -3
  351. package/src/hooks/usePushNotifications.ts +21 -8
  352. package/src/hooks/useRoomState.tsx +4 -0
  353. package/src/hooks/useSendMessage.tsx +258 -13
  354. package/src/hooks/useUnreadMessagesCounter.ts +13 -16
  355. package/src/main.ts +1 -0
  356. package/src/networking/api-requests/auth.api.ts +55 -1
  357. package/src/networking/apiClient.ts +2 -1
  358. package/src/networking/outboundQueue.ts +98 -0
  359. package/src/networking/xmpp/createTimeoutPromise.xmpp.ts +5 -1
  360. package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +11 -13
  361. package/src/networking/xmpp/getRoomsPaged.xmpp.ts +27 -3
  362. package/src/networking/xmpp/presenceInRoom.xmpp.ts +24 -9
  363. package/src/networking/xmpp/sendTextMessage.xmpp.ts +2 -1
  364. package/src/networking/xmppClient.ts +317 -43
  365. package/src/roomStore/Middleware/unreadMidlleware.tsx +23 -5
  366. package/src/roomStore/roomsSlice.ts +177 -27
  367. package/src/types/models/media.model.ts +3 -0
  368. package/src/types/models/xmpp.model.ts +2 -1
  369. package/src/types/types.ts +15 -0
  370. package/src/utils/installPromiseRejectionTracker.ts +91 -0
  371. package/src/utils/resendMessage.ts +2 -1
@@ -38,7 +38,8 @@ export const useHeapSender = (client: XmppClient | null) => {
38
38
  !!msg.isReply,
39
39
  msg.showInChannel === 'true',
40
40
  msg.mainMessage || '',
41
- msg.langSource
41
+ msg.langSource,
42
+ msg.id
42
43
  );
43
44
  } else {
44
45
  await client.sendMessage(
@@ -49,7 +49,7 @@ const logoutService = {
49
49
  performLogout: async (): Promise<void> => {
50
50
  // 0. Flush lastViewedTimestamp to the server's private store BEFORE
51
51
  // we close XMPP. Only rooms with no outstanding unread (plus the
52
- // active room) get their entries updated — rooms with unread
52
+ // visible room) get their entries updated — rooms with unread
53
53
  // keep their old marker so the next login still surfaces those
54
54
  // messages as unread. Without this, an active-room view at
55
55
  // logout would still appear unread on next login because we
@@ -58,11 +58,11 @@ const logoutService = {
58
58
  const state = store.getState();
59
59
  const client = (state.chatSettingStore as any)?.client;
60
60
  const rooms = state.rooms?.rooms;
61
- const activeRoomJID = state.rooms?.activeRoomJID || null;
61
+ const visibleRoomJID = state.rooms?.visibleRoomJID || null;
62
62
  if (client?.flushLastViewedToPrivateStoreStanza) {
63
63
  await Promise.race([
64
64
  client.flushLastViewedToPrivateStoreStanza(rooms, {
65
- activeRoomJID,
65
+ visibleRoomJID,
66
66
  onlyIfNoUnread: true,
67
67
  }),
68
68
  new Promise((res) => setTimeout(res, 2000)),
@@ -51,7 +51,13 @@ export function usePushNotifications() {
51
51
  };
52
52
 
53
53
  useEffect(() => {
54
- initToken();
54
+ // initToken is async — `initToken()` without `.catch` leaves any
55
+ // rejection unhandled (showed as `Uncaught (in promise, id: X)` red
56
+ // screen in dev). The inner try/catch covers most paths but any
57
+ // synchronous throw before the try-block ran would still leak.
58
+ initToken().catch((err) =>
59
+ console.warn('[usePushNotifications] initToken rejected', err)
60
+ );
55
61
 
56
62
  const unsubscribeForeground = onForegroundMessage((message) => {
57
63
  setNotification(message);
@@ -78,13 +84,20 @@ export function usePushNotifications() {
78
84
  handleNotificationPress(message);
79
85
  });
80
86
 
81
- getInitialNotification().then((message) => {
82
- if (message) {
83
- console.log('[usePushNotifications] Initial notification:', JSON.stringify(message, null, 2));
84
- setNotification(message);
85
- handleNotificationPress(message);
86
- }
87
- });
87
+ getInitialNotification()
88
+ .then((message) => {
89
+ if (message) {
90
+ console.log('[usePushNotifications] Initial notification:', JSON.stringify(message, null, 2));
91
+ setNotification(message);
92
+ handleNotificationPress(message);
93
+ }
94
+ })
95
+ .catch((err) =>
96
+ console.warn(
97
+ '[usePushNotifications] getInitialNotification failed',
98
+ err
99
+ )
100
+ );
88
101
 
89
102
  return () => {
90
103
  unsubscribeForeground();
@@ -12,6 +12,9 @@ export const useRoomState = (roomJID?: string) => {
12
12
  const activeRoomJID = useSelector(
13
13
  (state: RootState) => state.rooms.activeRoomJID
14
14
  );
15
+ const visibleRoomJID = useSelector(
16
+ (state: RootState) => state.rooms.visibleRoomJID
17
+ );
15
18
  const editAction = useSelector((state: RootState) => state.rooms.editAction);
16
19
  const globalLoading = useSelector(
17
20
  (state: RootState) => state.rooms.isLoading
@@ -37,6 +40,7 @@ export const useRoomState = (roomJID?: string) => {
37
40
  room,
38
41
  roomsList,
39
42
  activeRoomJID,
43
+ visibleRoomJID,
40
44
  editAction,
41
45
  globalLoading,
42
46
  loadingText,
@@ -1,18 +1,30 @@
1
1
  import { useCallback } from 'react';
2
+ import { Platform } from 'react-native';
2
3
  import { v4 as uuidv4 } from 'uuid';
3
4
  import { useXmppClient } from '../context/xmppProvider';
4
- import { useDispatch, useSelector } from 'react-redux';
5
+ import { useDispatch, useSelector, useStore } from 'react-redux';
5
6
  import { addRoomMessage, setEditAction } from '../roomStore/roomsSlice';
6
7
  import {
7
8
  addMessageToHeap,
8
9
  clearMessageFailure,
9
10
  markMessageFailed,
10
11
  } from '../roomStore/roomHeapSlice';
11
- import { uploadFile } from '../networking/api-requests/auth.api';
12
- import { RootState } from '../roomStore';
12
+ import { uploadFileViaFetch } from '../networking/api-requests/auth.api';
13
+ import { enqueueOutboundSend } from '../networking/outboundQueue';
14
+ import { RootState, store } from '../roomStore';
15
+ import { getGlobalXmppClient } from '../utils/clientRegistry';
13
16
  import { useEventHandlers } from './useEventHandlers';
14
17
  import type { IConfig, IMessage } from '../types/types';
15
18
 
19
+ // Watchdog: if a message stays "pending" (no server echo) for this
20
+ // long after the optimistic dispatch, mark it failed so the bubble
21
+ // flips out of the "sending..." state. Covers the silent-failure
22
+ // case (e.g. device offline before the message ever made it to the
23
+ // XMPP socket) — bug #18. Tuned generously so a brief network blip
24
+ // followed by reconnect within 30s still resolves naturally via the
25
+ // server echo.
26
+ const PENDING_WATCHDOG_MS = 30_000;
27
+
16
28
  // Monotonic counter for stanza ids. Bumped on each send within a single
17
29
  // process. Two rapid sends in the same millisecond used to collide on
18
30
  // `send-text-message-${Date.now()}`; that collision made
@@ -23,9 +35,18 @@ let __sendIdSeq = 0;
23
35
  const nextStanzaId = (prefix: string): string =>
24
36
  `${prefix}-${Date.now()}-${(__sendIdSeq = (__sendIdSeq + 1) >>> 0)}`;
25
37
 
38
+ // Hard client-side cap on a single upload. The backend rejects oversized
39
+ // bodies with HTTP 413; SendInput blocks oversized files at pick time,
40
+ // and this mirrors that limit on every send path (including retries).
41
+ const MAX_MEDIA_BYTES = 50 * 1024 * 1024;
42
+
26
43
  export const useSendMessage = (_configOverride?: IConfig) => {
27
44
  const { client } = useXmppClient();
28
45
  const dispatch = useDispatch();
46
+ // useStore gives us imperative getState() access for the watchdog —
47
+ // peek at the message's current pending/failed state from inside a
48
+ // setTimeout callback without re-rendering on every redux change.
49
+ const reduxStore = useStore<RootState>();
29
50
 
30
51
  // Split selectors so each returns a primitive/stable reference — the
31
52
  // single-object selector above caused a "returned a different result
@@ -120,16 +141,85 @@ export const useSendMessage = (_configOverride?: IConfig) => {
120
141
  );
121
142
  }
122
143
 
144
+ // Silent-failure watchdog (bug #18). If no echo lands within
145
+ // PENDING_WATCHDOG_MS, flip the bubble to "failed → tap to
146
+ // retry". We check at fire-time whether the message is still
147
+ // pending and not already marked failed by the catch path.
148
+ const watchdogTimer = setTimeout(() => {
149
+ const state = reduxStore.getState();
150
+ const roomMsgs = state.rooms?.rooms?.[activeRoomJID]?.messages || [];
151
+ const stillPending = roomMsgs.find(
152
+ (m: any) => m.id === optimisticId && m.pending
153
+ );
154
+ const alreadyFailed = state.roomHeapSlice?.failedMessages?.[optimisticId];
155
+ if (stillPending && !alreadyFailed) {
156
+ console.warn(
157
+ `Send watchdog fired — message ${optimisticId} stuck pending > ${PENDING_WATCHDOG_MS}ms; marking failed`
158
+ );
159
+ dispatch(
160
+ markMessageFailed({
161
+ kind: 'text',
162
+ id: optimisticId,
163
+ roomJID: activeRoomJID,
164
+ body: message,
165
+ isReply,
166
+ isChecked,
167
+ mainMessage,
168
+ })
169
+ );
170
+ handleMessageFailed({
171
+ message,
172
+ roomJID: activeRoomJID,
173
+ error: new Error('Send timed out (no server echo)'),
174
+ messageType: 'text',
175
+ });
176
+ }
177
+ }, PENDING_WATCHDOG_MS);
178
+
123
179
  try {
124
- if (!client) {
125
- throw new Error('No XMPP client');
180
+
181
+ const effectiveClient: any =
182
+ client ||
183
+ [
184
+ getGlobalXmppClient(),
185
+ store.getState()?.chatSettingStore?.client,
186
+ ].find((c: any) => c && c.status === 'online');
187
+
188
+ if (!effectiveClient) {
189
+ const anyClient: any =
190
+ client ||
191
+ getGlobalXmppClient() ||
192
+ store.getState()?.chatSettingStore?.client;
193
+ try {
194
+ anyClient?.forceReconnect?.();
195
+ } catch {}
196
+ enqueueOutboundSend({
197
+ optimisticId,
198
+ roomJID: activeRoomJID,
199
+ enqueuedAt: Date.now(),
200
+ send: (c) =>
201
+ c.sendMessage(
202
+ activeRoomJID,
203
+ user.firstName,
204
+ user.lastName,
205
+ '',
206
+ user.walletAddress,
207
+ message,
208
+ '',
209
+ isReply || false,
210
+ isChecked || false,
211
+ mainMessage || '',
212
+ optimisticId
213
+ ),
214
+ });
215
+ return;
126
216
  }
127
217
  // Pass the optimistic id as the stanza id so the server echoes
128
218
  // it back with the same value — the reducer's dedupe lookup
129
219
  // matches and the bubble flips from pending → delivered in-place
130
220
  // (instead of rendering two copies, which is what happens when
131
221
  // ids don't match).
132
- client.sendMessage(
222
+ effectiveClient.sendMessage(
133
223
  activeRoomJID,
134
224
  user.firstName,
135
225
  user.lastName,
@@ -149,6 +239,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
149
239
  messageType: 'text',
150
240
  });
151
241
  } catch (error) {
242
+ clearTimeout(watchdogTimer);
152
243
  dispatch(
153
244
  markMessageFailed({
154
245
  kind: 'text',
@@ -168,7 +259,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
168
259
  });
169
260
  }
170
261
  },
171
- [editAction, client, user, dispatch, handleMessageSent, handleMessageEdited, handleMessageFailed]
262
+ [editAction, client, user, dispatch, handleMessageSent, handleMessageEdited, handleMessageFailed, reduxStore]
172
263
  );
173
264
 
174
265
  const sendMedia = useCallback(
@@ -183,6 +274,36 @@ export const useSendMessage = (_configOverride?: IConfig) => {
183
274
  ) => {
184
275
  client?.onCriticalSend?.(activeRoomJID);
185
276
 
277
+ // Defensive 50 MB guard on every send path (SendInput blocks it at
278
+ // pick time, but retries replay the saved payload straight here).
279
+ if (typeof data?.size === 'number' && data.size > MAX_MEDIA_BYTES) {
280
+ console.warn('media exceeds 50MB cap — not uploading', {
281
+ name: data?.name,
282
+ size: data?.size,
283
+ });
284
+ if (existingId) {
285
+ dispatch(
286
+ markMessageFailed({
287
+ kind: 'media',
288
+ id: existingId,
289
+ roomJID: activeRoomJID,
290
+ data,
291
+ type,
292
+ isReply,
293
+ isChecked,
294
+ mainMessage,
295
+ })
296
+ );
297
+ }
298
+ handleMessageFailed({
299
+ message: 'media',
300
+ roomJID: activeRoomJID,
301
+ error: new Error('File exceeds the 50 MB upload limit'),
302
+ messageType: 'media',
303
+ });
304
+ return;
305
+ }
306
+
186
307
  const id = existingId || `send-media-message:${uuidv4()}`;
187
308
  const optimisticTimestamp = Date.now();
188
309
  const optimisticDate = new Date(optimisticTimestamp).toISOString();
@@ -245,11 +366,94 @@ export const useSendMessage = (_configOverride?: IConfig) => {
245
366
  );
246
367
  }
247
368
 
248
- try {
249
- const mediaData = new FormData();
250
- mediaData.append('files', data);
369
+ // Silent-failure watchdog for media-send (bug #18). Same shape
370
+ // as the text path: if the optimistic bubble never gets the echo
371
+ // (e.g. upload completed but XMPP send is buffered offline), flip
372
+ // to failed → tap to retry.
373
+ const mediaWatchdog = setTimeout(() => {
374
+ const state = reduxStore.getState();
375
+ const roomMsgs = state.rooms?.rooms?.[activeRoomJID]?.messages || [];
376
+ const stillPending = roomMsgs.find(
377
+ (m: any) => m.id === id && m.pending
378
+ );
379
+ const alreadyFailed = state.roomHeapSlice?.failedMessages?.[id];
380
+ if (stillPending && !alreadyFailed) {
381
+ console.warn(
382
+ `Media-send watchdog fired — ${id} stuck pending > ${PENDING_WATCHDOG_MS}ms; marking failed`
383
+ );
384
+ dispatch(
385
+ markMessageFailed({
386
+ kind: 'media',
387
+ id,
388
+ roomJID: activeRoomJID,
389
+ data,
390
+ type,
391
+ isReply,
392
+ isChecked,
393
+ mainMessage,
394
+ })
395
+ );
396
+ handleMessageFailed({
397
+ message: 'media',
398
+ roomJID: activeRoomJID,
399
+ error: new Error('Media send timed out (no server echo)'),
400
+ messageType: 'media',
401
+ });
402
+ }
403
+ }, PENDING_WATCHDOG_MS);
251
404
 
252
- const response = await uploadFile(mediaData);
405
+ // Help RN's FormData polyfill build a proper multipart/file part
406
+ // (instead of serialising the JS object as JSON). On iOS the
407
+ // picker can return ph:// or assets-library:// URIs for some
408
+ // legacy library items — those can't be read as files. Coerce
409
+ // to a file:// scheme when possible so the body is a real blob.
410
+ const fileBlob = {
411
+ uri:
412
+ typeof data?.uri === 'string'
413
+ ? data.uri.replace(/^assets-library:\/\//, 'file://')
414
+ : data?.uri,
415
+ type:
416
+ data?.type ||
417
+ data?.mimeType ||
418
+ type ||
419
+ 'application/octet-stream',
420
+ name: data?.name || data?.fileName || `media_${Date.now()}`,
421
+ };
422
+
423
+ // Mirror the web client: a single multipart POST to /files/ with
424
+ // the file under the plural "files" field. We send it via fetch
425
+ // (not axios) because RN's fetch sets the multipart boundary on the
426
+ // Content-Type header correctly. The previous axios fallback omitted
427
+ // a valid boundary, so the server mis-parsed one file as many and
428
+ // rejected the request with HTTP 413 "TOO_MANY_FILES". The only
429
+ // retry is the documented singular-"file" fallback for deployments
430
+ // that 500 on the plural field (bug #10).
431
+ const tryUpload = async () => {
432
+ const fd = new FormData();
433
+ fd.append('files', fileBlob as any);
434
+ try {
435
+ return await uploadFileViaFetch(fd);
436
+ } catch (err: any) {
437
+ if (err?.response?.status === 500) {
438
+ console.warn(
439
+ 'upload "files" field returned 500 — retrying with "file" (singular)',
440
+ { name: fileBlob.name, type: fileBlob.type }
441
+ );
442
+ const fd2 = new FormData();
443
+ fd2.append('file', fileBlob as any);
444
+ return await uploadFileViaFetch(fd2);
445
+ }
446
+ throw err;
447
+ }
448
+ };
449
+
450
+ try {
451
+ const response = await tryUpload();
452
+ // Upload succeeded — the stanza is now in flight. If the
453
+ // server echo arrives within the watchdog window the bubble
454
+ // flips normally; if not, the watchdog still fires and marks
455
+ // it failed. We don't clear the timer on upload success because
456
+ // the XMPP send could still fail silently.
253
457
 
254
458
  for (const item of response.data.results) {
255
459
  const messagePayload = {
@@ -281,7 +485,34 @@ export const useSendMessage = (_configOverride?: IConfig) => {
281
485
  // Stanza id == placeholder id so the MUC echo's outer
282
486
  // <message id="..."> matches xmppId on the placeholder and
283
487
  // insertMessageWithDelimiter merges in place + flips pending.
284
- client?.sendMediaMessageStanza(activeRoomJID, messagePayload, id);
488
+ const effectiveMediaClient: any =
489
+ client ||
490
+ [
491
+ getGlobalXmppClient(),
492
+ store.getState()?.chatSettingStore?.client,
493
+ ].find((c: any) => c && c.status === 'online');
494
+ if (effectiveMediaClient) {
495
+ effectiveMediaClient.sendMediaMessageStanza(
496
+ activeRoomJID,
497
+ messagePayload,
498
+ id
499
+ );
500
+ } else {
501
+ const anyMediaClient: any =
502
+ client ||
503
+ getGlobalXmppClient() ||
504
+ store.getState()?.chatSettingStore?.client;
505
+ try {
506
+ anyMediaClient?.forceReconnect?.();
507
+ } catch {}
508
+ enqueueOutboundSend({
509
+ optimisticId: id,
510
+ roomJID: activeRoomJID,
511
+ enqueuedAt: Date.now(),
512
+ send: (c) =>
513
+ c.sendMediaMessageStanza(activeRoomJID, messagePayload, id),
514
+ });
515
+ }
285
516
  }
286
517
 
287
518
  await handleMessageSent({
@@ -300,16 +531,30 @@ export const useSendMessage = (_configOverride?: IConfig) => {
300
531
  },
301
532
  });
302
533
  } catch (error: any) {
534
+ // Upload (or stanza send) threw an explicit error. Clear the
535
+ // watchdog so it doesn't double-fire `markMessageFailed`.
536
+ clearTimeout(mediaWatchdog);
303
537
  // Surface the real server payload so we can see why the upload
304
538
  // was rejected (axios collapses the message to "Request failed
305
539
  // with status code N"; the actual reason lives in
306
540
  // `error.response.data`).
541
+ const uriStr = typeof data?.uri === 'string' ? data.uri : '';
542
+ const uriScheme = uriStr.match(/^([a-z]+):/i)?.[1] ?? 'unknown';
307
543
  console.error('upload failed', {
308
544
  status: error?.response?.status,
309
545
  statusText: error?.response?.statusText,
310
546
  serverBody: error?.response?.data,
311
547
  requestUrl: error?.config?.url,
312
548
  axiosMessage: error?.message,
549
+ axiosCode: error?.code,
550
+ axiosCauseMessage: error?.cause?.message,
551
+ uri: uriStr,
552
+ uriScheme,
553
+ mime: fileBlob.type,
554
+ fileSizeBytes: data?.size ?? null,
555
+ fileName: fileBlob.name,
556
+ platformOS: Platform.OS,
557
+ platformVersion: Platform.Version,
313
558
  });
314
559
  dispatch(
315
560
  markMessageFailed({
@@ -331,7 +576,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
331
576
  });
332
577
  }
333
578
  },
334
- [client, config, user, dispatch, handleMessageSent, handleMessageFailed]
579
+ [client, config, user, dispatch, handleMessageSent, handleMessageFailed, reduxStore]
335
580
  );
336
581
 
337
582
  // Retry a previously-failed send by replaying the saved payload from
@@ -1,6 +1,6 @@
1
1
  import { useSyncExternalStore } from 'react';
2
2
  import { IRoom } from '../types/types';
3
- import { RootState, store } from '../roomStore';
3
+ import { store } from '../roomStore';
4
4
 
5
5
  interface UnreadMessagesMap {
6
6
  [roomJid: string]: number;
@@ -13,21 +13,18 @@ interface UnreadMessagesStats {
13
13
  }
14
14
 
15
15
  export const useUnreadMessagesCounter = (): UnreadMessagesStats => {
16
- const subscribe = (callback: () => void) => {
17
- const unsubscribe = store.subscribe(() => {
18
- const state: RootState = store.getState();
19
- const rooms = state.rooms?.rooms;
20
-
21
- if (rooms) {
22
- Object.entries(rooms).forEach(([roomJid, room]: [string, IRoom]) => {
23
- if (room.unreadMessages !== undefined) {
24
- callback();
25
- }
26
- });
27
- }
28
- });
29
- return unsubscribe;
30
- };
16
+ // Notify React on EVERY store change and let useSyncExternalStore's
17
+ // snapshot comparison (Object.is on the `rooms` reference) decide
18
+ // whether to re-render. The previous implementation only fired the
19
+ // callback while iterating rooms that already had `unreadMessages`
20
+ // defined — so when `rooms` became empty (logout, or the last room
21
+ // removed) the loop body never ran, the callback never fired, and the
22
+ // hook never re-rendered: a consumer's badge stayed stuck at its last
23
+ // non-zero count after logout. (It's also cheaper — one callback per
24
+ // change instead of one per unread room. Redux Toolkit keeps the
25
+ // `rooms` slice reference stable across actions that don't touch it,
26
+ // so non-rooms dispatches still don't trigger a re-render.)
27
+ const subscribe = (callback: () => void) => store.subscribe(callback);
31
28
 
32
29
  const rooms = useSyncExternalStore(
33
30
  subscribe,
package/src/main.ts CHANGED
@@ -28,6 +28,7 @@ export { XmppProvider } from './context/xmppProvider';
28
28
 
29
29
  // Hooks that consumers usually need (badge counts, logout, push, etc.).
30
30
  export { useUnread } from './hooks/useUnreadMessagesCounter';
31
+ export { useChatRoomFocus } from './hooks/useChatRoomFocus';
31
32
  export { logoutService } from './hooks/useLogout';
32
33
  export { useQRCodeChat, handleQRChatId } from './hooks/useQRCodeChatHandler';
33
34
  export { resendMessage } from './utils/resendMessage';
@@ -8,8 +8,9 @@ import { User } from '../../types/types';
8
8
  // } from 'firebase/auth';
9
9
  // import { app } from '../../../firebase-config';
10
10
 
11
- import http, { getCurrentAppToken } from '../apiClient';
11
+ import http, { getCurrentAppToken, getCurrentBaseURL } from '../apiClient';
12
12
  import { store } from '../../roomStore';
13
+ import { pushLog } from '../../utils/devLogger';
13
14
 
14
15
  // login functions
15
16
  export async function loginEmail(email: string, password: string) {
@@ -142,3 +143,56 @@ export function uploadFile(formData: FormData) {
142
143
  },
143
144
  });
144
145
  }
146
+
147
+ export async function uploadFileViaFetch(formData: FormData): Promise<{ data: any }> {
148
+ const token = store.getState().chatSettingStore?.user?.token ?? '';
149
+ const baseUrl = getCurrentBaseURL();
150
+ const url = `${baseUrl.replace(/\/$/, '')}/files/`;
151
+
152
+ pushLog('http', `→ POST ${url} (fetch)`, {
153
+ headers: { Authorization: token ? token.slice(0, 16) + '…' : '[empty]', Accept: '*/*' },
154
+ });
155
+
156
+ let res: Response;
157
+ try {
158
+ res = await fetch(url, {
159
+ method: 'POST',
160
+ headers: {
161
+ Authorization: token,
162
+ Accept: '*/*',
163
+ },
164
+ body: formData as any,
165
+ });
166
+ } catch (e: any) {
167
+ pushLog('http', `← ERR fetch /files/`, {
168
+ name: e?.name,
169
+ message: e?.message,
170
+ stack: e?.stack,
171
+ });
172
+ const err: any = new Error(e?.message || 'Network request failed');
173
+ err.code = 'ERR_NETWORK';
174
+ err.cause = e;
175
+ err.config = { url: '/files/' };
176
+ throw err;
177
+ }
178
+
179
+ if (!res.ok) {
180
+ let body: any = null;
181
+ try {
182
+ body = await res.json();
183
+ } catch {
184
+ try { body = await res.text(); } catch { body = null; }
185
+ }
186
+ pushLog('http', `← ${res.status} POST /files/ (fetch)`, body);
187
+ const err: any = new Error(`Upload failed: ${res.status}`);
188
+ err.response = { status: res.status, statusText: res.statusText, data: body };
189
+ err.config = { url: '/files/' };
190
+ throw err;
191
+ }
192
+
193
+ const data = await res.json();
194
+ pushLog('http', `← ${res.status} POST /files/ (fetch)`, {
195
+ resultsCount: Array.isArray(data?.results) ? data.results.length : 'n/a',
196
+ });
197
+ return { data };
198
+ }
@@ -171,7 +171,8 @@ http.interceptors.response.use(
171
171
  isRefreshing = true;
172
172
  try {
173
173
  const tokens = await refresh();
174
- console.log('tokens', tokens);
174
+ // (was: console.log('tokens', tokens) — dumped the full response
175
+ // incl. access/refresh/ws tokens on every refresh; removed.)
175
176
  isRefreshing = false;
176
177
  originalRequest.headers.Authorization = tokens.data.token;
177
178
  processQueue(tokens.data.token);