@ethora/chat-component-rn 26.5.5 → 26.5.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +177 -0
- package/README.md +67 -10
- package/index.js +24 -0
- package/lib/commonjs/assets/icons.js +5 -1
- package/lib/commonjs/assets/icons.js.map +1 -1
- package/lib/commonjs/components/ContextMenu/ContextMenuComponents.js +11 -5
- package/lib/commonjs/components/ContextMenu/ContextMenuComponents.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js +7 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatRoom.js +66 -34
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +59 -14
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +15 -7
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageContainer.js +2 -2
- package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageList.js +175 -30
- package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ReduxWrapper.js +17 -8
- package/lib/commonjs/components/MainComponents/ReduxWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/SystemMessage.js +34 -22
- package/lib/commonjs/components/MainComponents/SystemMessage.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/Message.js +117 -19
- package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js +82 -22
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +16 -4
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/DocumentViewer.js +104 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/DocumentViewer.js.map +1 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +175 -40
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js +29 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/commonjs/components/Modals/Modal/Modal.js +5 -1
- package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js +78 -39
- package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +3 -3
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/styledModalComponents.js +4 -9
- package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/commonjs/components/styled/MediaFilePreview.js +115 -5
- package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/commonjs/components/styled/MessageImage.js +49 -10
- package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
- package/lib/commonjs/components/styled/NewMessageLabel.js +8 -6
- package/lib/commonjs/components/styled/NewMessageLabel.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +53 -29
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/StyledInputComponents/MediaComponents.js +14 -4
- package/lib/commonjs/components/styled/StyledInputComponents/MediaComponents.js.map +1 -1
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +7 -2
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/commonjs/components/styled/UnsupportedType.js +5 -1
- package/lib/commonjs/components/styled/UnsupportedType.js.map +1 -1
- package/lib/commonjs/components/styled/VideoMessage.js +60 -22
- package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
- package/lib/commonjs/context/MessageNotificationContext.js +7 -7
- package/lib/commonjs/context/MessageNotificationContext.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +315 -34
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/chatAutoEnterer.js +2 -7
- package/lib/commonjs/helpers/chatAutoEnterer.js.map +1 -1
- package/lib/commonjs/helpers/historyPreloadScheduler.js +4 -1
- package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js +15 -5
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/commonjs/helpers/keyboardLayout.js +18 -0
- package/lib/commonjs/helpers/keyboardLayout.js.map +1 -0
- package/lib/commonjs/helpers/mediaDimensions.js +51 -0
- package/lib/commonjs/helpers/mediaDimensions.js.map +1 -0
- package/lib/commonjs/helpers/mimeToExtension.js +131 -0
- package/lib/commonjs/helpers/mimeToExtension.js.map +1 -0
- package/lib/commonjs/helpers/normalizeRoomJid.js +20 -0
- package/lib/commonjs/helpers/normalizeRoomJid.js.map +1 -0
- package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js +73 -1
- package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js.map +1 -1
- package/lib/commonjs/hooks/useChatRoomFocus.js +87 -0
- package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -0
- package/lib/commonjs/hooks/useChatWrapperInit.js +22 -10
- package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/commonjs/hooks/useEventHandlers.js +9 -1
- package/lib/commonjs/hooks/useEventHandlers.js.map +1 -1
- package/lib/commonjs/hooks/useHeapSender.js +1 -1
- package/lib/commonjs/hooks/useHeapSender.js.map +1 -1
- package/lib/commonjs/hooks/useLogout.js +3 -3
- package/lib/commonjs/hooks/useLogout.js.map +1 -1
- package/lib/commonjs/hooks/useMessageHeapState.js +6 -2
- package/lib/commonjs/hooks/useMessageHeapState.js.map +1 -1
- package/lib/commonjs/hooks/usePushNotifications.js +6 -2
- package/lib/commonjs/hooks/usePushNotifications.js.map +1 -1
- package/lib/commonjs/hooks/useRoomState.js +2 -0
- package/lib/commonjs/hooks/useRoomState.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +249 -14
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js +12 -14
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/commonjs/main.js +7 -0
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/auth.api.js +74 -1
- package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
- package/lib/commonjs/networking/apiClient.js +2 -1
- package/lib/commonjs/networking/apiClient.js.map +1 -1
- package/lib/commonjs/networking/outboundQueue.js +92 -0
- package/lib/commonjs/networking/outboundQueue.js.map +1 -0
- package/lib/commonjs/networking/xmpp/createTimeoutPromise.xmpp.js +4 -1
- package/lib/commonjs/networking/xmpp/createTimeoutPromise.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +7 -8
- package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
- package/lib/commonjs/networking/xmpp/getRoomsPaged.xmpp.js +26 -3
- package/lib/commonjs/networking/xmpp/getRoomsPaged.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +26 -8
- package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js +2 -1
- package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmppClient.js +371 -26
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js +22 -6
- package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js.map +1 -1
- package/lib/commonjs/roomStore/roomHeapSlice.js +26 -8
- package/lib/commonjs/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +157 -23
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/commonjs/utils/installPromiseRejectionTracker.js +83 -0
- package/lib/commonjs/utils/installPromiseRejectionTracker.js.map +1 -0
- package/lib/commonjs/utils/resendMessage.js +1 -1
- package/lib/commonjs/utils/resendMessage.js.map +1 -1
- package/lib/module/assets/icons.js +5 -1
- package/lib/module/assets/icons.js.map +1 -1
- package/lib/module/components/ContextMenu/ContextMenuComponents.js +11 -5
- package/lib/module/components/ContextMenu/ContextMenuComponents.js.map +1 -1
- package/lib/module/components/MainComponents/ChatHeader.js +7 -1
- package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/module/components/MainComponents/ChatRoom.js +67 -35
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +59 -14
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +15 -7
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MainComponents/MessageContainer.js +2 -2
- package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/module/components/MainComponents/MessageList.js +176 -31
- package/lib/module/components/MainComponents/MessageList.js.map +1 -1
- package/lib/module/components/MainComponents/ReduxWrapper.js +18 -8
- package/lib/module/components/MainComponents/ReduxWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/SystemMessage.js +33 -21
- package/lib/module/components/MainComponents/SystemMessage.js.map +1 -1
- package/lib/module/components/MessageBubble/Message.js +118 -20
- package/lib/module/components/MessageBubble/Message.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js +84 -24
- package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js +15 -3
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/DocumentViewer.js +99 -0
- package/lib/module/components/Modals/FilePreviewModal/DocumentViewer.js.map +1 -0
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +179 -42
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js +31 -3
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/module/components/Modals/Modal/Modal.js +5 -1
- package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js +80 -41
- package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +3 -3
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/module/components/Modals/styledModalComponents.js +4 -9
- package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/module/components/styled/MediaFilePreview.js +116 -6
- package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/module/components/styled/MessageImage.js +51 -12
- package/lib/module/components/styled/MessageImage.js.map +1 -1
- package/lib/module/components/styled/NewMessageLabel.js +8 -6
- package/lib/module/components/styled/NewMessageLabel.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +54 -30
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/StyledInputComponents/MediaComponents.js +14 -4
- package/lib/module/components/styled/StyledInputComponents/MediaComponents.js.map +1 -1
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +7 -2
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/module/components/styled/UnsupportedType.js +5 -1
- package/lib/module/components/styled/UnsupportedType.js.map +1 -1
- package/lib/module/components/styled/VideoMessage.js +61 -23
- package/lib/module/components/styled/VideoMessage.js.map +1 -1
- package/lib/module/context/MessageNotificationContext.js +7 -7
- package/lib/module/context/MessageNotificationContext.js.map +1 -1
- package/lib/module/context/xmppProvider.js +319 -37
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/chatAutoEnterer.js +2 -7
- package/lib/module/helpers/chatAutoEnterer.js.map +1 -1
- package/lib/module/helpers/historyPreloadScheduler.js +4 -1
- package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/module/helpers/insertMessageWithDelimiter.js +15 -5
- package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/module/helpers/keyboardLayout.js +12 -0
- package/lib/module/helpers/keyboardLayout.js.map +1 -0
- package/lib/module/helpers/mediaDimensions.js +46 -0
- package/lib/module/helpers/mediaDimensions.js.map +1 -0
- package/lib/module/helpers/mimeToExtension.js +124 -0
- package/lib/module/helpers/mimeToExtension.js.map +1 -0
- package/lib/module/helpers/normalizeRoomJid.js +15 -0
- package/lib/module/helpers/normalizeRoomJid.js.map +1 -0
- package/lib/module/helpers/resolveInitBeforeLoadUser.js +71 -0
- package/lib/module/helpers/resolveInitBeforeLoadUser.js.map +1 -1
- package/lib/module/hooks/useChatRoomFocus.js +82 -0
- package/lib/module/hooks/useChatRoomFocus.js.map +1 -0
- package/lib/module/hooks/useChatWrapperInit.js +22 -10
- package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/module/hooks/useEventHandlers.js +9 -1
- package/lib/module/hooks/useEventHandlers.js.map +1 -1
- package/lib/module/hooks/useHeapSender.js +1 -1
- package/lib/module/hooks/useHeapSender.js.map +1 -1
- package/lib/module/hooks/useLogout.js +3 -3
- package/lib/module/hooks/useLogout.js.map +1 -1
- package/lib/module/hooks/useMessageHeapState.js +6 -2
- package/lib/module/hooks/useMessageHeapState.js.map +1 -1
- package/lib/module/hooks/usePushNotifications.js +6 -2
- package/lib/module/hooks/usePushNotifications.js.map +1 -1
- package/lib/module/hooks/useRoomState.js +2 -0
- package/lib/module/hooks/useRoomState.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +252 -17
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/hooks/useUnreadMessagesCounter.js +12 -14
- package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/module/main.js +1 -0
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/auth.api.js +74 -2
- package/lib/module/networking/api-requests/auth.api.js.map +1 -1
- package/lib/module/networking/apiClient.js +2 -1
- package/lib/module/networking/apiClient.js.map +1 -1
- package/lib/module/networking/outboundQueue.js +84 -0
- package/lib/module/networking/outboundQueue.js.map +1 -0
- package/lib/module/networking/xmpp/createTimeoutPromise.xmpp.js +4 -1
- package/lib/module/networking/xmpp/createTimeoutPromise.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +7 -8
- package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
- package/lib/module/networking/xmpp/getRoomsPaged.xmpp.js +26 -3
- package/lib/module/networking/xmpp/getRoomsPaged.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +26 -8
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/sendTextMessage.xmpp.js +2 -1
- package/lib/module/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
- package/lib/module/networking/xmppClient.js +371 -26
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/Middleware/unreadMidlleware.js +22 -6
- package/lib/module/roomStore/Middleware/unreadMidlleware.js.map +1 -1
- package/lib/module/roomStore/roomHeapSlice.js +24 -7
- package/lib/module/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +154 -22
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/utils/installPromiseRejectionTracker.js +78 -0
- package/lib/module/utils/installPromiseRejectionTracker.js.map +1 -0
- package/lib/module/utils/resendMessage.js +1 -1
- package/lib/module/utils/resendMessage.js.map +1 -1
- package/lib/typescript/assets/icons.d.ts +8 -4
- package/lib/typescript/assets/icons.d.ts.map +1 -1
- package/lib/typescript/components/ContextMenu/ContextMenuComponents.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts +1 -0
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts +1 -0
- package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/SystemMessage.d.ts +0 -7
- package/lib/typescript/components/MainComponents/SystemMessage.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts +4 -2
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
- package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/DocumentViewer.d.ts +29 -0
- package/lib/typescript/components/Modals/FilePreviewModal/DocumentViewer.d.ts.map +1 -0
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts +0 -1
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/PdfView.d.ts.map +1 -1
- package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ModalWrapper/ModalWrapper.d.ts +6 -0
- package/lib/typescript/components/Modals/ModalWrapper/ModalWrapper.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/MediaFilePreview.d.ts.map +1 -1
- package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
- package/lib/typescript/components/styled/NewMessageLabel.d.ts +1 -5
- package/lib/typescript/components/styled/NewMessageLabel.d.ts.map +1 -1
- package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledInputComponents/MediaComponents.d.ts +9 -1
- package/lib/typescript/components/styled/StyledInputComponents/MediaComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/UnsupportedType.d.ts +1 -0
- package/lib/typescript/components/styled/UnsupportedType.d.ts.map +1 -1
- package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts +1 -0
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/chatAutoEnterer.d.ts.map +1 -1
- package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
- package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
- package/lib/typescript/helpers/keyboardLayout.d.ts +9 -0
- package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -0
- package/lib/typescript/helpers/mediaDimensions.d.ts +9 -0
- package/lib/typescript/helpers/mediaDimensions.d.ts.map +1 -0
- package/lib/typescript/helpers/mimeToExtension.d.ts +37 -0
- package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -0
- package/lib/typescript/helpers/normalizeRoomJid.d.ts +2 -0
- package/lib/typescript/helpers/normalizeRoomJid.d.ts.map +1 -0
- package/lib/typescript/helpers/resolveInitBeforeLoadUser.d.ts +18 -0
- package/lib/typescript/helpers/resolveInitBeforeLoadUser.d.ts.map +1 -1
- package/lib/typescript/hooks/useChatRoomFocus.d.ts +42 -0
- package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -0
- package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
- package/lib/typescript/hooks/useEventHandlers.d.ts +6 -0
- package/lib/typescript/hooks/useEventHandlers.d.ts.map +1 -1
- package/lib/typescript/hooks/useHeapSender.d.ts.map +1 -1
- package/lib/typescript/hooks/useMessageHeapState.d.ts +2 -0
- package/lib/typescript/hooks/useMessageHeapState.d.ts.map +1 -1
- package/lib/typescript/hooks/usePushNotifications.d.ts.map +1 -1
- package/lib/typescript/hooks/useRoomState.d.ts +1 -0
- package/lib/typescript/hooks/useRoomState.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts +2 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
- package/lib/typescript/main.d.ts +1 -0
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/auth.api.d.ts +3 -0
- package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
- package/lib/typescript/networking/apiClient.d.ts.map +1 -1
- package/lib/typescript/networking/outboundQueue.d.ts +57 -0
- package/lib/typescript/networking/outboundQueue.d.ts.map +1 -0
- package/lib/typescript/networking/xmpp/createTimeoutPromise.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +1 -1
- package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/getRoomsPaged.xmpp.d.ts +1 -1
- package/lib/typescript/networking/xmpp/getRoomsPaged.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmppClient.d.ts +58 -5
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/Middleware/unreadMidlleware.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomHeapSlice.d.ts +22 -1
- package/lib/typescript/roomStore/roomHeapSlice.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +8 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/types/models/media.model.d.ts +1 -0
- package/lib/typescript/types/models/media.model.d.ts.map +1 -1
- package/lib/typescript/types/models/xmpp.model.d.ts +1 -1
- package/lib/typescript/types/models/xmpp.model.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +10 -0
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/utils/installPromiseRejectionTracker.d.ts +20 -0
- package/lib/typescript/utils/installPromiseRejectionTracker.d.ts.map +1 -0
- package/lib/typescript/utils/resendMessage.d.ts.map +1 -1
- package/package.json +18 -2
- package/src/assets/icons.tsx +23 -14
- package/src/components/ContextMenu/ContextMenuComponents.tsx +10 -5
- package/src/components/MainComponents/ChatHeader.tsx +5 -1
- package/src/components/MainComponents/ChatRoom.tsx +81 -61
- package/src/components/MainComponents/ChatWrapper.tsx +100 -21
- package/src/components/MainComponents/MediaMessage.tsx +18 -8
- package/src/components/MainComponents/MessageContainer.tsx +4 -2
- package/src/components/MainComponents/MessageList.tsx +185 -31
- package/src/components/MainComponents/ReduxWrapper.tsx +19 -9
- package/src/components/MainComponents/SystemMessage.tsx +38 -26
- package/src/components/MessageBubble/Message.tsx +110 -27
- package/src/components/MessageBubble/MessageInteractions.tsx +98 -29
- package/src/components/Modals/AttachSheet/AttachSheet.tsx +17 -3
- package/src/components/Modals/FilePreviewModal/DocumentViewer.tsx +93 -0
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +182 -37
- package/src/components/Modals/FilePreviewModal/PdfView.tsx +32 -4
- package/src/components/Modals/Modal/Modal.tsx +4 -1
- package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +77 -44
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +19 -15
- package/src/components/Modals/styledModalComponents.tsx +4 -9
- package/src/components/styled/MediaFilePreview.tsx +111 -5
- package/src/components/styled/MessageImage.tsx +58 -14
- package/src/components/styled/NewMessageLabel.tsx +8 -5
- package/src/components/styled/SendInput.tsx +67 -29
- package/src/components/styled/StyledInputComponents/MediaComponents.tsx +15 -5
- package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +7 -2
- package/src/components/styled/UnsupportedType.tsx +7 -1
- package/src/components/styled/VideoMessage.tsx +59 -18
- package/src/context/MessageNotificationContext.tsx +8 -8
- package/src/context/xmppProvider.tsx +337 -32
- package/src/helpers/chatAutoEnterer.ts +2 -8
- package/src/helpers/historyPreloadScheduler.ts +4 -1
- package/src/helpers/insertMessageWithDelimiter.ts +22 -15
- package/src/helpers/keyboardLayout.ts +18 -0
- package/src/helpers/mediaDimensions.ts +47 -0
- package/src/helpers/mimeToExtension.ts +135 -0
- package/src/helpers/normalizeRoomJid.ts +6 -0
- package/src/helpers/resolveInitBeforeLoadUser.ts +79 -0
- package/src/hooks/useChatRoomFocus.ts +95 -0
- package/src/hooks/useChatWrapperInit.ts +51 -46
- package/src/hooks/useEventHandlers.tsx +24 -1
- package/src/hooks/useHeapSender.tsx +2 -1
- package/src/hooks/useLogout.tsx +3 -3
- package/src/hooks/useMessageHeapState.tsx +6 -2
- package/src/hooks/usePushNotifications.ts +21 -8
- package/src/hooks/useRoomState.tsx +4 -0
- package/src/hooks/useSendMessage.tsx +333 -17
- package/src/hooks/useUnreadMessagesCounter.ts +13 -16
- package/src/main.ts +1 -0
- package/src/networking/api-requests/auth.api.ts +60 -2
- package/src/networking/apiClient.ts +2 -1
- package/src/networking/outboundQueue.ts +98 -0
- package/src/networking/xmpp/createTimeoutPromise.xmpp.ts +5 -1
- package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +11 -13
- package/src/networking/xmpp/getRoomsPaged.xmpp.ts +27 -3
- package/src/networking/xmpp/presenceInRoom.xmpp.ts +24 -9
- package/src/networking/xmpp/sendTextMessage.xmpp.ts +2 -1
- package/src/networking/xmppClient.ts +399 -31
- package/src/roomStore/Middleware/unreadMidlleware.tsx +23 -5
- package/src/roomStore/roomHeapSlice.ts +47 -4
- package/src/roomStore/roomsSlice.ts +177 -27
- package/src/types/models/media.model.ts +3 -0
- package/src/types/models/xmpp.model.ts +2 -1
- package/src/types/types.ts +25 -0
- package/src/utils/installPromiseRejectionTracker.ts +91 -0
- package/src/utils/resendMessage.ts +2 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type KeyboardLayoutArgs = {
|
|
2
|
+
platform: string;
|
|
3
|
+
configuredOffset?: number;
|
|
4
|
+
bottomInset?: number;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const getKeyboardVerticalOffset = ({
|
|
8
|
+
platform,
|
|
9
|
+
configuredOffset = 0,
|
|
10
|
+
bottomInset = 0,
|
|
11
|
+
}: KeyboardLayoutArgs): number =>
|
|
12
|
+
configuredOffset + (platform === 'ios' ? bottomInset : 0);
|
|
13
|
+
|
|
14
|
+
export const getInputDockPaddingBottom = ({
|
|
15
|
+
platform,
|
|
16
|
+
bottomInset = 0,
|
|
17
|
+
}: Omit<KeyboardLayoutArgs, 'configuredOffset'>): number =>
|
|
18
|
+
platform === 'ios' ? bottomInset : 0;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Dimensions } from 'react-native';
|
|
2
|
+
|
|
3
|
+
// Shared sizing for inline media bubbles (images + video posters).
|
|
4
|
+
// Goal: show the media UNCROPPED, just scaled, preserving aspect ratio —
|
|
5
|
+
// portrait stays portrait, landscape stays landscape.
|
|
6
|
+
const screenW = Dimensions.get('window').width;
|
|
7
|
+
|
|
8
|
+
// Box the media must fit inside. Width adapts to the screen so it never
|
|
9
|
+
// blows past the bubble's max-width on small phones, but caps on tablets.
|
|
10
|
+
export const MEDIA_MAX_W = Math.min(260, Math.round(screenW * 0.64));
|
|
11
|
+
export const MEDIA_MAX_H = 320;
|
|
12
|
+
// Keep thumbnails from collapsing into a sliver (very wide/tall media).
|
|
13
|
+
const MEDIA_MIN_W = 140;
|
|
14
|
+
const MEDIA_MIN_H = 120;
|
|
15
|
+
|
|
16
|
+
export interface MediaDims {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Neutral 4:3 placeholder used before the natural size is known.
|
|
22
|
+
export const defaultMediaDims = (): MediaDims => ({
|
|
23
|
+
width: MEDIA_MAX_W,
|
|
24
|
+
height: Math.round(MEDIA_MAX_W * 0.75),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Fit (natW × natH) inside the box, preserving aspect ratio. Never
|
|
28
|
+
// upscales beyond the source resolution (avoids blur), but bumps very
|
|
29
|
+
// small media up to a sensible minimum so it stays tappable.
|
|
30
|
+
export const fitMediaDimensions = (natW: number, natH: number): MediaDims => {
|
|
31
|
+
if (!natW || !natH) {
|
|
32
|
+
return defaultMediaDims();
|
|
33
|
+
}
|
|
34
|
+
let scale = Math.min(MEDIA_MAX_W / natW, MEDIA_MAX_H / natH);
|
|
35
|
+
if (scale > 1) {
|
|
36
|
+
scale = 1;
|
|
37
|
+
}
|
|
38
|
+
let width = Math.round(natW * scale);
|
|
39
|
+
let height = Math.round(natH * scale);
|
|
40
|
+
|
|
41
|
+
if (width < MEDIA_MIN_W || height < MEDIA_MIN_H) {
|
|
42
|
+
const up = Math.max(MEDIA_MIN_W / width, MEDIA_MIN_H / height);
|
|
43
|
+
width = Math.min(MEDIA_MAX_W, Math.round(width * up));
|
|
44
|
+
height = Math.min(MEDIA_MAX_H, Math.round(height * up));
|
|
45
|
+
}
|
|
46
|
+
return { width, height };
|
|
47
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// MIME → file extension table for download/preview filename fallbacks.
|
|
2
|
+
// Centralized so FilePreviewModal, MediaMessage, and any future media
|
|
3
|
+
// surface share one source of truth. Keep additions sorted by category.
|
|
4
|
+
|
|
5
|
+
const MIME_TO_EXT: Record<string, string> = {
|
|
6
|
+
// images
|
|
7
|
+
'image/jpeg': '.jpg',
|
|
8
|
+
'image/jpg': '.jpg',
|
|
9
|
+
'image/png': '.png',
|
|
10
|
+
'image/gif': '.gif',
|
|
11
|
+
'image/webp': '.webp',
|
|
12
|
+
'image/heic': '.heic',
|
|
13
|
+
'image/heif': '.heif',
|
|
14
|
+
'image/bmp': '.bmp',
|
|
15
|
+
'image/svg+xml': '.svg',
|
|
16
|
+
'image/tiff': '.tiff',
|
|
17
|
+
|
|
18
|
+
// video
|
|
19
|
+
'video/mp4': '.mp4',
|
|
20
|
+
'video/quicktime': '.mov',
|
|
21
|
+
'video/x-m4v': '.m4v',
|
|
22
|
+
'video/webm': '.webm',
|
|
23
|
+
'video/3gpp': '.3gp',
|
|
24
|
+
'video/x-matroska': '.mkv',
|
|
25
|
+
'video/mpeg': '.mpeg',
|
|
26
|
+
|
|
27
|
+
// audio
|
|
28
|
+
'audio/mpeg': '.mp3',
|
|
29
|
+
'audio/mp3': '.mp3',
|
|
30
|
+
'audio/mp4': '.m4a',
|
|
31
|
+
'audio/x-m4a': '.m4a',
|
|
32
|
+
'audio/wav': '.wav',
|
|
33
|
+
'audio/x-wav': '.wav',
|
|
34
|
+
'audio/aac': '.aac',
|
|
35
|
+
'audio/ogg': '.ogg',
|
|
36
|
+
'audio/flac': '.flac',
|
|
37
|
+
'audio/webm': '.weba',
|
|
38
|
+
|
|
39
|
+
// documents
|
|
40
|
+
'application/pdf': '.pdf',
|
|
41
|
+
'application/msword': '.doc',
|
|
42
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
|
|
43
|
+
'.docx',
|
|
44
|
+
'application/vnd.ms-excel': '.xls',
|
|
45
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx',
|
|
46
|
+
'application/vnd.ms-powerpoint': '.ppt',
|
|
47
|
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation':
|
|
48
|
+
'.pptx',
|
|
49
|
+
'text/plain': '.txt',
|
|
50
|
+
'text/csv': '.csv',
|
|
51
|
+
'text/html': '.html',
|
|
52
|
+
'application/json': '.json',
|
|
53
|
+
'application/xml': '.xml',
|
|
54
|
+
'text/xml': '.xml',
|
|
55
|
+
'application/rtf': '.rtf',
|
|
56
|
+
|
|
57
|
+
// archives
|
|
58
|
+
'application/zip': '.zip',
|
|
59
|
+
'application/x-rar-compressed': '.rar',
|
|
60
|
+
'application/x-7z-compressed': '.7z',
|
|
61
|
+
'application/gzip': '.gz',
|
|
62
|
+
'application/x-tar': '.tar',
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const VALID_EXT_RE = /\.[a-z0-9]{1,8}$/i;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns the conventional extension (including the leading dot) for a
|
|
69
|
+
* MIME type, or `.bin` as a last-resort fallback so callers never end up
|
|
70
|
+
* with an extension-less filename.
|
|
71
|
+
*/
|
|
72
|
+
export function getExtensionForMime(mime: string | undefined | null): string {
|
|
73
|
+
if (!mime) {return '.bin';}
|
|
74
|
+
const normalized = mime.toLowerCase().split(';')[0]!.trim();
|
|
75
|
+
return MIME_TO_EXT[normalized] || '.bin';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Parses a URL or file path and returns the last segment, URL-decoded,
|
|
80
|
+
* stripped of query/hash. Returns `''` when nothing usable is present.
|
|
81
|
+
*/
|
|
82
|
+
export function filenameFromUrl(url: string | undefined | null): string {
|
|
83
|
+
if (!url) {return '';}
|
|
84
|
+
try {
|
|
85
|
+
// Strip query + hash without depending on a real URL parser (some RN
|
|
86
|
+
// URLs from CDNs do not parse cleanly).
|
|
87
|
+
const noQuery = url.split('?')[0]!.split('#')[0]!;
|
|
88
|
+
const last = noQuery.split('/').pop() || '';
|
|
89
|
+
return decodeURIComponent(last);
|
|
90
|
+
} catch {
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Ensures `fileName` ends with a valid extension. Strategy:
|
|
97
|
+
* 1. If the input already has an extension, return it unchanged.
|
|
98
|
+
* 2. Otherwise, derive the extension from `mime` and append it.
|
|
99
|
+
* 3. If `mime` is unknown, append `.bin`.
|
|
100
|
+
*
|
|
101
|
+
* Empty/falsy filenames get a `media_<timestamp>` base before the
|
|
102
|
+
* extension is appended so callers always get a usable filename.
|
|
103
|
+
*/
|
|
104
|
+
export function ensureFilenameHasExtension(
|
|
105
|
+
fileName: string | undefined | null,
|
|
106
|
+
mime: string | undefined | null
|
|
107
|
+
): string {
|
|
108
|
+
const base =
|
|
109
|
+
(fileName && fileName.trim()) || `media_${Date.now()}`;
|
|
110
|
+
if (VALID_EXT_RE.test(base)) {return base;}
|
|
111
|
+
return `${base}${getExtensionForMime(mime)}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Best-effort filename derivation for a message bubble:
|
|
116
|
+
* - server-provided `fileName`
|
|
117
|
+
* - server-provided `originalName`
|
|
118
|
+
* - URL pathname
|
|
119
|
+
* - generic `media_<timestamp>` so we never render an empty label
|
|
120
|
+
*
|
|
121
|
+
* Always returns a string with a valid extension.
|
|
122
|
+
*/
|
|
123
|
+
export function deriveDisplayFilename(opts: {
|
|
124
|
+
fileName?: string | null;
|
|
125
|
+
originalName?: string | null;
|
|
126
|
+
url?: string | null;
|
|
127
|
+
mime?: string | null;
|
|
128
|
+
}): string {
|
|
129
|
+
const candidate =
|
|
130
|
+
(opts.fileName && opts.fileName.trim()) ||
|
|
131
|
+
(opts.originalName && opts.originalName.trim()) ||
|
|
132
|
+
filenameFromUrl(opts.url) ||
|
|
133
|
+
'';
|
|
134
|
+
return ensureFilenameHasExtension(candidate, opts.mime);
|
|
135
|
+
}
|
|
@@ -237,4 +237,83 @@ export const applyResolvedUserToStore = (user?: User | null) => {
|
|
|
237
237
|
store.dispatch(setUser(user));
|
|
238
238
|
};
|
|
239
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Re-mints a User with a fresh xmppPassword for the XMPP credentials-
|
|
242
|
+
* provider path (bug #17). Unlike `resolveInitBeforeLoadUser` this
|
|
243
|
+
* ALWAYS hydrates via the chosen auth path even if the cached user
|
|
244
|
+
* already had xmppCredentials — that's the whole point, the old ones
|
|
245
|
+
* are stale.
|
|
246
|
+
*
|
|
247
|
+
* Selection order:
|
|
248
|
+
* 1. `jwtLogin` — re-exchange the JWT via `/users/client`.
|
|
249
|
+
* 2. Anything else (`userLogin` / `customLogin` / store / persisted)
|
|
250
|
+
* — `tryHydrateViaMy` on the current user, which calls
|
|
251
|
+
* `/users/my` and, on 401, refreshes the access token via
|
|
252
|
+
* `/users/login/refresh` and retries.
|
|
253
|
+
*
|
|
254
|
+
* Returns `null` only when nothing usable is available — the caller
|
|
255
|
+
* (xmppProvider) falls back to the cached creds in that case.
|
|
256
|
+
*/
|
|
257
|
+
export const refreshUserCredentialsForXmpp = async (
|
|
258
|
+
config?: IConfig,
|
|
259
|
+
signal?: AbortSignal
|
|
260
|
+
): Promise<User | null> => {
|
|
261
|
+
if (signal?.aborted) {return null;}
|
|
262
|
+
|
|
263
|
+
// Priority 1: jwtLogin — same path as `resolveInitBeforeLoadUser`
|
|
264
|
+
// priority 3. We always re-exchange because the original JWT may
|
|
265
|
+
// itself have expired (and the consumer is expected to swap
|
|
266
|
+
// `config.jwtLogin.token` for a fresh one before then).
|
|
267
|
+
if (config?.jwtLogin?.enabled && config?.jwtLogin?.token) {
|
|
268
|
+
try {
|
|
269
|
+
const fresh = await loginViaJwt(config.jwtLogin.token);
|
|
270
|
+
const normalized = normalizeUserForXmpp(fresh);
|
|
271
|
+
if (normalized && hasXmppCredentials(normalized)) {return normalized;}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
if (signal?.aborted || isAbortError(error)) {return null;}
|
|
274
|
+
// fall through to /users/my path
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const myEndpoint = config?.initBeforeLoadAuth?.myEndpoint || '/users/my';
|
|
279
|
+
|
|
280
|
+
// Priority 2: redux store user (covers userLogin + customLogin +
|
|
281
|
+
// anything previously persisted into chatSettingStore.user). The
|
|
282
|
+
// user must have at least a refreshToken for the refresh chain to
|
|
283
|
+
// produce something useful.
|
|
284
|
+
const currentUser = store.getState().chatSettingStore.user;
|
|
285
|
+
if (currentUser?.token || currentUser?.refreshToken) {
|
|
286
|
+
const hydrated = await tryHydrateViaMy(
|
|
287
|
+
currentUser as User,
|
|
288
|
+
myEndpoint,
|
|
289
|
+
signal
|
|
290
|
+
).catch(() => null);
|
|
291
|
+
if (hydrated && hasXmppCredentials(hydrated)) {return hydrated;}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Priority 3: persisted user in AsyncStorage — defensive; the store
|
|
295
|
+
// should already mirror this, but if the redux state got cleared
|
|
296
|
+
// mid-session (logout race) this gives us one last shot.
|
|
297
|
+
try {
|
|
298
|
+
const storedUser = await asyncLocalStorage<User>(
|
|
299
|
+
localStorageConstants.ETHORA_USER
|
|
300
|
+
).get();
|
|
301
|
+
if (
|
|
302
|
+
storedUser &&
|
|
303
|
+
(storedUser.token || storedUser.refreshToken || storedUser.xmppPassword)
|
|
304
|
+
) {
|
|
305
|
+
const hydrated = await tryHydrateViaMy(
|
|
306
|
+
storedUser,
|
|
307
|
+
myEndpoint,
|
|
308
|
+
signal
|
|
309
|
+
).catch(() => null);
|
|
310
|
+
if (hydrated && hasXmppCredentials(hydrated)) {return hydrated;}
|
|
311
|
+
}
|
|
312
|
+
} catch {
|
|
313
|
+
// ignore storage errors
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return null;
|
|
317
|
+
};
|
|
318
|
+
|
|
240
319
|
export default resolveInitBeforeLoadUser;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { useDispatch } from 'react-redux';
|
|
3
|
+
import {
|
|
4
|
+
clearVisibleRoom,
|
|
5
|
+
setCurrentRoom,
|
|
6
|
+
setLastViewedTimestamp,
|
|
7
|
+
setVisibleRoom,
|
|
8
|
+
} from '../roomStore/roomsSlice';
|
|
9
|
+
import { store } from '../roomStore';
|
|
10
|
+
|
|
11
|
+
interface UseChatRoomFocusOptions {
|
|
12
|
+
/** The room JID that the consumer's tab/screen is currently showing. */
|
|
13
|
+
roomJID: string | null | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the chat tab/screen is currently focused. In tab-based
|
|
16
|
+
* navigators where `<ChatRoom>` never unmounts, the SDK can't tell
|
|
17
|
+
* "user is looking at this tab" from "user is on a different tab"
|
|
18
|
+
* — pass this from `useFocusEffect` (React Navigation) or a similar
|
|
19
|
+
* focus signal so the unread counter clears on focus and starts
|
|
20
|
+
* counting again on blur.
|
|
21
|
+
*/
|
|
22
|
+
isFocused: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Public hook for consumers embedding `<ChatRoom>` inside a tab-based
|
|
27
|
+
* navigator. Mirrors the mount/unmount unread-tracking that ChatRoom
|
|
28
|
+
* does internally — but driven by an explicit focus signal so the
|
|
29
|
+
* unread counter behaves correctly when the chat tab is not focused
|
|
30
|
+
* but the component is still mounted.
|
|
31
|
+
*
|
|
32
|
+
* Without this hook, `useUnread()` will always return 0 for the chat
|
|
33
|
+
* room because the SDK assumes "mounted == active". With this hook,
|
|
34
|
+
* focus marks the room visible (clearing the badge) and blur stamps
|
|
35
|
+
* `lastViewedTimestamp = Date.now()` so future messages count as unread.
|
|
36
|
+
*
|
|
37
|
+
* Usage with React Navigation:
|
|
38
|
+
*
|
|
39
|
+
* ```tsx
|
|
40
|
+
* import { useIsFocused } from '@react-navigation/native';
|
|
41
|
+
*
|
|
42
|
+
* function ChatTab() {
|
|
43
|
+
* const isFocused = useIsFocused();
|
|
44
|
+
* useChatRoomFocus({ roomJID: 'general@conference.host', isFocused });
|
|
45
|
+
* return <Chat config={...} />;
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* Bug #18-adjacent / unread-tracking bug from sdk-bug-tracker.md.
|
|
50
|
+
*/
|
|
51
|
+
export const useChatRoomFocus = ({
|
|
52
|
+
roomJID,
|
|
53
|
+
isFocused,
|
|
54
|
+
}: UseChatRoomFocusOptions) => {
|
|
55
|
+
const dispatch = useDispatch();
|
|
56
|
+
const prevRef = useRef<{ roomJID: string | null; isFocused: boolean }>({
|
|
57
|
+
roomJID: null,
|
|
58
|
+
isFocused: false,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const leaveRoom = (jid: string) => {
|
|
62
|
+
const timestamp = Date.now();
|
|
63
|
+
dispatch(setLastViewedTimestamp({ chatJID: jid, timestamp }));
|
|
64
|
+
dispatch(clearVisibleRoom());
|
|
65
|
+
const rooms = store.getState().rooms?.rooms;
|
|
66
|
+
(store.getState().chatSettingStore as any)?.client
|
|
67
|
+
?.flushLastViewedToPrivateStoreStanza(rooms, { visibleRoomJID: jid })
|
|
68
|
+
.catch(() => {});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
const prev = prevRef.current;
|
|
73
|
+
if (prev.isFocused && prev.roomJID && (prev.roomJID !== roomJID || !isFocused)) {
|
|
74
|
+
leaveRoom(prev.roomJID);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (roomJID && isFocused) {
|
|
78
|
+
dispatch(setCurrentRoom({ roomJID }));
|
|
79
|
+
dispatch(setVisibleRoom({ roomJID }));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
prevRef.current = { roomJID: roomJID || null, isFocused };
|
|
83
|
+
}, [roomJID, isFocused, dispatch]);
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
return () => {
|
|
87
|
+
const prev = prevRef.current;
|
|
88
|
+
if (prev.isFocused && prev.roomJID) {
|
|
89
|
+
leaveRoom(prev.roomJID);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}, []);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export default useChatRoomFocus;
|
|
@@ -119,10 +119,8 @@ const useChatWrapperInit = ({
|
|
|
119
119
|
user.xmppUsername || user?.defaultWallet?.walletAddress,
|
|
120
120
|
user?.xmppPassword,
|
|
121
121
|
config?.xmppSettings
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
return client;
|
|
125
|
-
});
|
|
122
|
+
);
|
|
123
|
+
console.log(' Client initialized', newClient?.status);
|
|
126
124
|
|
|
127
125
|
if (roomsList && Object.keys(roomsList).length > 0) {
|
|
128
126
|
console.log(
|
|
@@ -156,27 +154,29 @@ const useChatWrapperInit = ({
|
|
|
156
154
|
await newClient.getRoomsStanza();
|
|
157
155
|
}
|
|
158
156
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
console.log(
|
|
166
|
-
'Got chats private store',
|
|
167
|
-
roomTimestampObject?.length || 0
|
|
168
|
-
);
|
|
169
|
-
updatedChatLastTimestamps(roomTimestampObject, dispatch);
|
|
170
|
-
if (!hasSyncedHistoryRef.current) {
|
|
171
|
-
console.log('Updating messages till last');
|
|
172
|
-
await updateMessagesTillLast(rooms, newClient);
|
|
173
|
-
hasSyncedHistoryRef.current = true;
|
|
174
|
-
}
|
|
175
|
-
setClient(newClient);
|
|
176
|
-
setConnectionLost(false);
|
|
177
|
-
console.log('Initialization complete');
|
|
178
|
-
}
|
|
157
|
+
try {
|
|
158
|
+
const roomTimestampObject: any =
|
|
159
|
+
await newClient.getChatsPrivateStoreRequestStanza();
|
|
160
|
+
console.log(
|
|
161
|
+
'Got chats private store',
|
|
162
|
+
roomTimestampObject?.length || 0
|
|
179
163
|
);
|
|
164
|
+
if (roomTimestampObject) {
|
|
165
|
+
updatedChatLastTimestamps(roomTimestampObject, dispatch);
|
|
166
|
+
}
|
|
167
|
+
if (!hasSyncedHistoryRef.current) {
|
|
168
|
+
console.log('Updating messages till last');
|
|
169
|
+
await updateMessagesTillLast(rooms, newClient);
|
|
170
|
+
hasSyncedHistoryRef.current = true;
|
|
171
|
+
}
|
|
172
|
+
setClient(newClient);
|
|
173
|
+
setConnectionLost(false);
|
|
174
|
+
console.log('Initialization complete');
|
|
175
|
+
} catch (err) {
|
|
176
|
+
console.warn('privateStore/timestamps failed', err);
|
|
177
|
+
setClient(newClient);
|
|
178
|
+
setConnectionLost(false);
|
|
179
|
+
}
|
|
180
180
|
|
|
181
181
|
{
|
|
182
182
|
config?.refreshTokens?.enabled && refresh();
|
|
@@ -204,29 +204,34 @@ const useChatWrapperInit = ({
|
|
|
204
204
|
}
|
|
205
205
|
setInited(true);
|
|
206
206
|
console.log(' Getting chats private store for existing client');
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
console.log(
|
|
214
|
-
'Got chats private store for existing client',
|
|
215
|
-
roomTimestampObject?.length || 0
|
|
216
|
-
);
|
|
217
|
-
updatedChatLastTimestamps(roomTimestampObject, dispatch);
|
|
218
|
-
if (!hasSyncedHistoryRef.current) {
|
|
219
|
-
console.log(
|
|
220
|
-
'Updating messages till last for existing client'
|
|
221
|
-
);
|
|
222
|
-
await updateMessagesTillLast(rooms, client);
|
|
223
|
-
hasSyncedHistoryRef.current = true;
|
|
224
|
-
}
|
|
225
|
-
setClient(client);
|
|
226
|
-
setConnectionLost(false);
|
|
227
|
-
console.log(' Initialization complete for existing client');
|
|
228
|
-
}
|
|
207
|
+
try {
|
|
208
|
+
const roomTimestampObject: any =
|
|
209
|
+
await client.getChatsPrivateStoreRequestStanza();
|
|
210
|
+
console.log(
|
|
211
|
+
'Got chats private store for existing client',
|
|
212
|
+
roomTimestampObject?.length || 0
|
|
229
213
|
);
|
|
214
|
+
if (roomTimestampObject) {
|
|
215
|
+
updatedChatLastTimestamps(roomTimestampObject, dispatch);
|
|
216
|
+
}
|
|
217
|
+
if (!hasSyncedHistoryRef.current) {
|
|
218
|
+
console.log(
|
|
219
|
+
'Updating messages till last for existing client'
|
|
220
|
+
);
|
|
221
|
+
await updateMessagesTillLast(rooms, client);
|
|
222
|
+
hasSyncedHistoryRef.current = true;
|
|
223
|
+
}
|
|
224
|
+
setClient(client);
|
|
225
|
+
setConnectionLost(false);
|
|
226
|
+
console.log(' Initialization complete for existing client');
|
|
227
|
+
} catch (err) {
|
|
228
|
+
console.warn(
|
|
229
|
+
'privateStore/timestamps failed (existing client)',
|
|
230
|
+
err
|
|
231
|
+
);
|
|
232
|
+
setClient(client);
|
|
233
|
+
setConnectionLost(false);
|
|
234
|
+
}
|
|
230
235
|
{
|
|
231
236
|
config?.refreshTokens?.enabled && refresh();
|
|
232
237
|
}
|
|
@@ -23,10 +23,17 @@ interface MessageEditedEvent {
|
|
|
23
23
|
user: any;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
interface MessageRetryEvent {
|
|
27
|
+
messageId: string;
|
|
28
|
+
roomJID: string;
|
|
29
|
+
messageType: 'text' | 'media';
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
export interface EventHandlersHook {
|
|
27
33
|
handleMessageSent: (event: MessageSentEvent) => Promise<void>;
|
|
28
34
|
handleMessageFailed: (event: MessageFailedEvent) => void;
|
|
29
35
|
handleMessageEdited: (event: MessageEditedEvent) => void;
|
|
36
|
+
handleMessageRetry: (event: MessageRetryEvent) => void;
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
export const useEventHandlers = (config?: IConfig): EventHandlersHook => {
|
|
@@ -77,5 +84,21 @@ export const useEventHandlers = (config?: IConfig): EventHandlersHook => {
|
|
|
77
84
|
[config]
|
|
78
85
|
);
|
|
79
86
|
|
|
80
|
-
|
|
87
|
+
const handleMessageRetry = useCallback(
|
|
88
|
+
(event: MessageRetryEvent) => {
|
|
89
|
+
try {
|
|
90
|
+
config?.eventHandlers?.onMessageRetry?.(event);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error('Error in message retry handler:', error);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
[config]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
handleMessageSent,
|
|
100
|
+
handleMessageFailed,
|
|
101
|
+
handleMessageEdited,
|
|
102
|
+
handleMessageRetry,
|
|
103
|
+
};
|
|
81
104
|
};
|
package/src/hooks/useLogout.tsx
CHANGED
|
@@ -49,7 +49,7 @@ const logoutService = {
|
|
|
49
49
|
performLogout: async (): Promise<void> => {
|
|
50
50
|
// 0. Flush lastViewedTimestamp to the server's private store BEFORE
|
|
51
51
|
// we close XMPP. Only rooms with no outstanding unread (plus the
|
|
52
|
-
//
|
|
52
|
+
// visible room) get their entries updated — rooms with unread
|
|
53
53
|
// keep their old marker so the next login still surfaces those
|
|
54
54
|
// messages as unread. Without this, an active-room view at
|
|
55
55
|
// logout would still appear unread on next login because we
|
|
@@ -58,11 +58,11 @@ const logoutService = {
|
|
|
58
58
|
const state = store.getState();
|
|
59
59
|
const client = (state.chatSettingStore as any)?.client;
|
|
60
60
|
const rooms = state.rooms?.rooms;
|
|
61
|
-
const
|
|
61
|
+
const visibleRoomJID = state.rooms?.visibleRoomJID || null;
|
|
62
62
|
if (client?.flushLastViewedToPrivateStoreStanza) {
|
|
63
63
|
await Promise.race([
|
|
64
64
|
client.flushLastViewedToPrivateStoreStanza(rooms, {
|
|
65
|
-
|
|
65
|
+
visibleRoomJID,
|
|
66
66
|
onlyIfNoUnread: true,
|
|
67
67
|
}),
|
|
68
68
|
new Promise((res) => setTimeout(res, 2000)),
|
|
@@ -3,9 +3,13 @@ import { RootState } from '../roomStore';
|
|
|
3
3
|
|
|
4
4
|
export const useMessageHeapState = () => {
|
|
5
5
|
const queue = useSelector(
|
|
6
|
-
(state: RootState) => state.roomHeapSlice
|
|
6
|
+
(state: RootState) => state.roomHeapSlice?.messageHeap
|
|
7
|
+
);
|
|
8
|
+
const failedMessages = useSelector(
|
|
9
|
+
(state: RootState) => state.roomHeapSlice?.failedMessages
|
|
7
10
|
);
|
|
8
11
|
const idSet = new Set(queue?.map((m) => m.id) ?? []);
|
|
12
|
+
const failedIdSet = new Set(Object.keys(failedMessages || {}));
|
|
9
13
|
|
|
10
|
-
return { queue, idSet };
|
|
14
|
+
return { queue, idSet, failedMessages, failedIdSet };
|
|
11
15
|
};
|
|
@@ -51,7 +51,13 @@ export function usePushNotifications() {
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
useEffect(() => {
|
|
54
|
-
initToken()
|
|
54
|
+
// initToken is async — `initToken()` without `.catch` leaves any
|
|
55
|
+
// rejection unhandled (showed as `Uncaught (in promise, id: X)` red
|
|
56
|
+
// screen in dev). The inner try/catch covers most paths but any
|
|
57
|
+
// synchronous throw before the try-block ran would still leak.
|
|
58
|
+
initToken().catch((err) =>
|
|
59
|
+
console.warn('[usePushNotifications] initToken rejected', err)
|
|
60
|
+
);
|
|
55
61
|
|
|
56
62
|
const unsubscribeForeground = onForegroundMessage((message) => {
|
|
57
63
|
setNotification(message);
|
|
@@ -78,13 +84,20 @@ export function usePushNotifications() {
|
|
|
78
84
|
handleNotificationPress(message);
|
|
79
85
|
});
|
|
80
86
|
|
|
81
|
-
getInitialNotification()
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
getInitialNotification()
|
|
88
|
+
.then((message) => {
|
|
89
|
+
if (message) {
|
|
90
|
+
console.log('[usePushNotifications] Initial notification:', JSON.stringify(message, null, 2));
|
|
91
|
+
setNotification(message);
|
|
92
|
+
handleNotificationPress(message);
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
.catch((err) =>
|
|
96
|
+
console.warn(
|
|
97
|
+
'[usePushNotifications] getInitialNotification failed',
|
|
98
|
+
err
|
|
99
|
+
)
|
|
100
|
+
);
|
|
88
101
|
|
|
89
102
|
return () => {
|
|
90
103
|
unsubscribeForeground();
|
|
@@ -12,6 +12,9 @@ export const useRoomState = (roomJID?: string) => {
|
|
|
12
12
|
const activeRoomJID = useSelector(
|
|
13
13
|
(state: RootState) => state.rooms.activeRoomJID
|
|
14
14
|
);
|
|
15
|
+
const visibleRoomJID = useSelector(
|
|
16
|
+
(state: RootState) => state.rooms.visibleRoomJID
|
|
17
|
+
);
|
|
15
18
|
const editAction = useSelector((state: RootState) => state.rooms.editAction);
|
|
16
19
|
const globalLoading = useSelector(
|
|
17
20
|
(state: RootState) => state.rooms.isLoading
|
|
@@ -37,6 +40,7 @@ export const useRoomState = (roomJID?: string) => {
|
|
|
37
40
|
room,
|
|
38
41
|
roomsList,
|
|
39
42
|
activeRoomJID,
|
|
43
|
+
visibleRoomJID,
|
|
40
44
|
editAction,
|
|
41
45
|
globalLoading,
|
|
42
46
|
loadingText,
|