@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.
- package/LICENSE +661 -0
- package/README.md +148 -0
- package/empty-shim.js +15 -0
- package/index.js +13 -0
- package/metro.js +72 -0
- package/package.json +99 -0
- package/src/api.config.ts +34 -0
- package/src/assets/BG.png +0 -0
- package/src/assets/BG.tsx +56 -0
- package/src/assets/File.svg +4 -0
- package/src/assets/ForzaCare.png +0 -0
- package/src/assets/ForzaCare.tsx +27 -0
- package/src/assets/icons.tsx +685 -0
- package/src/assets/images.tsx +41 -0
- package/src/assets/test.xml +243 -0
- package/src/components/AuthForms/Login.tsx +295 -0
- package/src/components/AuthForms/LoginAnonym.tsx +68 -0
- package/src/components/AuthForms/Register.tsx +8 -0
- package/src/components/ContextMenu/ContextMenuComponents.tsx +87 -0
- package/src/components/DropdownMenu/DropdownMenu.tsx +244 -0
- package/src/components/ExampleComponents/CustomMessage.tsx +92 -0
- package/src/components/ExampleComponents/CustomTypingIndicatorExamples.tsx +239 -0
- package/src/components/Header/HeaderRoomList.tsx +104 -0
- package/src/components/InputComponents/AudioInput.tsx +24 -0
- package/src/components/InputComponents/AudioRecorder.tsx +100 -0
- package/src/components/InputComponents/MediaInput.tsx +114 -0
- package/src/components/InputComponents/RecordingIndicator.tsx +77 -0
- package/src/components/InputComponents/Search.tsx +135 -0
- package/src/components/InputComponents/TextInput.tsx +66 -0
- package/src/components/MainComponents/ChatHeader.tsx +163 -0
- package/src/components/MainComponents/ChatRoom.tsx +392 -0
- package/src/components/MainComponents/ChatWrapper.tsx +318 -0
- package/src/components/MainComponents/ChooseChatMessage.tsx +44 -0
- package/src/components/MainComponents/ConnectionBanner.tsx +33 -0
- package/src/components/MainComponents/EditWrapper.tsx +72 -0
- package/src/components/MainComponents/LoginWrapper.tsx +134 -0
- package/src/components/MainComponents/MediaMessage.tsx +55 -0
- package/src/components/MainComponents/MessageContainer.tsx +122 -0
- package/src/components/MainComponents/MessageList.tsx +429 -0
- package/src/components/MainComponents/NoMessagesPlaceholder.tsx +49 -0
- package/src/components/MainComponents/ProfileImagePlaceholder.tsx +143 -0
- package/src/components/MainComponents/RNStyled.tsx +34 -0
- package/src/components/MainComponents/ReduxWrapper.tsx +40 -0
- package/src/components/MainComponents/RoomList.tsx +246 -0
- package/src/components/MainComponents/Select.tsx +165 -0
- package/src/components/MainComponents/Switch.tsx +73 -0
- package/src/components/MainComponents/SystemMessage.tsx +42 -0
- package/src/components/Menu/HeaderRoomListMenu.tsx +169 -0
- package/src/components/MenuRoom/MenuRoom.tsx +46 -0
- package/src/components/MessageBubble/Avatar.tsx +84 -0
- package/src/components/MessageBubble/BottomReplyContainer.tsx +117 -0
- package/src/components/MessageBubble/CustomDivider.tsx +10 -0
- package/src/components/MessageBubble/DeletedMessage.tsx +36 -0
- package/src/components/MessageBubble/Message.tsx +400 -0
- package/src/components/MessageBubble/MessageInteractions.tsx +247 -0
- package/src/components/MessageBubble/MessageReaction.tsx +149 -0
- package/src/components/MessageBubble/MessageReply.tsx +50 -0
- package/src/components/MessageBubble/MessageTranslations.tsx +30 -0
- package/src/components/Modals/AddMembersModal/AddMembersModal.tsx +142 -0
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +471 -0
- package/src/components/Modals/ChatProfileModal/DeleteChatModal.tsx +91 -0
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +298 -0
- package/src/components/Modals/Modal/Modal.tsx +52 -0
- package/src/components/Modals/ModalHeaderComponent.tsx +41 -0
- package/src/components/Modals/ModalSelectMedia/ModalSelectMedia.tsx +285 -0
- package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +103 -0
- package/src/components/Modals/NewChatModal/ModalContent.tsx +151 -0
- package/src/components/Modals/NewChatModal/NewChatModal.tsx +391 -0
- package/src/components/Modals/NewChatModal/UpdNewChatModal.tsx +136 -0
- package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +134 -0
- package/src/components/Modals/SettingsModals/BlockedUsers/BlockedUsersModal.tsx +63 -0
- package/src/components/Modals/SettingsModals/DocumentShares/DocumentSharesModal.tsx +115 -0
- package/src/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.tsx +121 -0
- package/src/components/Modals/SettingsModals/ManageDataModal/StyledComponents.ts +0 -0
- package/src/components/Modals/SettingsModals/ProfileShares/ProfileShares.tsx +65 -0
- package/src/components/Modals/SettingsModals/Referrals/Referrals.tsx +90 -0
- package/src/components/Modals/SettingsModals/SharedStyledComponents.ts +74 -0
- package/src/components/Modals/SettingsModals/Visibility/RadioInput.tsx +59 -0
- package/src/components/Modals/SettingsModals/Visibility/StyledComponents.ts +32 -0
- package/src/components/Modals/SettingsModals/Visibility/VisibilityModal.tsx +146 -0
- package/src/components/Modals/UserProfileModal/EditUserModal.tsx +163 -0
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +410 -0
- package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +85 -0
- package/src/components/Modals/styledModalComponents.tsx +181 -0
- package/src/components/OperationalModal/OperationalModal.tsx +78 -0
- package/src/components/RoomComponents/ChatRoomItem.tsx +219 -0
- package/src/components/RoomComponents/LastMessageItem.tsx +47 -0
- package/src/components/RoomComponents/styled/LastAudioMessage.tsx +62 -0
- package/src/components/RoomComponents/styled/LastMessageEmoji.tsx +26 -0
- package/src/components/RoomComponents/styled/LastMessageFile.tsx +54 -0
- package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +54 -0
- package/src/components/RoomComponents/styled/LastMessageVideo.tsx +70 -0
- package/src/components/RoomComponents/styled/LastTextMessage.tsx +65 -0
- package/src/components/RoomComponents/styled/StyledRoomComponents.ts +53 -0
- package/src/components/SortDropDown/index.tsx +76 -0
- package/src/components/Thread/ThreadHeader.tsx +41 -0
- package/src/components/Thread/ThreadWrapper.tsx +270 -0
- package/src/components/Toast/Toast.tsx +128 -0
- package/src/components/Toast/index.ts +13 -0
- package/src/components/UsersList/StyledComponents.ts +30 -0
- package/src/components/UsersList/UsersList.tsx +112 -0
- package/src/components/styled/ActionButton.tsx +40 -0
- package/src/components/styled/AudioMessage.tsx +82 -0
- package/src/components/styled/Button.tsx +107 -0
- package/src/components/styled/ChatWrapperBox.tsx +9 -0
- package/src/components/styled/DateLabel.tsx +77 -0
- package/src/components/styled/Loader.tsx +65 -0
- package/src/components/styled/MediaFilePreview.tsx +42 -0
- package/src/components/styled/MediaModal.tsx +54 -0
- package/src/components/styled/MessageImage.tsx +54 -0
- package/src/components/styled/NewMessageLabel.tsx +50 -0
- package/src/components/styled/RoomListComponents/index.tsx +164 -0
- package/src/components/styled/SendInput.tsx +297 -0
- package/src/components/styled/StyledComponents.ts +320 -0
- package/src/components/styled/StyledInput.tsx +101 -0
- package/src/components/styled/StyledInputComponents/AudioComponents.tsx +1 -0
- package/src/components/styled/StyledInputComponents/Composing.tsx +97 -0
- package/src/components/styled/StyledInputComponents/CustomTypingIndicator.tsx +261 -0
- package/src/components/styled/StyledInputComponents/MediaComponents.tsx +90 -0
- package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +131 -0
- package/src/components/styled/StyledInputComponents/VideoComponents.tsx +49 -0
- package/src/components/styled/TreadLabel.tsx +50 -0
- package/src/components/styled/UnsupportedType.tsx +95 -0
- package/src/components/styled/VideoMessage.tsx +68 -0
- package/src/context/MessageNotificationContext.tsx +335 -0
- package/src/context/PushNotificationProvider.tsx +78 -0
- package/src/context/ToastContext.tsx +63 -0
- package/src/context/toastProvider.tsx +0 -0
- package/src/context/xmppProvider.tsx +364 -0
- package/src/helpers/block_scroll.ts +95 -0
- package/src/helpers/chatAutoEnterer.ts +46 -0
- package/src/helpers/checkUniqueUsers.tsx +31 -0
- package/src/helpers/constants/CHAT_TYPES.ts +6 -0
- package/src/helpers/constants/LANGUAGE_OPTIONS.ts +14 -0
- package/src/helpers/constants/LOCAL_STORAGE.ts +3 -0
- package/src/helpers/constants/MESSAGE_INTERACTIONS.ts +29 -0
- package/src/helpers/constants/MODAL_TYPES.ts +57 -0
- package/src/helpers/constants/PLATFORM_CONSTANTS.ts +3 -0
- package/src/helpers/createMainMessageForThread.ts +23 -0
- package/src/helpers/createMessageFromXml.ts +118 -0
- package/src/helpers/createRoomFromApi.tsx +27 -0
- package/src/helpers/createUserNameFromSetUser.ts +15 -0
- package/src/helpers/dateComparison.ts +12 -0
- package/src/helpers/debounce.ts +10 -0
- package/src/helpers/ensureScopedChatCache.ts +61 -0
- package/src/helpers/extractUniqueMembersFromRooms.ts +45 -0
- package/src/helpers/formatNumberWithCommas.ts +3 -0
- package/src/helpers/getBooleanFromString.ts +7 -0
- package/src/helpers/getDataFromXml.ts +80 -0
- package/src/helpers/getNumberFromString.ts +5 -0
- package/src/helpers/getRoomsWithRetry.ts +45 -0
- package/src/helpers/getTintedColor.ts +28 -0
- package/src/helpers/getUnnamedUsers.ts +39 -0
- package/src/helpers/handleCopyClick.ts +3 -0
- package/src/helpers/handleXmppError.ts +14 -0
- package/src/helpers/hashcolor.ts +34 -0
- package/src/helpers/historyPreloadScheduler.ts +264 -0
- package/src/helpers/initRoomsPresence.ts +32 -0
- package/src/helpers/initXmppRooms.tsx +71 -0
- package/src/helpers/insertMessageWithDelimiter.ts +96 -0
- package/src/helpers/isChatIdPresentInArray.ts +54 -0
- package/src/helpers/localStorageUser.ts +9 -0
- package/src/helpers/markdownParser.tsx +295 -0
- package/src/helpers/nanoToMs.ts +3 -0
- package/src/helpers/parseMessageBody.tsx +516 -0
- package/src/helpers/parseUrls.tsx +42 -0
- package/src/helpers/resolveInitBeforeLoadUser.ts +240 -0
- package/src/helpers/storeConsole.ts +26 -0
- package/src/helpers/transformTranslatations.ts +16 -0
- package/src/helpers/updateMessagesTillLast.tsx +104 -0
- package/src/helpers/updatedChatLastTimestamps.ts +29 -0
- package/src/helpers/validator.ts +20 -0
- package/src/helpers/walletUsername.ts +12 -0
- package/src/hooks/hooks.ts +6 -0
- package/src/hooks/useChatSettingState.tsx +38 -0
- package/src/hooks/useChatWrapperInit.ts +266 -0
- package/src/hooks/useComposing.tsx +59 -0
- package/src/hooks/useCustomTypingIndicator.tsx +193 -0
- package/src/hooks/useEventHandlers.tsx +81 -0
- package/src/hooks/useGetNewArchRoom.tsx +57 -0
- package/src/hooks/useHeapSender.tsx +88 -0
- package/src/hooks/useLocalStorage.tsx +53 -0
- package/src/hooks/useLogout.tsx +31 -0
- package/src/hooks/useMessageHeapState.tsx +11 -0
- package/src/hooks/useMessageLoaderQueue.tsx +90 -0
- package/src/hooks/useMessageQueue.ts +146 -0
- package/src/hooks/usePendingNotification.ts +49 -0
- package/src/hooks/usePrevious.tsx +15 -0
- package/src/hooks/usePushNotifications.ts +106 -0
- package/src/hooks/useQRCodeChatHandler.ts +58 -0
- package/src/hooks/useRoomInitialization.tsx +160 -0
- package/src/hooks/useRoomState.tsx +47 -0
- package/src/hooks/useRoomUrl.tsx +41 -0
- package/src/hooks/useSendMessage.tsx +306 -0
- package/src/hooks/useUnreadMessagesCounter.ts +55 -0
- package/src/hooks/useXmppInitialization.ts +148 -0
- package/src/main.ts +45 -0
- package/src/networking/api-requests/auth.api.ts +140 -0
- package/src/networking/api-requests/push.api.ts +55 -0
- package/src/networking/api-requests/roomMembers.api.ts +20 -0
- package/src/networking/api-requests/rooms.api.ts +142 -0
- package/src/networking/api-requests/user.api.ts +65 -0
- package/src/networking/apiClient.ts +149 -0
- package/src/networking/helpers/refreshChecker.ts +13 -0
- package/src/networking/stanzaHandlers.ts +418 -0
- package/src/networking/xmpp/actionSetTimestampToPrivateStore.xmpp.ts +37 -0
- package/src/networking/xmpp/allRoomPresences.xmpp.ts +10 -0
- package/src/networking/xmpp/createPrivateRoom.xmpp.ts +26 -0
- package/src/networking/xmpp/createRoom.xmpp.ts +35 -0
- package/src/networking/xmpp/createRoomPresence.xmpp.ts +74 -0
- package/src/networking/xmpp/createTimeoutPromise.xmpp.ts +15 -0
- package/src/networking/xmpp/deleteMessage.xmpp.ts +19 -0
- package/src/networking/xmpp/editMessage.xmpp.ts +46 -0
- package/src/networking/xmpp/getChatsPrivateStoreRequest.xmpp.ts +57 -0
- package/src/networking/xmpp/getHistory.xmpp.ts +140 -0
- package/src/networking/xmpp/getLastMessageArchive.xmpp.ts +24 -0
- package/src/networking/xmpp/getRoomInfo.xmpp.ts +15 -0
- package/src/networking/xmpp/getRoomMembers.xmpp.ts +13 -0
- package/src/networking/xmpp/getRooms.xmpp.ts +43 -0
- package/src/networking/xmpp/getRoomsPaged.xmpp.ts +59 -0
- package/src/networking/xmpp/handlePong.xmpp.ts +7 -0
- package/src/networking/xmpp/handleStanzas.xmpp.ts +55 -0
- package/src/networking/xmpp/inviteRoomRequest.xmpp.ts +25 -0
- package/src/networking/xmpp/leaveTheRoom.xmpp.ts +15 -0
- package/src/networking/xmpp/listenerManager.ts +116 -0
- package/src/networking/xmpp/presenceInRoom.xmpp.ts +57 -0
- package/src/networking/xmpp/roomConfig.xmpp.ts +71 -0
- package/src/networking/xmpp/sendMediaMessage.xmpp.ts +97 -0
- package/src/networking/xmpp/sendMessageReaction.xmpp.ts +41 -0
- package/src/networking/xmpp/sendPing.xmpp.ts +21 -0
- package/src/networking/xmpp/sendTextMessage.xmpp.ts +99 -0
- package/src/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.ts +44 -0
- package/src/networking/xmpp/sendTypingRequest.xmpp.ts +26 -0
- package/src/networking/xmpp/setChatsPrivateStoreRequest.xmpp.ts +48 -0
- package/src/networking/xmpp/setMeAsOwner.xmpp.ts +52 -0
- package/src/networking/xmpp/setRoomImage.xmpp.ts +26 -0
- package/src/networking/xmpp/setVCard.xmpp.ts +19 -0
- package/src/networking/xmpp/subscribeToRoomMessages.xmpp.ts +75 -0
- package/src/networking/xmppClient.ts +603 -0
- package/src/roomStore/Middleware/logoutMiddleware.tsx +24 -0
- package/src/roomStore/Middleware/newMessageMidlleware.tsx +87 -0
- package/src/roomStore/Middleware/reactionsMiddleware.tsx +77 -0
- package/src/roomStore/Middleware/testMiddleware.tsx +20 -0
- package/src/roomStore/Middleware/unreadMidlleware.tsx +58 -0
- package/src/roomStore/chatSettingsSlice.ts +178 -0
- package/src/roomStore/index.ts +68 -0
- package/src/roomStore/persistence.ts +152 -0
- package/src/roomStore/roomHeapSlice.ts +37 -0
- package/src/roomStore/roomsSlice.ts +353 -0
- package/src/services/pushNotifications.ts +170 -0
- package/src/services/pushSubscriptionService.ts +145 -0
- package/src/types/messages.ts +61 -0
- package/src/types/models/action.model.ts +30 -0
- package/src/types/models/config.model.ts +16 -0
- package/src/types/models/customComponents.model.ts +53 -0
- package/src/types/models/language.model.ts +11 -0
- package/src/types/models/media.model.ts +5 -0
- package/src/types/models/message.model.ts +69 -0
- package/src/types/models/modal.model.ts +9 -0
- package/src/types/models/room.model.ts +120 -0
- package/src/types/models/user.model.ts +90 -0
- package/src/types/models/xmpp.model.ts +155 -0
- package/src/types/types.ts +505 -0
- package/src/utils/PriorityQueue.ts +47 -0
- package/src/utils/actionHelpers.ts +40 -0
- package/src/utils/actionLogger.ts +64 -0
- package/src/utils/clientRegistry.ts +80 -0
- package/src/utils/devLogger.ts +197 -0
- package/src/utils/messageNotificationManager.ts +108 -0
- package/src/utils/resendMessage.ts +87 -0
- package/src/utils/toastEmitter.ts +27 -0
- package/src/utils/xmppMemoryMonitor.ts +63 -0
- 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
|
+
};
|