@ethora/chat-component-rn 26.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +148 -0
  3. package/empty-shim.js +15 -0
  4. package/index.js +13 -0
  5. package/metro.js +72 -0
  6. package/package.json +99 -0
  7. package/src/api.config.ts +34 -0
  8. package/src/assets/BG.png +0 -0
  9. package/src/assets/BG.tsx +56 -0
  10. package/src/assets/File.svg +4 -0
  11. package/src/assets/ForzaCare.png +0 -0
  12. package/src/assets/ForzaCare.tsx +27 -0
  13. package/src/assets/icons.tsx +685 -0
  14. package/src/assets/images.tsx +41 -0
  15. package/src/assets/test.xml +243 -0
  16. package/src/components/AuthForms/Login.tsx +295 -0
  17. package/src/components/AuthForms/LoginAnonym.tsx +68 -0
  18. package/src/components/AuthForms/Register.tsx +8 -0
  19. package/src/components/ContextMenu/ContextMenuComponents.tsx +87 -0
  20. package/src/components/DropdownMenu/DropdownMenu.tsx +244 -0
  21. package/src/components/ExampleComponents/CustomMessage.tsx +92 -0
  22. package/src/components/ExampleComponents/CustomTypingIndicatorExamples.tsx +239 -0
  23. package/src/components/Header/HeaderRoomList.tsx +104 -0
  24. package/src/components/InputComponents/AudioInput.tsx +24 -0
  25. package/src/components/InputComponents/AudioRecorder.tsx +100 -0
  26. package/src/components/InputComponents/MediaInput.tsx +114 -0
  27. package/src/components/InputComponents/RecordingIndicator.tsx +77 -0
  28. package/src/components/InputComponents/Search.tsx +135 -0
  29. package/src/components/InputComponents/TextInput.tsx +66 -0
  30. package/src/components/MainComponents/ChatHeader.tsx +163 -0
  31. package/src/components/MainComponents/ChatRoom.tsx +392 -0
  32. package/src/components/MainComponents/ChatWrapper.tsx +318 -0
  33. package/src/components/MainComponents/ChooseChatMessage.tsx +44 -0
  34. package/src/components/MainComponents/ConnectionBanner.tsx +33 -0
  35. package/src/components/MainComponents/EditWrapper.tsx +72 -0
  36. package/src/components/MainComponents/LoginWrapper.tsx +134 -0
  37. package/src/components/MainComponents/MediaMessage.tsx +55 -0
  38. package/src/components/MainComponents/MessageContainer.tsx +122 -0
  39. package/src/components/MainComponents/MessageList.tsx +429 -0
  40. package/src/components/MainComponents/NoMessagesPlaceholder.tsx +49 -0
  41. package/src/components/MainComponents/ProfileImagePlaceholder.tsx +143 -0
  42. package/src/components/MainComponents/RNStyled.tsx +34 -0
  43. package/src/components/MainComponents/ReduxWrapper.tsx +40 -0
  44. package/src/components/MainComponents/RoomList.tsx +246 -0
  45. package/src/components/MainComponents/Select.tsx +165 -0
  46. package/src/components/MainComponents/Switch.tsx +73 -0
  47. package/src/components/MainComponents/SystemMessage.tsx +42 -0
  48. package/src/components/Menu/HeaderRoomListMenu.tsx +169 -0
  49. package/src/components/MenuRoom/MenuRoom.tsx +46 -0
  50. package/src/components/MessageBubble/Avatar.tsx +84 -0
  51. package/src/components/MessageBubble/BottomReplyContainer.tsx +117 -0
  52. package/src/components/MessageBubble/CustomDivider.tsx +10 -0
  53. package/src/components/MessageBubble/DeletedMessage.tsx +36 -0
  54. package/src/components/MessageBubble/Message.tsx +400 -0
  55. package/src/components/MessageBubble/MessageInteractions.tsx +247 -0
  56. package/src/components/MessageBubble/MessageReaction.tsx +149 -0
  57. package/src/components/MessageBubble/MessageReply.tsx +50 -0
  58. package/src/components/MessageBubble/MessageTranslations.tsx +30 -0
  59. package/src/components/Modals/AddMembersModal/AddMembersModal.tsx +142 -0
  60. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +471 -0
  61. package/src/components/Modals/ChatProfileModal/DeleteChatModal.tsx +91 -0
  62. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +298 -0
  63. package/src/components/Modals/Modal/Modal.tsx +52 -0
  64. package/src/components/Modals/ModalHeaderComponent.tsx +41 -0
  65. package/src/components/Modals/ModalSelectMedia/ModalSelectMedia.tsx +285 -0
  66. package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +103 -0
  67. package/src/components/Modals/NewChatModal/ModalContent.tsx +151 -0
  68. package/src/components/Modals/NewChatModal/NewChatModal.tsx +391 -0
  69. package/src/components/Modals/NewChatModal/UpdNewChatModal.tsx +136 -0
  70. package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +134 -0
  71. package/src/components/Modals/SettingsModals/BlockedUsers/BlockedUsersModal.tsx +63 -0
  72. package/src/components/Modals/SettingsModals/DocumentShares/DocumentSharesModal.tsx +115 -0
  73. package/src/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.tsx +121 -0
  74. package/src/components/Modals/SettingsModals/ManageDataModal/StyledComponents.ts +0 -0
  75. package/src/components/Modals/SettingsModals/ProfileShares/ProfileShares.tsx +65 -0
  76. package/src/components/Modals/SettingsModals/Referrals/Referrals.tsx +90 -0
  77. package/src/components/Modals/SettingsModals/SharedStyledComponents.ts +74 -0
  78. package/src/components/Modals/SettingsModals/Visibility/RadioInput.tsx +59 -0
  79. package/src/components/Modals/SettingsModals/Visibility/StyledComponents.ts +32 -0
  80. package/src/components/Modals/SettingsModals/Visibility/VisibilityModal.tsx +146 -0
  81. package/src/components/Modals/UserProfileModal/EditUserModal.tsx +163 -0
  82. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +410 -0
  83. package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +85 -0
  84. package/src/components/Modals/styledModalComponents.tsx +181 -0
  85. package/src/components/OperationalModal/OperationalModal.tsx +78 -0
  86. package/src/components/RoomComponents/ChatRoomItem.tsx +219 -0
  87. package/src/components/RoomComponents/LastMessageItem.tsx +47 -0
  88. package/src/components/RoomComponents/styled/LastAudioMessage.tsx +62 -0
  89. package/src/components/RoomComponents/styled/LastMessageEmoji.tsx +26 -0
  90. package/src/components/RoomComponents/styled/LastMessageFile.tsx +54 -0
  91. package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +54 -0
  92. package/src/components/RoomComponents/styled/LastMessageVideo.tsx +70 -0
  93. package/src/components/RoomComponents/styled/LastTextMessage.tsx +65 -0
  94. package/src/components/RoomComponents/styled/StyledRoomComponents.ts +53 -0
  95. package/src/components/SortDropDown/index.tsx +76 -0
  96. package/src/components/Thread/ThreadHeader.tsx +41 -0
  97. package/src/components/Thread/ThreadWrapper.tsx +270 -0
  98. package/src/components/Toast/Toast.tsx +128 -0
  99. package/src/components/Toast/index.ts +13 -0
  100. package/src/components/UsersList/StyledComponents.ts +30 -0
  101. package/src/components/UsersList/UsersList.tsx +112 -0
  102. package/src/components/styled/ActionButton.tsx +40 -0
  103. package/src/components/styled/AudioMessage.tsx +82 -0
  104. package/src/components/styled/Button.tsx +107 -0
  105. package/src/components/styled/ChatWrapperBox.tsx +9 -0
  106. package/src/components/styled/DateLabel.tsx +77 -0
  107. package/src/components/styled/Loader.tsx +65 -0
  108. package/src/components/styled/MediaFilePreview.tsx +42 -0
  109. package/src/components/styled/MediaModal.tsx +54 -0
  110. package/src/components/styled/MessageImage.tsx +54 -0
  111. package/src/components/styled/NewMessageLabel.tsx +50 -0
  112. package/src/components/styled/RoomListComponents/index.tsx +164 -0
  113. package/src/components/styled/SendInput.tsx +297 -0
  114. package/src/components/styled/StyledComponents.ts +320 -0
  115. package/src/components/styled/StyledInput.tsx +101 -0
  116. package/src/components/styled/StyledInputComponents/AudioComponents.tsx +1 -0
  117. package/src/components/styled/StyledInputComponents/Composing.tsx +97 -0
  118. package/src/components/styled/StyledInputComponents/CustomTypingIndicator.tsx +261 -0
  119. package/src/components/styled/StyledInputComponents/MediaComponents.tsx +90 -0
  120. package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +131 -0
  121. package/src/components/styled/StyledInputComponents/VideoComponents.tsx +49 -0
  122. package/src/components/styled/TreadLabel.tsx +50 -0
  123. package/src/components/styled/UnsupportedType.tsx +95 -0
  124. package/src/components/styled/VideoMessage.tsx +68 -0
  125. package/src/context/MessageNotificationContext.tsx +335 -0
  126. package/src/context/PushNotificationProvider.tsx +78 -0
  127. package/src/context/ToastContext.tsx +63 -0
  128. package/src/context/toastProvider.tsx +0 -0
  129. package/src/context/xmppProvider.tsx +364 -0
  130. package/src/helpers/block_scroll.ts +95 -0
  131. package/src/helpers/chatAutoEnterer.ts +46 -0
  132. package/src/helpers/checkUniqueUsers.tsx +31 -0
  133. package/src/helpers/constants/CHAT_TYPES.ts +6 -0
  134. package/src/helpers/constants/LANGUAGE_OPTIONS.ts +14 -0
  135. package/src/helpers/constants/LOCAL_STORAGE.ts +3 -0
  136. package/src/helpers/constants/MESSAGE_INTERACTIONS.ts +29 -0
  137. package/src/helpers/constants/MODAL_TYPES.ts +57 -0
  138. package/src/helpers/constants/PLATFORM_CONSTANTS.ts +3 -0
  139. package/src/helpers/createMainMessageForThread.ts +23 -0
  140. package/src/helpers/createMessageFromXml.ts +118 -0
  141. package/src/helpers/createRoomFromApi.tsx +27 -0
  142. package/src/helpers/createUserNameFromSetUser.ts +15 -0
  143. package/src/helpers/dateComparison.ts +12 -0
  144. package/src/helpers/debounce.ts +10 -0
  145. package/src/helpers/ensureScopedChatCache.ts +61 -0
  146. package/src/helpers/extractUniqueMembersFromRooms.ts +45 -0
  147. package/src/helpers/formatNumberWithCommas.ts +3 -0
  148. package/src/helpers/getBooleanFromString.ts +7 -0
  149. package/src/helpers/getDataFromXml.ts +80 -0
  150. package/src/helpers/getNumberFromString.ts +5 -0
  151. package/src/helpers/getRoomsWithRetry.ts +45 -0
  152. package/src/helpers/getTintedColor.ts +28 -0
  153. package/src/helpers/getUnnamedUsers.ts +39 -0
  154. package/src/helpers/handleCopyClick.ts +3 -0
  155. package/src/helpers/handleXmppError.ts +14 -0
  156. package/src/helpers/hashcolor.ts +34 -0
  157. package/src/helpers/historyPreloadScheduler.ts +264 -0
  158. package/src/helpers/initRoomsPresence.ts +32 -0
  159. package/src/helpers/initXmppRooms.tsx +71 -0
  160. package/src/helpers/insertMessageWithDelimiter.ts +96 -0
  161. package/src/helpers/isChatIdPresentInArray.ts +54 -0
  162. package/src/helpers/localStorageUser.ts +9 -0
  163. package/src/helpers/markdownParser.tsx +295 -0
  164. package/src/helpers/nanoToMs.ts +3 -0
  165. package/src/helpers/parseMessageBody.tsx +516 -0
  166. package/src/helpers/parseUrls.tsx +42 -0
  167. package/src/helpers/resolveInitBeforeLoadUser.ts +240 -0
  168. package/src/helpers/storeConsole.ts +26 -0
  169. package/src/helpers/transformTranslatations.ts +16 -0
  170. package/src/helpers/updateMessagesTillLast.tsx +104 -0
  171. package/src/helpers/updatedChatLastTimestamps.ts +29 -0
  172. package/src/helpers/validator.ts +20 -0
  173. package/src/helpers/walletUsername.ts +12 -0
  174. package/src/hooks/hooks.ts +6 -0
  175. package/src/hooks/useChatSettingState.tsx +38 -0
  176. package/src/hooks/useChatWrapperInit.ts +266 -0
  177. package/src/hooks/useComposing.tsx +59 -0
  178. package/src/hooks/useCustomTypingIndicator.tsx +193 -0
  179. package/src/hooks/useEventHandlers.tsx +81 -0
  180. package/src/hooks/useGetNewArchRoom.tsx +57 -0
  181. package/src/hooks/useHeapSender.tsx +88 -0
  182. package/src/hooks/useLocalStorage.tsx +53 -0
  183. package/src/hooks/useLogout.tsx +31 -0
  184. package/src/hooks/useMessageHeapState.tsx +11 -0
  185. package/src/hooks/useMessageLoaderQueue.tsx +90 -0
  186. package/src/hooks/useMessageQueue.ts +146 -0
  187. package/src/hooks/usePendingNotification.ts +49 -0
  188. package/src/hooks/usePrevious.tsx +15 -0
  189. package/src/hooks/usePushNotifications.ts +106 -0
  190. package/src/hooks/useQRCodeChatHandler.ts +58 -0
  191. package/src/hooks/useRoomInitialization.tsx +160 -0
  192. package/src/hooks/useRoomState.tsx +47 -0
  193. package/src/hooks/useRoomUrl.tsx +41 -0
  194. package/src/hooks/useSendMessage.tsx +306 -0
  195. package/src/hooks/useUnreadMessagesCounter.ts +55 -0
  196. package/src/hooks/useXmppInitialization.ts +148 -0
  197. package/src/main.ts +45 -0
  198. package/src/networking/api-requests/auth.api.ts +140 -0
  199. package/src/networking/api-requests/push.api.ts +55 -0
  200. package/src/networking/api-requests/roomMembers.api.ts +20 -0
  201. package/src/networking/api-requests/rooms.api.ts +142 -0
  202. package/src/networking/api-requests/user.api.ts +65 -0
  203. package/src/networking/apiClient.ts +149 -0
  204. package/src/networking/helpers/refreshChecker.ts +13 -0
  205. package/src/networking/stanzaHandlers.ts +418 -0
  206. package/src/networking/xmpp/actionSetTimestampToPrivateStore.xmpp.ts +37 -0
  207. package/src/networking/xmpp/allRoomPresences.xmpp.ts +10 -0
  208. package/src/networking/xmpp/createPrivateRoom.xmpp.ts +26 -0
  209. package/src/networking/xmpp/createRoom.xmpp.ts +35 -0
  210. package/src/networking/xmpp/createRoomPresence.xmpp.ts +74 -0
  211. package/src/networking/xmpp/createTimeoutPromise.xmpp.ts +15 -0
  212. package/src/networking/xmpp/deleteMessage.xmpp.ts +19 -0
  213. package/src/networking/xmpp/editMessage.xmpp.ts +46 -0
  214. package/src/networking/xmpp/getChatsPrivateStoreRequest.xmpp.ts +57 -0
  215. package/src/networking/xmpp/getHistory.xmpp.ts +140 -0
  216. package/src/networking/xmpp/getLastMessageArchive.xmpp.ts +24 -0
  217. package/src/networking/xmpp/getRoomInfo.xmpp.ts +15 -0
  218. package/src/networking/xmpp/getRoomMembers.xmpp.ts +13 -0
  219. package/src/networking/xmpp/getRooms.xmpp.ts +43 -0
  220. package/src/networking/xmpp/getRoomsPaged.xmpp.ts +59 -0
  221. package/src/networking/xmpp/handlePong.xmpp.ts +7 -0
  222. package/src/networking/xmpp/handleStanzas.xmpp.ts +55 -0
  223. package/src/networking/xmpp/inviteRoomRequest.xmpp.ts +25 -0
  224. package/src/networking/xmpp/leaveTheRoom.xmpp.ts +15 -0
  225. package/src/networking/xmpp/listenerManager.ts +116 -0
  226. package/src/networking/xmpp/presenceInRoom.xmpp.ts +57 -0
  227. package/src/networking/xmpp/roomConfig.xmpp.ts +71 -0
  228. package/src/networking/xmpp/sendMediaMessage.xmpp.ts +97 -0
  229. package/src/networking/xmpp/sendMessageReaction.xmpp.ts +41 -0
  230. package/src/networking/xmpp/sendPing.xmpp.ts +21 -0
  231. package/src/networking/xmpp/sendTextMessage.xmpp.ts +99 -0
  232. package/src/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.ts +44 -0
  233. package/src/networking/xmpp/sendTypingRequest.xmpp.ts +26 -0
  234. package/src/networking/xmpp/setChatsPrivateStoreRequest.xmpp.ts +48 -0
  235. package/src/networking/xmpp/setMeAsOwner.xmpp.ts +52 -0
  236. package/src/networking/xmpp/setRoomImage.xmpp.ts +26 -0
  237. package/src/networking/xmpp/setVCard.xmpp.ts +19 -0
  238. package/src/networking/xmpp/subscribeToRoomMessages.xmpp.ts +75 -0
  239. package/src/networking/xmppClient.ts +603 -0
  240. package/src/roomStore/Middleware/logoutMiddleware.tsx +24 -0
  241. package/src/roomStore/Middleware/newMessageMidlleware.tsx +87 -0
  242. package/src/roomStore/Middleware/reactionsMiddleware.tsx +77 -0
  243. package/src/roomStore/Middleware/testMiddleware.tsx +20 -0
  244. package/src/roomStore/Middleware/unreadMidlleware.tsx +58 -0
  245. package/src/roomStore/chatSettingsSlice.ts +178 -0
  246. package/src/roomStore/index.ts +68 -0
  247. package/src/roomStore/persistence.ts +152 -0
  248. package/src/roomStore/roomHeapSlice.ts +37 -0
  249. package/src/roomStore/roomsSlice.ts +353 -0
  250. package/src/services/pushNotifications.ts +170 -0
  251. package/src/services/pushSubscriptionService.ts +145 -0
  252. package/src/types/messages.ts +61 -0
  253. package/src/types/models/action.model.ts +30 -0
  254. package/src/types/models/config.model.ts +16 -0
  255. package/src/types/models/customComponents.model.ts +53 -0
  256. package/src/types/models/language.model.ts +11 -0
  257. package/src/types/models/media.model.ts +5 -0
  258. package/src/types/models/message.model.ts +69 -0
  259. package/src/types/models/modal.model.ts +9 -0
  260. package/src/types/models/room.model.ts +120 -0
  261. package/src/types/models/user.model.ts +90 -0
  262. package/src/types/models/xmpp.model.ts +155 -0
  263. package/src/types/types.ts +505 -0
  264. package/src/utils/PriorityQueue.ts +47 -0
  265. package/src/utils/actionHelpers.ts +40 -0
  266. package/src/utils/actionLogger.ts +64 -0
  267. package/src/utils/clientRegistry.ts +80 -0
  268. package/src/utils/devLogger.ts +197 -0
  269. package/src/utils/messageNotificationManager.ts +108 -0
  270. package/src/utils/resendMessage.ts +87 -0
  271. package/src/utils/toastEmitter.ts +27 -0
  272. package/src/utils/xmppMemoryMonitor.ts +63 -0
  273. package/src/version.ts +1 -0
