@ethora/chat-component-rn 26.5.21 → 26.6.11

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 (372) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +3 -3
  3. package/index.js +1 -1
  4. package/lib/commonjs/components/MainComponents/ChatHeader.js +20 -8
  5. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  6. package/lib/commonjs/components/MainComponents/ChatWrapper.js +17 -0
  7. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  8. package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js +62 -0
  9. package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js.map +1 -0
  10. package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js +253 -0
  11. package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js.map +1 -0
  12. package/lib/commonjs/components/MainComponents/MediaMessage.js +7 -1
  13. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  14. package/lib/commonjs/components/MainComponents/RoomList.js +23 -9
  15. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  16. package/lib/commonjs/components/MessageBubble/Message.js +72 -11
  17. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  18. package/lib/commonjs/components/MessageBubble/MessageTranslate.js +160 -0
  19. package/lib/commonjs/components/MessageBubble/MessageTranslate.js.map +1 -0
  20. package/lib/commonjs/components/MessageBubble/TranslatedMessageBody.js +59 -0
  21. package/lib/commonjs/components/MessageBubble/TranslatedMessageBody.js.map +1 -0
  22. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +3 -3
  23. package/lib/commonjs/components/UsersList/UsersList.js +3 -1
  24. package/lib/commonjs/components/UsersList/UsersList.js.map +1 -1
  25. package/lib/commonjs/components/VideoCalls/CallButtons.js +159 -0
  26. package/lib/commonjs/components/VideoCalls/CallButtons.js.map +1 -0
  27. package/lib/commonjs/components/VideoCalls/CallIcons.js +328 -0
  28. package/lib/commonjs/components/VideoCalls/CallIcons.js.map +1 -0
  29. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +550 -0
  30. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -0
  31. package/lib/commonjs/components/VideoCalls/VideoCallSession.js +636 -0
  32. package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -0
  33. package/lib/commonjs/components/VideoCalls/livekitRuntime.js +91 -0
  34. package/lib/commonjs/components/VideoCalls/livekitRuntime.js.map +1 -0
  35. package/lib/commonjs/components/VideoCalls/useCallKeep.js +215 -0
  36. package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -0
  37. package/lib/commonjs/components/styled/AudioMessage.js +91 -33
  38. package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
  39. package/lib/commonjs/components/styled/RoomListComponents/index.js +13 -1
  40. package/lib/commonjs/components/styled/RoomListComponents/index.js.map +1 -1
  41. package/lib/commonjs/components/styled/SendInput.js +83 -49
  42. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  43. package/lib/commonjs/components/styled/StyledComponents.js +9 -4
  44. package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
  45. package/lib/commonjs/components/styled/StyledInputComponents/Composing.js +2 -0
  46. package/lib/commonjs/components/styled/StyledInputComponents/Composing.js.map +1 -1
  47. package/lib/commonjs/components/styled/VideoMessage.js +110 -26
  48. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  49. package/lib/commonjs/context/xmppProvider.js +10 -3
  50. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  51. package/lib/commonjs/helpers/callLogMessage.js +162 -0
  52. package/lib/commonjs/helpers/callLogMessage.js.map +1 -0
  53. package/lib/commonjs/helpers/callPush.js +61 -0
  54. package/lib/commonjs/helpers/callPush.js.map +1 -0
  55. package/lib/commonjs/helpers/constants/LANGUAGE_OPTIONS.js +24 -12
  56. package/lib/commonjs/helpers/constants/LANGUAGE_OPTIONS.js.map +1 -1
  57. package/lib/commonjs/helpers/createUserNameFromSetUser.js +51 -2
  58. package/lib/commonjs/helpers/createUserNameFromSetUser.js.map +1 -1
  59. package/lib/commonjs/helpers/getDataFromXml.js +19 -1
  60. package/lib/commonjs/helpers/getDataFromXml.js.map +1 -1
  61. package/lib/commonjs/helpers/incomingCallFromPush.js +74 -0
  62. package/lib/commonjs/helpers/incomingCallFromPush.js.map +1 -0
  63. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +13 -1
  64. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  65. package/lib/commonjs/helpers/isUnresolvedSenderId.js +32 -0
  66. package/lib/commonjs/helpers/isUnresolvedSenderId.js.map +1 -0
  67. package/lib/commonjs/hooks/useChatSettingState.js +2 -0
  68. package/lib/commonjs/hooks/useChatSettingState.js.map +1 -1
  69. package/lib/commonjs/hooks/useMessageTranslation.js +51 -0
  70. package/lib/commonjs/hooks/useMessageTranslation.js.map +1 -0
  71. package/lib/commonjs/hooks/usePushNotifications.js +13 -3
  72. package/lib/commonjs/hooks/usePushNotifications.js.map +1 -1
  73. package/lib/commonjs/hooks/useSendMessage.js +14 -4
  74. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  75. package/lib/commonjs/i18n/strings.js +1308 -0
  76. package/lib/commonjs/i18n/strings.js.map +1 -0
  77. package/lib/commonjs/i18n/useT.js +60 -0
  78. package/lib/commonjs/i18n/useT.js.map +1 -0
  79. package/lib/commonjs/main.js +44 -0
  80. package/lib/commonjs/main.js.map +1 -1
  81. package/lib/commonjs/networking/api-requests/auth.api.js +81 -52
  82. package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
  83. package/lib/commonjs/networking/api-requests/push.api.js +34 -5
  84. package/lib/commonjs/networking/api-requests/push.api.js.map +1 -1
  85. package/lib/commonjs/networking/api-requests/rooms.api.js +108 -0
  86. package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
  87. package/lib/commonjs/networking/callTokenStanza.js +531 -0
  88. package/lib/commonjs/networking/callTokenStanza.js.map +1 -0
  89. package/lib/commonjs/networking/outboundQueue.js.map +1 -1
  90. package/lib/commonjs/networking/stanzaHandlers.js +75 -8
  91. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  92. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +47 -11
  93. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  94. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js +2 -1
  95. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  96. package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +42 -5
  97. package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
  98. package/lib/commonjs/networking/xmppClient.js +78 -16
  99. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  100. package/lib/commonjs/roomStore/callSlice.js +144 -0
  101. package/lib/commonjs/roomStore/callSlice.js.map +1 -0
  102. package/lib/commonjs/roomStore/chatSettingsSlice.js +8 -2
  103. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  104. package/lib/commonjs/roomStore/index.js +7 -1
  105. package/lib/commonjs/roomStore/index.js.map +1 -1
  106. package/lib/commonjs/roomStore/persistence.js +69 -5
  107. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  108. package/lib/commonjs/roomStore/roomsSlice.js +136 -6
  109. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  110. package/lib/commonjs/utils/translateModePolicy.js +33 -0
  111. package/lib/commonjs/utils/translateModePolicy.js.map +1 -0
  112. package/lib/module/components/MainComponents/ChatHeader.js +20 -8
  113. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  114. package/lib/module/components/MainComponents/ChatWrapper.js +17 -0
  115. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  116. package/lib/module/components/MainComponents/LanguageSelectorButton.js +57 -0
  117. package/lib/module/components/MainComponents/LanguageSelectorButton.js.map +1 -0
  118. package/lib/module/components/MainComponents/LanguageSelectorModal.js +246 -0
  119. package/lib/module/components/MainComponents/LanguageSelectorModal.js.map +1 -0
  120. package/lib/module/components/MainComponents/MediaMessage.js +7 -1
  121. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  122. package/lib/module/components/MainComponents/RoomList.js +23 -9
  123. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  124. package/lib/module/components/MessageBubble/Message.js +73 -12
  125. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  126. package/lib/module/components/MessageBubble/MessageTranslate.js +155 -0
  127. package/lib/module/components/MessageBubble/MessageTranslate.js.map +1 -0
  128. package/lib/module/components/MessageBubble/TranslatedMessageBody.js +53 -0
  129. package/lib/module/components/MessageBubble/TranslatedMessageBody.js.map +1 -0
  130. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +3 -3
  131. package/lib/module/components/UsersList/UsersList.js +3 -1
  132. package/lib/module/components/UsersList/UsersList.js.map +1 -1
  133. package/lib/module/components/VideoCalls/CallButtons.js +154 -0
  134. package/lib/module/components/VideoCalls/CallButtons.js.map +1 -0
  135. package/lib/module/components/VideoCalls/CallIcons.js +309 -0
  136. package/lib/module/components/VideoCalls/CallIcons.js.map +1 -0
  137. package/lib/module/components/VideoCalls/VideoCallOverlay.js +544 -0
  138. package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -0
  139. package/lib/module/components/VideoCalls/VideoCallSession.js +630 -0
  140. package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -0
  141. package/lib/module/components/VideoCalls/livekitRuntime.js +83 -0
  142. package/lib/module/components/VideoCalls/livekitRuntime.js.map +1 -0
  143. package/lib/module/components/VideoCalls/useCallKeep.js +210 -0
  144. package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -0
  145. package/lib/module/components/styled/AudioMessage.js +91 -33
  146. package/lib/module/components/styled/AudioMessage.js.map +1 -1
  147. package/lib/module/components/styled/RoomListComponents/index.js +13 -1
  148. package/lib/module/components/styled/RoomListComponents/index.js.map +1 -1
  149. package/lib/module/components/styled/SendInput.js +83 -49
  150. package/lib/module/components/styled/SendInput.js.map +1 -1
  151. package/lib/module/components/styled/StyledComponents.js +9 -4
  152. package/lib/module/components/styled/StyledComponents.js.map +1 -1
  153. package/lib/module/components/styled/StyledInputComponents/Composing.js +2 -0
  154. package/lib/module/components/styled/StyledInputComponents/Composing.js.map +1 -1
  155. package/lib/module/components/styled/VideoMessage.js +111 -27
  156. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  157. package/lib/module/context/xmppProvider.js +11 -4
  158. package/lib/module/context/xmppProvider.js.map +1 -1
  159. package/lib/module/helpers/callLogMessage.js +152 -0
  160. package/lib/module/helpers/callLogMessage.js.map +1 -0
  161. package/lib/module/helpers/callPush.js +55 -0
  162. package/lib/module/helpers/callPush.js.map +1 -0
  163. package/lib/module/helpers/constants/LANGUAGE_OPTIONS.js +24 -12
  164. package/lib/module/helpers/constants/LANGUAGE_OPTIONS.js.map +1 -1
  165. package/lib/module/helpers/createUserNameFromSetUser.js +49 -1
  166. package/lib/module/helpers/createUserNameFromSetUser.js.map +1 -1
  167. package/lib/module/helpers/getDataFromXml.js +20 -1
  168. package/lib/module/helpers/getDataFromXml.js.map +1 -1
  169. package/lib/module/helpers/incomingCallFromPush.js +70 -0
  170. package/lib/module/helpers/incomingCallFromPush.js.map +1 -0
  171. package/lib/module/helpers/insertMessageWithDelimiter.js +13 -1
  172. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  173. package/lib/module/helpers/isUnresolvedSenderId.js +27 -0
  174. package/lib/module/helpers/isUnresolvedSenderId.js.map +1 -0
  175. package/lib/module/hooks/useChatSettingState.js +2 -0
  176. package/lib/module/hooks/useChatSettingState.js.map +1 -1
  177. package/lib/module/hooks/useMessageTranslation.js +46 -0
  178. package/lib/module/hooks/useMessageTranslation.js.map +1 -0
  179. package/lib/module/hooks/usePushNotifications.js +13 -3
  180. package/lib/module/hooks/usePushNotifications.js.map +1 -1
  181. package/lib/module/hooks/useSendMessage.js +15 -5
  182. package/lib/module/hooks/useSendMessage.js.map +1 -1
  183. package/lib/module/i18n/strings.js +1300 -0
  184. package/lib/module/i18n/strings.js.map +1 -0
  185. package/lib/module/i18n/useT.js +55 -0
  186. package/lib/module/i18n/useT.js.map +1 -0
  187. package/lib/module/main.js +7 -1
  188. package/lib/module/main.js.map +1 -1
  189. package/lib/module/networking/api-requests/auth.api.js +80 -51
  190. package/lib/module/networking/api-requests/auth.api.js.map +1 -1
  191. package/lib/module/networking/api-requests/push.api.js +35 -5
  192. package/lib/module/networking/api-requests/push.api.js.map +1 -1
  193. package/lib/module/networking/api-requests/rooms.api.js +109 -1
  194. package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
  195. package/lib/module/networking/callTokenStanza.js +526 -0
  196. package/lib/module/networking/callTokenStanza.js.map +1 -0
  197. package/lib/module/networking/outboundQueue.js.map +1 -1
  198. package/lib/module/networking/stanzaHandlers.js +76 -9
  199. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  200. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +48 -11
  201. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  202. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js +1 -1
  203. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  204. package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +43 -5
  205. package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
  206. package/lib/module/networking/xmppClient.js +78 -16
  207. package/lib/module/networking/xmppClient.js.map +1 -1
  208. package/lib/module/roomStore/callSlice.js +130 -0
  209. package/lib/module/roomStore/callSlice.js.map +1 -0
  210. package/lib/module/roomStore/chatSettingsSlice.js +6 -1
  211. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  212. package/lib/module/roomStore/index.js +6 -1
  213. package/lib/module/roomStore/index.js.map +1 -1
  214. package/lib/module/roomStore/persistence.js +69 -5
  215. package/lib/module/roomStore/persistence.js.map +1 -1
  216. package/lib/module/roomStore/roomsSlice.js +134 -5
  217. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  218. package/lib/module/utils/translateModePolicy.js +27 -0
  219. package/lib/module/utils/translateModePolicy.js.map +1 -0
  220. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  221. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  222. package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts +12 -0
  223. package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts.map +1 -0
  224. package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts +31 -0
  225. package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts.map +1 -0
  226. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  227. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  228. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  229. package/lib/typescript/components/MessageBubble/MessageTranslate.d.ts +44 -0
  230. package/lib/typescript/components/MessageBubble/MessageTranslate.d.ts.map +1 -0
  231. package/lib/typescript/components/MessageBubble/TranslatedMessageBody.d.ts +24 -0
  232. package/lib/typescript/components/MessageBubble/TranslatedMessageBody.d.ts.map +1 -0
  233. package/lib/typescript/components/UsersList/UsersList.d.ts.map +1 -1
  234. package/lib/typescript/components/VideoCalls/CallButtons.d.ts +16 -0
  235. package/lib/typescript/components/VideoCalls/CallButtons.d.ts.map +1 -0
  236. package/lib/typescript/components/VideoCalls/CallIcons.d.ts +30 -0
  237. package/lib/typescript/components/VideoCalls/CallIcons.d.ts.map +1 -0
  238. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts +10 -0
  239. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -0
  240. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts +38 -0
  241. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -0
  242. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts +52 -0
  243. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts.map +1 -0
  244. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts +32 -0
  245. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -0
  246. package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
  247. package/lib/typescript/components/styled/RoomListComponents/index.d.ts.map +1 -1
  248. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  249. package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
  250. package/lib/typescript/components/styled/StyledInputComponents/Composing.d.ts.map +1 -1
  251. package/lib/typescript/components/styled/VideoMessage.d.ts +2 -0
  252. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  253. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  254. package/lib/typescript/helpers/callLogMessage.d.ts +34 -0
  255. package/lib/typescript/helpers/callLogMessage.d.ts.map +1 -0
  256. package/lib/typescript/helpers/callPush.d.ts +23 -0
  257. package/lib/typescript/helpers/callPush.d.ts.map +1 -0
  258. package/lib/typescript/helpers/constants/LANGUAGE_OPTIONS.d.ts +14 -0
  259. package/lib/typescript/helpers/constants/LANGUAGE_OPTIONS.d.ts.map +1 -1
  260. package/lib/typescript/helpers/createUserNameFromSetUser.d.ts +33 -1
  261. package/lib/typescript/helpers/createUserNameFromSetUser.d.ts.map +1 -1
  262. package/lib/typescript/helpers/getDataFromXml.d.ts.map +1 -1
  263. package/lib/typescript/helpers/incomingCallFromPush.d.ts +14 -0
  264. package/lib/typescript/helpers/incomingCallFromPush.d.ts.map +1 -0
  265. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  266. package/lib/typescript/helpers/isUnresolvedSenderId.d.ts +2 -0
  267. package/lib/typescript/helpers/isUnresolvedSenderId.d.ts.map +1 -0
  268. package/lib/typescript/hooks/useChatSettingState.d.ts +2 -1
  269. package/lib/typescript/hooks/useChatSettingState.d.ts.map +1 -1
  270. package/lib/typescript/hooks/useMessageTranslation.d.ts +25 -0
  271. package/lib/typescript/hooks/useMessageTranslation.d.ts.map +1 -0
  272. package/lib/typescript/hooks/usePushNotifications.d.ts.map +1 -1
  273. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  274. package/lib/typescript/i18n/strings.d.ts +16 -0
  275. package/lib/typescript/i18n/strings.d.ts.map +1 -0
  276. package/lib/typescript/i18n/useT.d.ts +34 -0
  277. package/lib/typescript/i18n/useT.d.ts.map +1 -0
  278. package/lib/typescript/main.d.ts +6 -1
  279. package/lib/typescript/main.d.ts.map +1 -1
  280. package/lib/typescript/networking/api-requests/auth.api.d.ts +27 -1
  281. package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
  282. package/lib/typescript/networking/api-requests/push.api.d.ts.map +1 -1
  283. package/lib/typescript/networking/api-requests/rooms.api.d.ts +3 -0
  284. package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
  285. package/lib/typescript/networking/callTokenStanza.d.ts +14 -0
  286. package/lib/typescript/networking/callTokenStanza.d.ts.map +1 -0
  287. package/lib/typescript/networking/outboundQueue.d.ts +1 -0
  288. package/lib/typescript/networking/outboundQueue.d.ts.map +1 -1
  289. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  290. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  291. package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts +10 -0
  292. package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts.map +1 -1
  293. package/lib/typescript/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts +16 -1
  294. package/lib/typescript/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts.map +1 -1
  295. package/lib/typescript/networking/xmppClient.d.ts +1 -1
  296. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  297. package/lib/typescript/roomStore/callSlice.d.ts +39 -0
  298. package/lib/typescript/roomStore/callSlice.d.ts.map +1 -0
  299. package/lib/typescript/roomStore/chatSettingsSlice.d.ts +10 -1
  300. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  301. package/lib/typescript/roomStore/index.d.ts +4 -0
  302. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  303. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  304. package/lib/typescript/roomStore/roomsSlice.d.ts +6 -1
  305. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  306. package/lib/typescript/types/models/language.model.d.ts +1 -1
  307. package/lib/typescript/types/models/language.model.d.ts.map +1 -1
  308. package/lib/typescript/types/models/message.model.d.ts +7 -0
  309. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  310. package/lib/typescript/types/types.d.ts +135 -1
  311. package/lib/typescript/types/types.d.ts.map +1 -1
  312. package/lib/typescript/utils/translateModePolicy.d.ts +20 -0
  313. package/lib/typescript/utils/translateModePolicy.d.ts.map +1 -0
  314. package/package.json +20 -4
  315. package/src/components/MainComponents/ChatHeader.tsx +30 -9
  316. package/src/components/MainComponents/ChatWrapper.tsx +15 -0
  317. package/src/components/MainComponents/LanguageSelectorButton.tsx +53 -0
  318. package/src/components/MainComponents/LanguageSelectorModal.tsx +276 -0
  319. package/src/components/MainComponents/MediaMessage.tsx +5 -0
  320. package/src/components/MainComponents/RoomList.tsx +27 -9
  321. package/src/components/MessageBubble/Message.tsx +109 -17
  322. package/src/components/MessageBubble/MessageTranslate.tsx +182 -0
  323. package/src/components/MessageBubble/TranslatedMessageBody.tsx +59 -0
  324. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +3 -3
  325. package/src/components/UsersList/UsersList.tsx +3 -1
  326. package/src/components/VideoCalls/CallButtons.tsx +171 -0
  327. package/src/components/VideoCalls/CallIcons.tsx +246 -0
  328. package/src/components/VideoCalls/VideoCallOverlay.tsx +627 -0
  329. package/src/components/VideoCalls/VideoCallSession.tsx +675 -0
  330. package/src/components/VideoCalls/livekitRuntime.ts +100 -0
  331. package/src/components/VideoCalls/useCallKeep.ts +252 -0
  332. package/src/components/styled/AudioMessage.tsx +97 -37
  333. package/src/components/styled/RoomListComponents/index.tsx +15 -3
  334. package/src/components/styled/SendInput.tsx +94 -51
  335. package/src/components/styled/StyledComponents.ts +9 -6
  336. package/src/components/styled/StyledInputComponents/Composing.tsx +7 -1
  337. package/src/components/styled/VideoMessage.tsx +114 -20
  338. package/src/context/xmppProvider.tsx +14 -1
  339. package/src/helpers/callLogMessage.ts +174 -0
  340. package/src/helpers/callPush.ts +90 -0
  341. package/src/helpers/constants/LANGUAGE_OPTIONS.ts +20 -5
  342. package/src/helpers/createUserNameFromSetUser.ts +68 -2
  343. package/src/helpers/getDataFromXml.ts +40 -4
  344. package/src/helpers/incomingCallFromPush.ts +83 -0
  345. package/src/helpers/insertMessageWithDelimiter.ts +27 -9
  346. package/src/helpers/isUnresolvedSenderId.ts +25 -0
  347. package/src/hooks/useChatSettingState.tsx +4 -0
  348. package/src/hooks/useMessageTranslation.ts +70 -0
  349. package/src/hooks/usePushNotifications.ts +15 -3
  350. package/src/hooks/useSendMessage.tsx +18 -5
  351. package/src/i18n/strings.ts +1322 -0
  352. package/src/i18n/useT.ts +56 -0
  353. package/src/main.ts +18 -1
  354. package/src/networking/api-requests/auth.api.ts +79 -44
  355. package/src/networking/api-requests/push.api.ts +39 -8
  356. package/src/networking/api-requests/rooms.api.ts +109 -1
  357. package/src/networking/callTokenStanza.ts +636 -0
  358. package/src/networking/outboundQueue.ts +1 -0
  359. package/src/networking/stanzaHandlers.ts +74 -15
  360. package/src/networking/xmpp/handleStanzas.xmpp.ts +52 -11
  361. package/src/networking/xmpp/sendTextMessage.xmpp.ts +1 -1
  362. package/src/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.ts +41 -5
  363. package/src/networking/xmppClient.ts +97 -28
  364. package/src/roomStore/callSlice.ts +190 -0
  365. package/src/roomStore/chatSettingsSlice.ts +16 -0
  366. package/src/roomStore/index.ts +5 -0
  367. package/src/roomStore/persistence.ts +103 -3
  368. package/src/roomStore/roomsSlice.ts +149 -4
  369. package/src/types/models/language.model.ts +17 -1
  370. package/src/types/models/message.model.ts +9 -0
  371. package/src/types/types.ts +142 -2
  372. package/src/utils/translateModePolicy.ts +31 -0