@@ -0,0 +1,240 @@
1
+ import http, { setBaseURL } from '../networking/apiClient';
2
+ import { loginViaJwt } from '../networking/api-requests/auth.api';
3
+ import { getMyUser } from '../networking/api-requests/user.api';
4
+ import { IConfig, User } from '../types/types';
5
+ import { store } from '../roomStore';
6
+ import { setUser } from '../roomStore/chatSettingsSlice';
7
+ import { walletToUsername } from './walletUsername';
8
+ import { asyncLocalStorage } from '../hooks/useLocalStorage';
9
+ import { localStorageConstants } from './constants/LOCAL_STORAGE';
10
+
11
+ interface ResolveInitBeforeLoadUserOptions {
12
+ config?: IConfig;
13
+ signal?: AbortSignal;
14
+ }
15
+
16
+ interface HttpLikeError {
17
+ response?: { status?: number };
18
+ message?: string;
19
+ }
20
+
21
+ const getStatusCode = (error: unknown): number | null => {
22
+ const status = (error as HttpLikeError)?.response?.status;
23
+ return typeof status === 'number' ? status : null;
24
+ };
25
+
26
+ const isAuthError = (error: unknown): boolean => {
27
+ const code = getStatusCode(error);
28
+ return code === 401 || code === 403;
29
+ };
30
+
31
+ const isAbortError = (error: unknown): boolean => {
32
+ const message = (error as HttpLikeError)?.message || '';
33
+ return typeof message === 'string' && message.toLowerCase().includes('abort');
34
+ };
35
+
36
+ const hasXmppCredentials = (user?: Partial<User> | null): boolean =>
37
+ Boolean(
38
+ user?.xmppPassword &&
39
+ (user?.xmppUsername || user?.defaultWallet?.walletAddress)
40
+ );
41
+
42
+ const normalizeUserForXmpp = (user?: User | null): User | null => {
43
+ if (!user) {return null;}
44
+ const normalizedXmppUsername =
45
+ user.xmppUsername || walletToUsername(user?.defaultWallet?.walletAddress || '');
46
+ return { ...user, xmppUsername: normalizedXmppUsername };
47
+ };
48
+
49
+ const refreshWithToken = async (refreshToken: string) => {
50
+ const response = await http.post(
51
+ '/users/login/refresh',
52
+ {},
53
+ { headers: { Authorization: refreshToken } }
54
+ );
55
+ return {
56
+ token: response?.data?.token || '',
57
+ refreshToken: response?.data?.refreshToken || refreshToken,
58
+ };
59
+ };
60
+
61
+ const mergeUsers = (base?: User | null, patch?: User | null): User | null => {
62
+ if (!base && !patch) {return null;}
63
+ return {
64
+ ...(base || ({} as User)),
65
+ ...(patch || ({} as User)),
66
+ defaultWallet: {
67
+ walletAddress:
68
+ patch?.defaultWallet?.walletAddress ||
69
+ base?.defaultWallet?.walletAddress ||
70
+ '',
71
+ },
72
+ } as User;
73
+ };
74
+
75
+ const tryHydrateViaMy = async (
76
+ candidate: User,
77
+ myEndpoint?: string,
78
+ signal?: AbortSignal
79
+ ): Promise<User | null> => {
80
+ if (signal?.aborted) {return null;}
81
+
82
+ const mergedCandidate = normalizeUserForXmpp(candidate);
83
+
84
+ if (!candidate?.token && !candidate?.refreshToken) {
85
+ return mergedCandidate;
86
+ }
87
+
88
+ let workingToken = candidate?.token || '';
89
+ let workingRefresh = candidate?.refreshToken || '';
90
+
91
+ const candidateWithCurrentTokens = (): User => ({
92
+ ...candidate,
93
+ token: workingToken || candidate.token,
94
+ refreshToken: workingRefresh || candidate.refreshToken,
95
+ });
96
+
97
+ const fallbackWithCreds = (): User | null => {
98
+ const normalized = normalizeUserForXmpp(candidateWithCurrentTokens());
99
+ if (normalized && hasXmppCredentials(normalized)) {return normalized;}
100
+ return null;
101
+ };
102
+
103
+ if (workingToken) {
104
+ try {
105
+ const myUser = await getMyUser({ token: workingToken, endpoint: myEndpoint });
106
+ const merged = normalizeUserForXmpp(mergeUsers(candidate, myUser));
107
+ if (merged) {
108
+ merged.token = workingToken || merged.token;
109
+ merged.refreshToken = workingRefresh || merged.refreshToken;
110
+ }
111
+ return merged;
112
+ } catch (error) {
113
+ if (signal?.aborted || isAbortError(error)) {return null;}
114
+ if (isAuthError(error)) {
115
+ if (!workingRefresh) {return fallbackWithCreds();}
116
+ // fall through to refresh path
117
+ } else {
118
+ const fallback = fallbackWithCreds();
119
+ return fallback || null;
120
+ }
121
+ }
122
+ }
123
+
124
+ if (!workingRefresh) {return mergedCandidate;}
125
+
126
+ try {
127
+ const refreshed = await refreshWithToken(workingRefresh);
128
+ workingToken = refreshed.token;
129
+ workingRefresh = refreshed.refreshToken;
130
+
131
+ try {
132
+ const myUser = await getMyUser({ token: workingToken, endpoint: myEndpoint });
133
+ const merged = normalizeUserForXmpp(
134
+ mergeUsers(candidateWithCurrentTokens(), myUser)
135
+ );
136
+ if (merged) {
137
+ merged.token = workingToken || merged.token;
138
+ merged.refreshToken = workingRefresh || merged.refreshToken;
139
+ }
140
+ return merged;
141
+ } catch (myError) {
142
+ if (signal?.aborted || isAbortError(myError)) {return null;}
143
+ const fallback = fallbackWithCreds();
144
+ if (fallback) {return fallback;}
145
+ if (isAuthError(myError)) {return null;}
146
+ throw myError;
147
+ }
148
+ } catch (error) {
149
+ if (signal?.aborted || isAbortError(error)) {return null;}
150
+ if (isAuthError(error)) {return null;}
151
+ throw error;
152
+ }
153
+ };
154
+
155
+ export const resolveInitBeforeLoadUser = async (
156
+ options?: ResolveInitBeforeLoadUserOptions
157
+ ): Promise<User | null> => {
158
+ const { config, signal } = options || {};
159
+ if (signal?.aborted) {return null;}
160
+
161
+ if (config?.baseUrl) {
162
+ setBaseURL(config.baseUrl, config.customAppToken);
163
+ }
164
+
165
+ const myEndpoint = config?.initBeforeLoadAuth?.myEndpoint || '/users/my';
166
+
167
+ // Priority 1: explicit userLogin
168
+ const explicitUser = config?.userLogin?.enabled ? config?.userLogin?.user : null;
169
+ if (explicitUser) {
170
+ const candidate = normalizeUserForXmpp(explicitUser);
171
+ if (candidate && hasXmppCredentials(candidate)) {return candidate;}
172
+
173
+ const hydrated = await tryHydrateViaMy(explicitUser, myEndpoint, signal).catch(
174
+ () => null
175
+ );
176
+ if (hydrated && hasXmppCredentials(hydrated)) {return hydrated;}
177
+ return null;
178
+ }
179
+
180
+ // Priority 2: customLogin function
181
+ if (config?.customLogin?.enabled && config?.customLogin?.loginFunction) {
182
+ try {
183
+ const customUser = await config.customLogin.loginFunction();
184
+ if (customUser) {
185
+ const candidate = normalizeUserForXmpp(customUser);
186
+ if (candidate && hasXmppCredentials(candidate)) {return candidate;}
187
+ const hydrated = await tryHydrateViaMy(customUser, myEndpoint, signal).catch(
188
+ () => null
189
+ );
190
+ if (hydrated && hasXmppCredentials(hydrated)) {return hydrated;}
191
+ }
192
+ } catch (error) {
193
+ if (signal?.aborted || isAbortError(error) || isAuthError(error)) {return null;}
194
+ }
195
+ }
196
+
197
+ // Priority 3: jwtLogin (legacy)
198
+ if (config?.jwtLogin?.enabled && config?.jwtLogin?.token) {
199
+ try {
200
+ const jwtUser = await loginViaJwt(config.jwtLogin.token);
201
+ const normalized = normalizeUserForXmpp(jwtUser);
202
+ if (normalized && hasXmppCredentials(normalized)) {return normalized;}
203
+ } catch (error) {
204
+ if (signal?.aborted || isAbortError(error) || isAuthError(error)) {return null;}
205
+ throw error;
206
+ }
207
+ }
208
+
209
+ // Priority 4: redux store user (in-memory hot path)
210
+ const currentUser = store.getState().chatSettingStore.user;
211
+ if (currentUser?.token || currentUser?.refreshToken || currentUser?.xmppPassword) {
212
+ const hydrated = await tryHydrateViaMy(currentUser as User, myEndpoint, signal).catch(
213
+ () => null
214
+ );
215
+ if (hydrated && hasXmppCredentials(hydrated)) {return hydrated;}
216
+ }
217
+
218
+ // Priority 5: persisted user in AsyncStorage
219
+ try {
220
+ const storedUser = await asyncLocalStorage<User>(localStorageConstants.ETHORA_USER).get();
221
+ if (storedUser && (storedUser.token || storedUser.refreshToken || storedUser.xmppPassword)) {
222
+ const hydrated = await tryHydrateViaMy(storedUser, myEndpoint, signal).catch(
223
+ () => null
224
+ );
225
+ if (hydrated && hasXmppCredentials(hydrated)) {return hydrated;}
226
+ await asyncLocalStorage(localStorageConstants.ETHORA_USER).remove();
227
+ }
228
+ } catch {
229
+ // ignore storage errors
230
+ }
231
+
232
+ return null;
233
+ };
234
+
235
+ export const applyResolvedUserToStore = (user?: User | null) => {
236
+ if (!user) {return;}
237
+ store.dispatch(setUser(user));
238
+ };
239
+
240
+ export default resolveInitBeforeLoadUser;
@@ -0,0 +1,26 @@
1
+ import { RootState, store } from '../roomStore';
2
+
3
+ /**
4
+ * Return the current redux state. Mirrors web `useStoreConsole`.
5
+ * Attach to `globalThis.useStoreConsole` only when
6
+ * `config.useStoreConsoleEnabled === true`; clean up otherwise.
7
+ */
8
+ export const useStoreConsole = (): RootState => store.getState();
9
+
10
+ const g: any = globalThis as any;
11
+
12
+ const refresh = () => {
13
+ try {
14
+ const config = store.getState().chatSettingStore?.config;
15
+ if (config?.useStoreConsoleEnabled === true) {
16
+ g.useStoreConsole = useStoreConsole;
17
+ } else if (g.useStoreConsole) {
18
+ delete g.useStoreConsole;
19
+ }
20
+ } catch {
21
+ // ignore — state may not be ready yet
22
+ }
23
+ };
24
+
25
+ refresh();
26
+ store.subscribe(refresh);
@@ -0,0 +1,16 @@
1
+ interface Translation {
2
+ translatedText: string;
3
+ language: string;
4
+ languageName: string;
5
+ }
6
+ export interface TranslationObject {
7
+ [language: string]: Translation;
8
+ }
9
+ export const transformArrayToObject = (
10
+ array: Translation[]
11
+ ): TranslationObject => {
12
+ return array.reduce((acc, item) => {
13
+ acc[item.language] = item;
14
+ return acc;
15
+ }, {} as TranslationObject);
16
+ };
@@ -0,0 +1,104 @@
1
+ import XmppClient from '../networking/xmppClient';
2
+ import { store } from '../roomStore';
3
+ import {
4
+ getLastMessageTimestamp,
5
+ insertUsers,
6
+ setRoomMessages,
7
+ } from '../roomStore/roomsSlice';
8
+ import { IMessage, IRoom } from '../types/types';
9
+ import { checkUniqueUsers } from './checkUniqueUsers';
10
+
11
+ export const updateMessagesTillLast = async (
12
+ rooms: {
13
+ [jid: string]: IRoom;
14
+ },
15
+ client: XmppClient,
16
+ batchSize = 5,
17
+ maxFetchAttempts = 4,
18
+ messagesPerFetch = 5
19
+ ) => {
20
+ const roomEntries = Object.keys(rooms);
21
+ if (roomEntries.length > 0) {
22
+ let processedIndex = 0;
23
+
24
+ while (processedIndex < roomEntries.length) {
25
+ const currentBatch = roomEntries.slice(
26
+ processedIndex,
27
+ processedIndex + batchSize
28
+ );
29
+
30
+ const lastTimestampsByJid = currentBatch.reduce(
31
+ (acc, current: string) => {
32
+ acc[current] = getLastMessageTimestamp(
33
+ store.getState().rooms,
34
+ current
35
+ );
36
+ return acc;
37
+ },
38
+ {}
39
+ );
40
+
41
+ await Promise.all(
42
+ currentBatch.map(async (jid, index) => {
43
+ try {
44
+ if (index > 0) {await new Promise((res) => setTimeout(res, 125));}
45
+
46
+ let counter = 0;
47
+ let isMessageFound = false;
48
+ let currentJidNewMessages: IMessage[] = [];
49
+
50
+ const lastCachedMessagesTimeStamp = lastTimestampsByJid[jid];
51
+ if (!lastCachedMessagesTimeStamp) {return;}
52
+
53
+ while (!isMessageFound && counter < maxFetchAttempts) {
54
+ const lastMessageId =
55
+ counter > 0 ? currentJidNewMessages[0]?.id : undefined;
56
+
57
+ const fetchedMessages = await client.getHistoryStanza(
58
+ jid,
59
+ messagesPerFetch,
60
+ Number(lastMessageId)
61
+ );
62
+
63
+ if (!fetchedMessages.length) {break;}
64
+
65
+ counter++;
66
+
67
+ currentJidNewMessages = [
68
+ ...fetchedMessages,
69
+ ...currentJidNewMessages,
70
+ ];
71
+
72
+ isMessageFound = currentJidNewMessages.some(
73
+ (message: IMessage) =>
74
+ Number(message.id) === Number(lastCachedMessagesTimeStamp)
75
+ );
76
+
77
+ if (!isMessageFound && !(counter <= maxFetchAttempts - 1)) {
78
+ const fixedUsers = await checkUniqueUsers(
79
+ currentJidNewMessages
80
+ );
81
+ if (fixedUsers && fixedUsers.length > 0) {
82
+ store.dispatch(insertUsers({ newUsers: fixedUsers }));
83
+ }
84
+
85
+ store.dispatch(
86
+ setRoomMessages({
87
+ roomJID: jid,
88
+ messages: currentJidNewMessages,
89
+ })
90
+ );
91
+ }
92
+ }
93
+ } catch (error) {
94
+ console.error(`Error processing room ${jid}:`, error);
95
+ }
96
+ })
97
+ );
98
+
99
+ processedIndex += batchSize;
100
+ }
101
+ }
102
+
103
+ console.log('All rooms processed');
104
+ };
@@ -0,0 +1,29 @@
1
+ import { setLastViewedTimestamp } from '../roomStore/roomsSlice';
2
+
3
+ export const updatedChatLastTimestamps = (
4
+ roomTimestampObject: [jid: string, timestamp: string],
5
+ dispatch: any
6
+ ) => {
7
+ if (!roomTimestampObject) {return;}
8
+
9
+ if (roomTimestampObject && Object.keys(roomTimestampObject).length > 0) {
10
+ const roomTimestampArray = Object.entries(roomTimestampObject).map(
11
+ ([jid, timestamp]) => ({
12
+ jid,
13
+ timestamp,
14
+ })
15
+ );
16
+ console.log('getting roomTimestampArray', roomTimestampArray);
17
+
18
+ roomTimestampArray.forEach(({ jid, timestamp }) => {
19
+ if (jid) {
20
+ dispatch(
21
+ setLastViewedTimestamp({
22
+ chatJID: jid,
23
+ timestamp: Number(timestamp || 0),
24
+ })
25
+ );
26
+ }
27
+ });
28
+ }
29
+ };
@@ -0,0 +1,20 @@
1
+ import { IMessage } from '../types/types';
2
+
3
+ export const validateMessages = (messages: IMessage[]): boolean => {
4
+ const requiredAttributes: (keyof IMessage)[] = ['id', 'user', 'date', 'body'];
5
+ let isValid = true;
6
+ messages.forEach((message, index) => {
7
+ const missingAttributes = requiredAttributes.filter(
8
+ (attr) => !(attr in message)
9
+ );
10
+ if (missingAttributes.length > 0) {
11
+ console.error(
12
+ `Message at index ${index} is missing attributes: ${missingAttributes.join(
13
+ ', '
14
+ )}`
15
+ );
16
+ isValid = false;
17
+ }
18
+ });
19
+ return isValid;
20
+ };
@@ -0,0 +1,12 @@
1
+ export function walletToUsername(string: string) {
2
+ if (string) {
3
+ return string.replaceAll(/([A-Z])/g, '_$1').toLowerCase();
4
+ }
5
+ return '';
6
+ }
7
+
8
+ export function usernameToWallet(string: string) {
9
+ return string.replaceAll(/_([a-z])/gm, (m1: string, m2: string) => {
10
+ return m2.toUpperCase();
11
+ });
12
+ }
@@ -0,0 +1,6 @@
1
+ import { useDispatch, useSelector } from 'react-redux';
2
+ import type { TypedUseSelectorHook } from 'react-redux';
3
+ import type { RootState, AppDispatch } from '../roomStore';
4
+
5
+ export const useAppDispatch: () => AppDispatch = useDispatch;
6
+ export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
@@ -0,0 +1,38 @@
1
+ import { useSelector } from 'react-redux';
2
+ import { RootState } from '../roomStore';
3
+
4
+ export const useChatSettingState = () => {
5
+ const user = useSelector((state: RootState) => state.chatSettingStore.user);
6
+ const activeFile = useSelector(
7
+ (state: RootState) => state.chatSettingStore.activeFile
8
+ );
9
+ const activeModal = useSelector(
10
+ (state: RootState) => state.chatSettingStore.activeModal
11
+ );
12
+ const config = useSelector(
13
+ (state: RootState) => state.chatSettingStore.config
14
+ );
15
+ const deleteModal = useSelector(
16
+ (state: RootState) => state.chatSettingStore.deleteModal
17
+ );
18
+ const selectedUser = useSelector(
19
+ (state: RootState) => state.chatSettingStore.selectedUser
20
+ );
21
+ const langSource = useSelector(
22
+ (state: RootState) => state.chatSettingStore.langSource
23
+ );
24
+ const client = useSelector(
25
+ (state: RootState) => state.chatSettingStore.client
26
+ );
27
+
28
+ return {
29
+ user,
30
+ activeFile,
31
+ activeModal,
32
+ config,
33
+ deleteModal,
34
+ selectedUser,
35
+ langSource,
36
+ client,
37
+ };
38
+ };