@@ -0,0 +1,174 @@
1
+ import { IMessage } from '../types/types';
2
+
3
+ // A server "call-state" stanza is emitted into the room when a call session
4
+ // concludes (someone leaves the LiveKit room). It carries:
5
+ // type="call-state" callId="..." durationMs="<ms>"
6
+ // callerXmppUsername="<who started the call>" isSystemMessage="true"
7
+ // We turn it into a friendly chat-log entry, Telegram/WhatsApp style:
8
+ // - durationMs > 0 -> "Outgoing call · 12 sec" / "Incoming call · 1 min"
9
+ // - durationMs == 0 -> "No answer" (we called) / "Missed call" (they called)
10
+ // Direction is derived from callerXmppUsername vs the logged-in user.
11
+
12
+ export interface CallLogMeta {
13
+ callId: string;
14
+ direction: 'outgoing' | 'incoming';
15
+ durationMs: number;
16
+ missed: boolean;
17
+ kind: 'audio' | 'video';
18
+ }
19
+
20
+ export const isCallLogMessage = (message: unknown): boolean => {
21
+ const type = String((message as any)?.type || '').toLowerCase();
22
+ return type === 'call-state';
23
+ };
24
+
25
+ // Only a call-state that actually carries log metadata (a caller and/or a
26
+ // duration) is worth rendering. Bare client-side signaling frames
27
+ // (state=cancelled/declined/ended with no caller/duration) must NOT become
28
+ // chat entries, they're real-time teardown only.
29
+ export const callStateHasLogData = (attrs: Record<string, any>): boolean => {
30
+ if (!attrs) {return false;}
31
+ const hasCaller = !!String(attrs.callerXmppUsername || '').trim();
32
+ const hasDuration =
33
+ attrs.durationMs !== undefined &&
34
+ attrs.durationMs !== null &&
35
+ attrs.durationMs !== '';
36
+ return hasCaller || hasDuration;
37
+ };
38
+
39
+ export const formatCallDuration = (ms: number): string => {
40
+ const totalSeconds = Math.max(0, Math.round(ms / 1000));
41
+ if (totalSeconds < 60) {return `${totalSeconds} sec`;}
42
+ const minutes = Math.floor(totalSeconds / 60);
43
+ const seconds = totalSeconds % 60;
44
+ if (seconds === 0) {return `${minutes} min`;}
45
+ return `${minutes} min ${seconds} sec`;
46
+ };
47
+
48
+ export const transformCallLogMessage = (
49
+ message: IMessage,
50
+ selfXmppUsername: string
51
+ ): IMessage => {
52
+ if (!isCallLogMessage(message)) {return message;}
53
+
54
+ const raw = message as any;
55
+ const callerLocal = String(raw.callerXmppUsername || '')
56
+ .split('@')[0]
57
+ .trim();
58
+ const selfLocal = String(selfXmppUsername || '').split('@')[0].trim();
59
+ // When we know the caller, "outgoing" means we started it. With no
60
+ // caller info, default to incoming (safer label than claiming we dialed).
61
+ const isOutgoing = !!callerLocal && callerLocal === selfLocal;
62
+ const durationMs = Number(raw.durationMs || 0);
63
+ const kind: 'audio' | 'video' =
64
+ String(raw.kind || '').toLowerCase() === 'audio' ? 'audio' : 'video';
65
+
66
+ let body: string;
67
+ if (durationMs > 0) {
68
+ body = `${isOutgoing ? 'Outgoing' : 'Incoming'} call · ${formatCallDuration(durationMs)}`;
69
+ } else {
70
+ body = isOutgoing ? 'No answer' : 'Missed call';
71
+ }
72
+
73
+ const callLog: CallLogMeta = {
74
+ callId: String(raw.callId || raw.callid || '').trim(),
75
+ direction: isOutgoing ? 'outgoing' : 'incoming',
76
+ durationMs,
77
+ missed: durationMs === 0,
78
+ kind,
79
+ };
80
+
81
+ return {
82
+ ...message,
83
+ body,
84
+ // Render through the existing centered SystemMessage pipeline.
85
+ isSystemMessage: 'true',
86
+ callLog,
87
+ } as IMessage;
88
+ };
89
+
90
+ // Build a "call ended" log entry locally (client-side) when a call finishes.
91
+ // The authoritative entry is a SERVER `call-state` broadcast, but that isn't
92
+ // guaranteed to arrive (see header comment). This fallback keeps the chat log
93
+ // working regardless. It's deduplicated against any server copy in
94
+ // `addRoomMessage` by `callLog.callId` (the entry with the largest duration
95
+ // wins), so if the server does broadcast, the two collapse into one.
96
+ export const buildLocalCallLogMessage = (params: {
97
+ callId: string;
98
+ direction: 'outgoing' | 'incoming';
99
+ durationMs: number;
100
+ kind: 'audio' | 'video';
101
+ selfXmppUsername: string;
102
+ }): IMessage => {
103
+ const { callId, direction, durationMs, kind, selfXmppUsername } = params;
104
+ const isOutgoing = direction === 'outgoing';
105
+ const safeDuration = Math.max(0, Math.round(durationMs || 0));
106
+
107
+ let body: string;
108
+ if (safeDuration > 0) {
109
+ body = `${isOutgoing ? 'Outgoing' : 'Incoming'} call · ${formatCallDuration(safeDuration)}`;
110
+ } else {
111
+ body = isOutgoing ? 'No answer' : 'Missed call';
112
+ }
113
+
114
+ const callLog: CallLogMeta = {
115
+ callId,
116
+ direction,
117
+ durationMs: safeDuration,
118
+ missed: safeDuration === 0,
119
+ kind,
120
+ };
121
+
122
+ return {
123
+ // Deterministic id so a re-fire for the same call collapses in place.
124
+ id: callId ? `calllog-${callId}` : `calllog-${Date.now()}`,
125
+ body,
126
+ date: new Date().toISOString(),
127
+ isSystemMessage: 'true',
128
+ type: 'call-state',
129
+ callLog,
130
+ user: { id: selfXmppUsername },
131
+ } as unknown as IMessage;
132
+ };
133
+
134
+ /**
135
+ * The label for a call-log entry, built at RENDER time from the callLog
136
+ * meta rather than read off `message.body`.
137
+ *
138
+ * transformCallLogMessage bakes an English sentence into `body` the moment
139
+ * the stanza arrives, which freezes the language: switch to French and
140
+ * every call log you already received stays English forever, because the
141
+ * text is data by then, not a rendering. The meta (direction/duration/
142
+ * missed) is the actual fact, the sentence is a view of it, so it belongs
143
+ * where the view is. `body` stays as the fallback for entries received
144
+ * before this existed, and for the notification/room-list preview paths
145
+ * that only have the raw message.
146
+ */
147
+ export const formatCallLogLabel = (
148
+ callLog: CallLogMeta | undefined,
149
+ t: (key: string, vars?: Record<string, string | number>) => string,
150
+ fallbackBody = ''
151
+ ): string => {
152
+ if (!callLog) {return fallbackBody;}
153
+
154
+ if (!callLog.durationMs || callLog.durationMs <= 0) {
155
+ return callLog.direction === 'outgoing'
156
+ ? t('call.noAnswer')
157
+ : t('call.missed');
158
+ }
159
+
160
+ const totalSeconds = Math.max(0, Math.round(callLog.durationMs / 1000));
161
+ const minutes = Math.floor(totalSeconds / 60);
162
+ const seconds = totalSeconds % 60;
163
+ const duration =
164
+ totalSeconds < 60
165
+ ? t('call.durationSec', { n: totalSeconds })
166
+ : seconds === 0
167
+ ? t('call.durationMin', { n: minutes })
168
+ : t('call.durationMinSec', { m: minutes, s: seconds });
169
+
170
+ const direction =
171
+ callLog.direction === 'outgoing' ? t('call.outgoing') : t('call.incoming');
172
+
173
+ return `${direction} · ${duration}`;
174
+ };
@@ -0,0 +1,90 @@
1
+ // Recognise and parse an *incoming call* push notification.
2
+ //
3
+ // Calls normally ring via a live XMPP `call-token` stanza, which only arrives
4
+ // while the socket is connected. On mobile the socket is dead whenever the OS
5
+ // backgrounds or kills the app, so the backend also delivers the call over
6
+ // push, in the same `data`-payload format as message pushes. This helper lets
7
+ // the push layer tell a call push apart from a chat push and pull the call
8
+ // fields out, tolerating the field-name variations backends tend to use.
9
+
10
+ export interface ParsedCallPush {
11
+ callId: string | null;
12
+ /** LiveKit token, if the push carried one (lets us ring + accept offline). */
13
+ token: string | null;
14
+ kind: 'audio' | 'video';
15
+ /** Bare room name (JID localpart) the call belongs to. */
16
+ roomBareName: string | null;
17
+ /** Raw room reference from the payload (full JID or bare name). */
18
+ roomRef: string | null;
19
+ /** Display name for the ring screen (caller). */
20
+ callerName: string | null;
21
+ /** Caller's xmpp localpart, when provided. */
22
+ callerXmppUsername: string | null;
23
+ }
24
+
25
+ const pick = (data: Record<string, any>, keys: string[]): string => {
26
+ for (const k of keys) {
27
+ const v = data?.[k];
28
+ if (v !== undefined && v !== null && String(v).trim() !== '') {
29
+ return String(v).trim();
30
+ }
31
+ }
32
+ return '';
33
+ };
34
+
35
+ /**
36
+ * True when a push `data` payload represents an incoming call. Matches on an
37
+ * explicit call marker (`type`/`pushType`/`category`/`event` === "call"-ish)
38
+ * or on a callId paired with a call-specific field, so a normal message push
39
+ * is never misread as a call.
40
+ */
41
+ export const isCallPush = (
42
+ data: Record<string, any> | null | undefined
43
+ ): boolean => {
44
+ if (!data) {return false;}
45
+ const marker = pick(data, [
46
+ 'type',
47
+ 'pushType',
48
+ 'category',
49
+ 'messageType',
50
+ 'event',
51
+ ]).toLowerCase();
52
+ if (
53
+ marker === 'call' ||
54
+ marker === 'incoming-call' ||
55
+ marker === 'call-token' ||
56
+ marker === 'call-invite'
57
+ ) {
58
+ return true;
59
+ }
60
+ const callId = pick(data, ['callId', 'callid', 'callID']);
61
+ const hasCallField =
62
+ !!pick(data, ['callToken', 'livekitToken']) ||
63
+ !!pick(data, ['callKind']) ||
64
+ pick(data, ['kind']).toLowerCase() === 'audio' ||
65
+ pick(data, ['kind']).toLowerCase() === 'video';
66
+ return !!callId && hasCallField;
67
+ };
68
+
69
+ export const parseCallPush = (
70
+ data: Record<string, any> | null | undefined
71
+ ): ParsedCallPush => {
72
+ const d = data || {};
73
+ const roomRef =
74
+ pick(d, ['callRoom', 'room', 'roomJid', 'jid', 'chatId']) || null;
75
+ const roomBareName = roomRef ? roomRef.split('@')[0] || roomRef : null;
76
+ const kindRaw = pick(d, ['callKind', 'kind']).toLowerCase();
77
+ return {
78
+ callId: pick(d, ['callId', 'callid', 'callID']) || null,
79
+ token: pick(d, ['callToken', 'livekitToken', 'token']) || null,
80
+ kind: kindRaw === 'audio' ? 'audio' : 'video',
81
+ roomBareName,
82
+ roomRef,
83
+ callerName:
84
+ pick(d, ['callerName', 'callerDisplayName', 'senderName', 'title']) ||
85
+ null,
86
+ callerXmppUsername:
87
+ pick(d, ['callerXmppUsername', 'callerUsername', 'userJid', 'senderJid'])
88
+ .split('@')[0] || null,
89
+ };
90
+ };
@@ -5,10 +5,25 @@ type LanguageOption = {
5
5
  id: Iso639_1Codes;
6
6
  };
7
7
 
8
+ /**
9
+ * Languages the in-chat globe picker offers.
10
+ *
11
+ * Names are AUTONYMS (each language written in itself), which is what
12
+ * every mainstream language picker does: a reader who only speaks French
13
+ * can find "Français" but not "French". Ids carry the region because the
14
+ * deployment's readers are Canadian and US, and the region is forwarded to
15
+ * the translation service so it can tell fr-CA from fr-FR. Base-language
16
+ * lookups (i18n tables, Translate-button visibility) strip it via
17
+ * toBaseLanguage, so both forms interoperate.
18
+ *
19
+ * Commented-out entries still have full string tables in i18n/strings.ts,
20
+ * they're just not offered to readers in the current deployment.
21
+ */
8
22
  export const LANGUAGE_OPTIONS: LanguageOption[] = [
9
- { name: 'English', id: 'en' },
10
- { name: 'Spanish', id: 'es' },
11
- { name: 'Portuguese', id: 'pt' },
12
- { name: 'Haitian Creole', id: 'ht' },
13
- { name: 'Chinese', id: 'zh' },
23
+ { name: 'English', id: 'en-CA' },
24
+ { name: 'Español', id: 'es-US' },
25
+ { name: 'Français', id: 'fr-CA' },
26
+ // { name: 'Português', id: 'pt' },
27
+ // { name: 'Kreyòl ayisyen', id: 'ht' },
28
+ // { name: '中文', id: 'zh' },
14
29
  ];
@@ -1,5 +1,11 @@
1
- import { RoomMember } from '../types/types';
1
+ import { IMessage, RoomMember } from '../types/types';
2
2
 
3
+ /**
4
+ * Cache-only lookup. Returns the literal "Deleted User" as a MISS sentinel
5
+ * when `usersSet` has no entry for `userId` yet, callers that want a
6
+ * better fallback (e.g. resolveSenderDisplayName below) check for that
7
+ * exact string rather than treating it as a real name.
8
+ */
3
9
  export const createUserNameFromSetUser = (
4
10
  usersSet: Record<string, RoomMember>,
5
11
  userId: string
@@ -10,6 +16,66 @@ export const createUserNameFromSetUser = (
10
16
 
11
17
  const firstName = user.firstName?.trim() || '';
12
18
  const lastName = user.lastName?.trim() || '';
19
+ // REST-loaded members carry firstName/lastName; XMPP-roster-only
20
+ // members (no REST match yet) carry just the roster `name` attr —
21
+ // fall back to that before giving up and returning the raw id.
22
+ const bareName = user.name?.trim() || '';
13
23
 
14
- return `${firstName} ${lastName}`.trim() || userId;
24
+ return `${firstName} ${lastName}`.trim() || bareName || userId;
25
+ };
26
+
27
+ /**
28
+ * The sender's display name, resolved WITHOUT depending on `usersSet`
29
+ * having already been hydrated.
30
+ *
31
+ * `usersSet` is populated by a separate fetch (member list / presence) that
32
+ * can still be in flight when a message arrives, most reliably right after
33
+ * reconnect, when a burst of catch-up messages can land before that fetch
34
+ * resolves. A cache-only lookup shows the literal "Deleted User" for every
35
+ * one of those messages, even though the sender is very much not deleted.
36
+ * On mobile this is the common case, not the rare one: every return from
37
+ * background reconnects.
38
+ *
39
+ * The message itself already carries the sender's name on the wire: every
40
+ * client that sends through this SDK stamps `senderFirstName` /
41
+ * `senderLastName` / `fullName` onto the outgoing stanza's `<data>` element
42
+ * (see sendTextMessage.xmpp.ts / sendTextMessageWithTranslateTag.xmpp.ts),
43
+ * and createMessageFromXml spreads those onto the top-level message object.
44
+ * Preferring that over the cache removes the timing dependency entirely for
45
+ * the common case, and "Deleted User" becomes what it should have always
46
+ * been: a rare last resort, not "usersSet hasn't loaded yet".
47
+ */
48
+ export const resolveSenderDisplayName = (
49
+ message: Pick<IMessage, 'user'> & {
50
+ fullName?: string;
51
+ senderFirstName?: string;
52
+ senderLastName?: string;
53
+ },
54
+ usersSet: Record<string, RoomMember>
55
+ ): string => {
56
+ const rawUserId = String(message?.user?.id || '');
57
+ const localUserId = rawUserId.split('@')[0];
58
+ const currentNameRaw = String(message?.user?.name || '').trim();
59
+ // A previously-resolved "Deleted User" is itself a miss sentinel, not a
60
+ // real name, don't let it short-circuit the fallback chain below.
61
+ const currentName = currentNameRaw === 'Deleted User' ? '' : currentNameRaw;
62
+
63
+ const dataFullName = String(message?.fullName || '').trim();
64
+ const dataFirst = String(message?.senderFirstName || '').trim();
65
+ const dataLast = String(message?.senderLastName || '').trim();
66
+ const composedFromData = dataFullName || `${dataFirst} ${dataLast}`.trim();
67
+
68
+ const usersSetName = createUserNameFromSetUser(usersSet, localUserId);
69
+ const usersSetNameAlt = createUserNameFromSetUser(usersSet, rawUserId);
70
+ const isUsersSetUseful = (name: string) => !!name && name !== 'Deleted User';
71
+
72
+ return (
73
+ currentName ||
74
+ (isUsersSetUseful(usersSetName) && usersSetName) ||
75
+ (isUsersSetUseful(usersSetNameAlt) && usersSetNameAlt) ||
76
+ composedFromData ||
77
+ localUserId ||
78
+ rawUserId ||
79
+ 'Deleted User'
80
+ );
15
81
  };
@@ -2,6 +2,38 @@ import { Element } from 'ltx';
2
2
  import { Iso639_1Codes, IUser } from '../types/types';
3
3
  import { transformArrayToObject } from './transformTranslatations';
4
4
 
5
+ // Tolerant JSON parse: a malformed `translations` attr must not reject the
6
+ // whole stanza (which would silently drop the message). Mirrors the web
7
+ // SDK's safeJsonParse.
8
+ const safeJsonParse = <T,>(value: unknown, fallback: T): T => {
9
+ if (typeof value !== 'string' || !value) {return fallback;}
10
+ try {
11
+ return JSON.parse(value) as T;
12
+ } catch {
13
+ return fallback;
14
+ }
15
+ };
16
+
17
+ // Keep only well-formed translation entries (drops partial/garbage items),
18
+ // same shape guard the web SDK applies before transformArrayToObject.
19
+ const normalizeTranslations = (value: unknown) =>
20
+ Array.isArray(value)
21
+ ? value.filter(
22
+ (
23
+ item
24
+ ): item is {
25
+ translatedText: string;
26
+ language: string;
27
+ languageName: string;
28
+ } =>
29
+ !!item &&
30
+ typeof item === 'object' &&
31
+ typeof (item as any).translatedText === 'string' &&
32
+ typeof (item as any).language === 'string' &&
33
+ typeof (item as any).languageName === 'string'
34
+ )
35
+ : [];
36
+
5
37
  const extractTimestamp = (str: string, stanza?: any): string | null => {
6
38
  if (!str) {return null;}
7
39
  if (typeof str !== 'string') {
@@ -43,12 +75,16 @@ export const getDataFromXml = async (stanza: Element): Promise<DataXml | undefin
43
75
 
44
76
  const body = fullData?.getChild('body')?.getText() || undefined;
45
77
  const deleted = !!fullData?.getChild('deleted');
78
+ const translationPayload = safeJsonParse<{ translates?: unknown[] }>(
79
+ fullData?.getChild('translations')?.attrs?.value,
80
+ {}
81
+ );
46
82
  const translations = fullData?.getChild('translations')?.attrs?.value
47
- ? transformArrayToObject(
48
- JSON.parse(fullData.getChild('translations')!.attrs.value).translates
49
- )
83
+ ? transformArrayToObject(normalizeTranslations(translationPayload.translates))
50
84
  : undefined;
51
- const langSource = fullData?.getChild('translate')?.attrs?.source;
85
+ const langSource = fullData?.getChild('translate')?.attrs?.source as
86
+ | Iso639_1Codes
87
+ | undefined;
52
88
  const numericPart = /\d{13,}/.exec(id || '')?.[0];
53
89
  const date = numericPart
54
90
  ? new Date(+numericPart.slice(0, 13)).toISOString()
@@ -0,0 +1,83 @@
1
+ import { store } from '../roomStore';
2
+ import { setIncomingCallToken } from '../roomStore/callSlice';
3
+ import { isCallPush, parseCallPush } from './callPush';
4
+
5
+ /**
6
+ * Turn an incoming-call push into a ringing call.
7
+ *
8
+ * On mobile the XMPP socket dies whenever the OS backgrounds or kills the
9
+ * app, and the `call-token` stanza that normally opens the ring screen is
10
+ * lost with it. The backend also delivers the call as a data push, so this
11
+ * is the path every call takes when the app was not in the foreground.
12
+ *
13
+ * Returns true when the payload WAS a call push (whether or not it could
14
+ * be rung), so the caller knows to stop and not also show it as a chat
15
+ * notification. A user should never get a "new message: call-state" toast.
16
+ */
17
+ export const handleCallPush = (
18
+ data: Record<string, any> | null | undefined
19
+ ): boolean => {
20
+ if (!isCallPush(data)) {
21
+ return false;
22
+ }
23
+
24
+ const parsed = parseCallPush(data);
25
+ const state = store.getState();
26
+
27
+ // Calls off in this deployment: swallow the push rather than ringing a
28
+ // screen the host never opted into.
29
+ if (state.chatSettingStore.config?.videoCalls?.enabled !== true) {
30
+ return true;
31
+ }
32
+
33
+ // Already ringing or in this exact call (the push raced the stanza, or
34
+ // two pushes arrived). Re-dispatching would reset startedAt and restart
35
+ // the ring, so leave the existing call alone.
36
+ const current = state.call;
37
+ if (current.phase !== 'idle') {
38
+ const sameCall =
39
+ (!!parsed.callId && parsed.callId === current.callId) ||
40
+ (!!parsed.roomBareName && parsed.roomBareName === current.roomBareName);
41
+ if (sameCall || current.phase === 'in-call') {
42
+ return true;
43
+ }
44
+ }
45
+
46
+ // Without a LiveKit token there is nothing to accept: the push is only
47
+ // an alert. Ringing anyway would give the user an Accept button that
48
+ // cannot work, so treat it as handled and let the stanza (once the
49
+ // socket is back up) open the real ring screen.
50
+ if (!parsed.token) {
51
+ return true;
52
+ }
53
+
54
+ // Resolve the full room JID from the local room map. The push carries
55
+ // the bare name; callSlice and the hangup signal both want the JID.
56
+ const rooms = state.rooms.rooms || {};
57
+ const resolved = Object.values(rooms).find(
58
+ (room: any) =>
59
+ (room?.jid || '').split('@')[0] === parsed.roomBareName ||
60
+ room?.jid === parsed.roomRef
61
+ ) as { jid?: string; name?: string } | undefined;
62
+
63
+ const roomJid =
64
+ resolved?.jid ||
65
+ (parsed.roomRef && parsed.roomRef.includes('@') ? parsed.roomRef : '');
66
+ if (!roomJid) {
67
+ return true;
68
+ }
69
+
70
+ store.dispatch(
71
+ setIncomingCallToken({
72
+ roomJid,
73
+ roomName: parsed.callerName || resolved?.name || null,
74
+ roomBareName: parsed.roomBareName,
75
+ token: parsed.token,
76
+ kind: parsed.kind,
77
+ callId: parsed.callId,
78
+ peerXmppUsername: parsed.callerXmppUsername,
79
+ })
80
+ );
81
+
82
+ return true;
83
+ };
@@ -71,20 +71,38 @@ export function insertMessageWithDelimiter(
71
71
  isDateAfter(msg.date?.toString() ?? '', lastViewedTimestamp.toString())
72
72
  );
73
73
 
74
- if (delimiterIndex !== -1) {
75
- roomMessages.splice(delimiterIndex, 0, {
76
- id: 'delimiter-new',
77
- user: {
74
+ if (delimiterIndex !== -1) {
75
+ // The divider's date is what ORDERS it: roomsSlice re-sorts every
76
+ // merged page by timestamp (see `byMs`), so a divider stamped with
77
+ // `new Date()` — i.e. now — sorted past every real message and
78
+ // rendered at the very bottom, BELOW the new messages it is
79
+ // supposed to introduce. Anchor it a hair before the first unread
80
+ // instead, which is where it belongs and where any later sort keeps
81
+ // it. Derived from that message rather than from
82
+ // lastViewedTimestamp so it works whatever format the caller passes.
83
+ const firstUnreadMs = Date.parse(
84
+ String(roomMessages[delimiterIndex]?.date ?? '')
85
+ );
86
+ const rawLastViewed = lastViewedTimestamp.toString();
87
+ const lastViewedMs =
88
+ Date.parse(rawLastViewed) || Number(rawLastViewed) || Date.now();
89
+ const anchorMs = Number.isFinite(firstUnreadMs)
90
+ ? firstUnreadMs - 1
91
+ : lastViewedMs;
92
+
93
+ roomMessages.splice(delimiterIndex, 0, {
94
+ id: 'delimiter-new',
95
+ user: {
78
96
  id: 'system',
79
97
  name: undefined,
80
98
  token: '',
81
99
  refreshToken: '',
82
100
  },
83
- date: new Date().toString(),
84
- body: 'New Messages',
85
- roomJid: '',
86
- });
87
- }
101
+ date: new Date(anchorMs).toISOString(),
102
+ body: 'New Messages',
103
+ roomJid: '',
104
+ });
105
+ }
88
106
  }
89
107
  } else if (
90
108
  isDateBefore(newMessageDate.toString(), firstMessage?.date?.toString() ?? '')
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Whether a resolved sender "name" is really just an unresolved id.
3
+ *
4
+ * The name chain ends at the sender's JID localpart when `usersSet` has no
5
+ * entry and the wire carried no name. For a real member that never happens
6
+ * for long — the REST roster fills the cache in. But some senders are not
7
+ * members at all: a broadcast posted by the app itself arrives with the
8
+ * ROOM's own id as its occupant resource (e.g.
9
+ * `646cc8dc96d4a4dc8f7b2f2d_67f6823cf5995841ba431f06`), so no roster will
10
+ * ever resolve it and the bubble ends up captioned with 50 characters of
11
+ * hex.
12
+ *
13
+ * Ethora ids are `<24-hex appId>_<24-hex objectId>`, which is what this
14
+ * matches. A raw objectId on its own is matched too, since some senders
15
+ * carry only that half.
16
+ */
17
+ const ETHORA_ID = /^[0-9a-f]{24}(_[0-9a-f]{24})?$/i;
18
+
19
+ export const isUnresolvedSenderId = (name?: string): boolean => {
20
+ const trimmed = String(name || '').trim();
21
+ if (!trimmed) {
22
+ return true;
23
+ }
24
+ return ETHORA_ID.test(trimmed);
25
+ };
@@ -24,6 +24,9 @@ export const useChatSettingState = () => {
24
24
  const client = useSelector(
25
25
  (state: RootState) => state.chatSettingStore.client
26
26
  );
27
+ const translateMode = useSelector(
28
+ (state: RootState) => state.chatSettingStore.translateMode
29
+ );
27
30
 
28
31
  return {
29
32
  user,
@@ -33,6 +36,7 @@ export const useChatSettingState = () => {
33
36
  deleteModal,
34
37
  selectedUser,
35
38
  langSource,
39
+ translateMode,
36
40
  client,
37
41
  };
38
42
  };