@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
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
2
3
|
import { v4 as uuidv4 } from 'uuid';
|
|
3
4
|
import { useXmppClient } from '../context/xmppProvider';
|
|
4
|
-
import { useDispatch, useSelector } from 'react-redux';
|
|
5
|
+
import { useDispatch, useSelector, useStore } from 'react-redux';
|
|
5
6
|
import { addRoomMessage, setEditAction } from '../roomStore/roomsSlice';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
addMessageToHeap,
|
|
9
|
+
clearMessageFailure,
|
|
10
|
+
markMessageFailed,
|
|
11
|
+
} from '../roomStore/roomHeapSlice';
|
|
12
|
+
import { uploadFileViaFetch } from '../networking/api-requests/auth.api';
|
|
13
|
+
import { enqueueOutboundSend } from '../networking/outboundQueue';
|
|
14
|
+
import { RootState, store } from '../roomStore';
|
|
15
|
+
import { getGlobalXmppClient } from '../utils/clientRegistry';
|
|
9
16
|
import { useEventHandlers } from './useEventHandlers';
|
|
10
17
|
import type { IConfig, IMessage } from '../types/types';
|
|
11
18
|
|
|
19
|
+
// Watchdog: if a message stays "pending" (no server echo) for this
|
|
20
|
+
// long after the optimistic dispatch, mark it failed so the bubble
|
|
21
|
+
// flips out of the "sending..." state. Covers the silent-failure
|
|
22
|
+
// case (e.g. device offline before the message ever made it to the
|
|
23
|
+
// XMPP socket) — bug #18. Tuned generously so a brief network blip
|
|
24
|
+
// followed by reconnect within 30s still resolves naturally via the
|
|
25
|
+
// server echo.
|
|
26
|
+
const PENDING_WATCHDOG_MS = 30_000;
|
|
27
|
+
|
|
12
28
|
// Monotonic counter for stanza ids. Bumped on each send within a single
|
|
13
29
|
// process. Two rapid sends in the same millisecond used to collide on
|
|
14
30
|
// `send-text-message-${Date.now()}`; that collision made
|
|
@@ -19,9 +35,18 @@ let __sendIdSeq = 0;
|
|
|
19
35
|
const nextStanzaId = (prefix: string): string =>
|
|
20
36
|
`${prefix}-${Date.now()}-${(__sendIdSeq = (__sendIdSeq + 1) >>> 0)}`;
|
|
21
37
|
|
|
38
|
+
// Hard client-side cap on a single upload. The backend rejects oversized
|
|
39
|
+
// bodies with HTTP 413; SendInput blocks oversized files at pick time,
|
|
40
|
+
// and this mirrors that limit on every send path (including retries).
|
|
41
|
+
const MAX_MEDIA_BYTES = 50 * 1024 * 1024;
|
|
42
|
+
|
|
22
43
|
export const useSendMessage = (_configOverride?: IConfig) => {
|
|
23
44
|
const { client } = useXmppClient();
|
|
24
45
|
const dispatch = useDispatch();
|
|
46
|
+
// useStore gives us imperative getState() access for the watchdog —
|
|
47
|
+
// peek at the message's current pending/failed state from inside a
|
|
48
|
+
// setTimeout callback without re-rendering on every redux change.
|
|
49
|
+
const reduxStore = useStore<RootState>();
|
|
25
50
|
|
|
26
51
|
// Split selectors so each returns a primitive/stable reference — the
|
|
27
52
|
// single-object selector above caused a "returned a different result
|
|
@@ -38,8 +63,13 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
38
63
|
handleMessageSent,
|
|
39
64
|
handleMessageFailed,
|
|
40
65
|
handleMessageEdited,
|
|
66
|
+
handleMessageRetry,
|
|
41
67
|
} = useEventHandlers(config);
|
|
42
68
|
|
|
69
|
+
const failedMessages = useSelector(
|
|
70
|
+
(state: RootState) => state.roomHeapSlice?.failedMessages || {}
|
|
71
|
+
);
|
|
72
|
+
|
|
43
73
|
const sendMessage = useCallback(
|
|
44
74
|
async (
|
|
45
75
|
message: string,
|
|
@@ -111,16 +141,85 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
111
141
|
);
|
|
112
142
|
}
|
|
113
143
|
|
|
144
|
+
// Silent-failure watchdog (bug #18). If no echo lands within
|
|
145
|
+
// PENDING_WATCHDOG_MS, flip the bubble to "failed → tap to
|
|
146
|
+
// retry". We check at fire-time whether the message is still
|
|
147
|
+
// pending and not already marked failed by the catch path.
|
|
148
|
+
const watchdogTimer = setTimeout(() => {
|
|
149
|
+
const state = reduxStore.getState();
|
|
150
|
+
const roomMsgs = state.rooms?.rooms?.[activeRoomJID]?.messages || [];
|
|
151
|
+
const stillPending = roomMsgs.find(
|
|
152
|
+
(m: any) => m.id === optimisticId && m.pending
|
|
153
|
+
);
|
|
154
|
+
const alreadyFailed = state.roomHeapSlice?.failedMessages?.[optimisticId];
|
|
155
|
+
if (stillPending && !alreadyFailed) {
|
|
156
|
+
console.warn(
|
|
157
|
+
`Send watchdog fired — message ${optimisticId} stuck pending > ${PENDING_WATCHDOG_MS}ms; marking failed`
|
|
158
|
+
);
|
|
159
|
+
dispatch(
|
|
160
|
+
markMessageFailed({
|
|
161
|
+
kind: 'text',
|
|
162
|
+
id: optimisticId,
|
|
163
|
+
roomJID: activeRoomJID,
|
|
164
|
+
body: message,
|
|
165
|
+
isReply,
|
|
166
|
+
isChecked,
|
|
167
|
+
mainMessage,
|
|
168
|
+
})
|
|
169
|
+
);
|
|
170
|
+
handleMessageFailed({
|
|
171
|
+
message,
|
|
172
|
+
roomJID: activeRoomJID,
|
|
173
|
+
error: new Error('Send timed out (no server echo)'),
|
|
174
|
+
messageType: 'text',
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}, PENDING_WATCHDOG_MS);
|
|
178
|
+
|
|
114
179
|
try {
|
|
115
|
-
|
|
116
|
-
|
|
180
|
+
|
|
181
|
+
const effectiveClient: any =
|
|
182
|
+
client ||
|
|
183
|
+
[
|
|
184
|
+
getGlobalXmppClient(),
|
|
185
|
+
store.getState()?.chatSettingStore?.client,
|
|
186
|
+
].find((c: any) => c && c.status === 'online');
|
|
187
|
+
|
|
188
|
+
if (!effectiveClient) {
|
|
189
|
+
const anyClient: any =
|
|
190
|
+
client ||
|
|
191
|
+
getGlobalXmppClient() ||
|
|
192
|
+
store.getState()?.chatSettingStore?.client;
|
|
193
|
+
try {
|
|
194
|
+
anyClient?.forceReconnect?.();
|
|
195
|
+
} catch {}
|
|
196
|
+
enqueueOutboundSend({
|
|
197
|
+
optimisticId,
|
|
198
|
+
roomJID: activeRoomJID,
|
|
199
|
+
enqueuedAt: Date.now(),
|
|
200
|
+
send: (c) =>
|
|
201
|
+
c.sendMessage(
|
|
202
|
+
activeRoomJID,
|
|
203
|
+
user.firstName,
|
|
204
|
+
user.lastName,
|
|
205
|
+
'',
|
|
206
|
+
user.walletAddress,
|
|
207
|
+
message,
|
|
208
|
+
'',
|
|
209
|
+
isReply || false,
|
|
210
|
+
isChecked || false,
|
|
211
|
+
mainMessage || '',
|
|
212
|
+
optimisticId
|
|
213
|
+
),
|
|
214
|
+
});
|
|
215
|
+
return;
|
|
117
216
|
}
|
|
118
217
|
// Pass the optimistic id as the stanza id so the server echoes
|
|
119
218
|
// it back with the same value — the reducer's dedupe lookup
|
|
120
219
|
// matches and the bubble flips from pending → delivered in-place
|
|
121
220
|
// (instead of rendering two copies, which is what happens when
|
|
122
221
|
// ids don't match).
|
|
123
|
-
|
|
222
|
+
effectiveClient.sendMessage(
|
|
124
223
|
activeRoomJID,
|
|
125
224
|
user.firstName,
|
|
126
225
|
user.lastName,
|
|
@@ -140,6 +239,18 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
140
239
|
messageType: 'text',
|
|
141
240
|
});
|
|
142
241
|
} catch (error) {
|
|
242
|
+
clearTimeout(watchdogTimer);
|
|
243
|
+
dispatch(
|
|
244
|
+
markMessageFailed({
|
|
245
|
+
kind: 'text',
|
|
246
|
+
id: optimisticId,
|
|
247
|
+
roomJID: activeRoomJID,
|
|
248
|
+
body: message,
|
|
249
|
+
isReply,
|
|
250
|
+
isChecked,
|
|
251
|
+
mainMessage,
|
|
252
|
+
})
|
|
253
|
+
);
|
|
143
254
|
handleMessageFailed({
|
|
144
255
|
message,
|
|
145
256
|
roomJID: activeRoomJID,
|
|
@@ -148,7 +259,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
148
259
|
});
|
|
149
260
|
}
|
|
150
261
|
},
|
|
151
|
-
[editAction, client, user, dispatch, handleMessageSent, handleMessageEdited, handleMessageFailed]
|
|
262
|
+
[editAction, client, user, dispatch, handleMessageSent, handleMessageEdited, handleMessageFailed, reduxStore]
|
|
152
263
|
);
|
|
153
264
|
|
|
154
265
|
const sendMedia = useCallback(
|
|
@@ -158,11 +269,42 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
158
269
|
activeRoomJID: string,
|
|
159
270
|
isReply: boolean = false,
|
|
160
271
|
isChecked: boolean = false,
|
|
161
|
-
mainMessage: string = ''
|
|
272
|
+
mainMessage: string = '',
|
|
273
|
+
existingId?: string
|
|
162
274
|
) => {
|
|
163
275
|
client?.onCriticalSend?.(activeRoomJID);
|
|
164
276
|
|
|
165
|
-
|
|
277
|
+
// Defensive 50 MB guard on every send path (SendInput blocks it at
|
|
278
|
+
// pick time, but retries replay the saved payload straight here).
|
|
279
|
+
if (typeof data?.size === 'number' && data.size > MAX_MEDIA_BYTES) {
|
|
280
|
+
console.warn('media exceeds 50MB cap — not uploading', {
|
|
281
|
+
name: data?.name,
|
|
282
|
+
size: data?.size,
|
|
283
|
+
});
|
|
284
|
+
if (existingId) {
|
|
285
|
+
dispatch(
|
|
286
|
+
markMessageFailed({
|
|
287
|
+
kind: 'media',
|
|
288
|
+
id: existingId,
|
|
289
|
+
roomJID: activeRoomJID,
|
|
290
|
+
data,
|
|
291
|
+
type,
|
|
292
|
+
isReply,
|
|
293
|
+
isChecked,
|
|
294
|
+
mainMessage,
|
|
295
|
+
})
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
handleMessageFailed({
|
|
299
|
+
message: 'media',
|
|
300
|
+
roomJID: activeRoomJID,
|
|
301
|
+
error: new Error('File exceeds the 50 MB upload limit'),
|
|
302
|
+
messageType: 'media',
|
|
303
|
+
});
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const id = existingId || `send-media-message:${uuidv4()}`;
|
|
166
308
|
const optimisticTimestamp = Date.now();
|
|
167
309
|
const optimisticDate = new Date(optimisticTimestamp).toISOString();
|
|
168
310
|
const selfId =
|
|
@@ -171,7 +313,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
171
313
|
`${user?.firstName || ''} ${user?.lastName || ''}`.trim() || selfId;
|
|
172
314
|
const fileSizeStr = data?.size != null ? String(data.size) : '';
|
|
173
315
|
|
|
174
|
-
if (!config?.disableSentLogic) {
|
|
316
|
+
if (!config?.disableSentLogic && !existingId) {
|
|
175
317
|
dispatch(
|
|
176
318
|
addRoomMessage({
|
|
177
319
|
roomJID: activeRoomJID,
|
|
@@ -224,11 +366,94 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
224
366
|
);
|
|
225
367
|
}
|
|
226
368
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
369
|
+
// Silent-failure watchdog for media-send (bug #18). Same shape
|
|
370
|
+
// as the text path: if the optimistic bubble never gets the echo
|
|
371
|
+
// (e.g. upload completed but XMPP send is buffered offline), flip
|
|
372
|
+
// to failed → tap to retry.
|
|
373
|
+
const mediaWatchdog = setTimeout(() => {
|
|
374
|
+
const state = reduxStore.getState();
|
|
375
|
+
const roomMsgs = state.rooms?.rooms?.[activeRoomJID]?.messages || [];
|
|
376
|
+
const stillPending = roomMsgs.find(
|
|
377
|
+
(m: any) => m.id === id && m.pending
|
|
378
|
+
);
|
|
379
|
+
const alreadyFailed = state.roomHeapSlice?.failedMessages?.[id];
|
|
380
|
+
if (stillPending && !alreadyFailed) {
|
|
381
|
+
console.warn(
|
|
382
|
+
`Media-send watchdog fired — ${id} stuck pending > ${PENDING_WATCHDOG_MS}ms; marking failed`
|
|
383
|
+
);
|
|
384
|
+
dispatch(
|
|
385
|
+
markMessageFailed({
|
|
386
|
+
kind: 'media',
|
|
387
|
+
id,
|
|
388
|
+
roomJID: activeRoomJID,
|
|
389
|
+
data,
|
|
390
|
+
type,
|
|
391
|
+
isReply,
|
|
392
|
+
isChecked,
|
|
393
|
+
mainMessage,
|
|
394
|
+
})
|
|
395
|
+
);
|
|
396
|
+
handleMessageFailed({
|
|
397
|
+
message: 'media',
|
|
398
|
+
roomJID: activeRoomJID,
|
|
399
|
+
error: new Error('Media send timed out (no server echo)'),
|
|
400
|
+
messageType: 'media',
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}, PENDING_WATCHDOG_MS);
|
|
404
|
+
|
|
405
|
+
// Help RN's FormData polyfill build a proper multipart/file part
|
|
406
|
+
// (instead of serialising the JS object as JSON). On iOS the
|
|
407
|
+
// picker can return ph:// or assets-library:// URIs for some
|
|
408
|
+
// legacy library items — those can't be read as files. Coerce
|
|
409
|
+
// to a file:// scheme when possible so the body is a real blob.
|
|
410
|
+
const fileBlob = {
|
|
411
|
+
uri:
|
|
412
|
+
typeof data?.uri === 'string'
|
|
413
|
+
? data.uri.replace(/^assets-library:\/\//, 'file://')
|
|
414
|
+
: data?.uri,
|
|
415
|
+
type:
|
|
416
|
+
data?.type ||
|
|
417
|
+
data?.mimeType ||
|
|
418
|
+
type ||
|
|
419
|
+
'application/octet-stream',
|
|
420
|
+
name: data?.name || data?.fileName || `media_${Date.now()}`,
|
|
421
|
+
};
|
|
230
422
|
|
|
231
|
-
|
|
423
|
+
// Mirror the web client: a single multipart POST to /files/ with
|
|
424
|
+
// the file under the plural "files" field. We send it via fetch
|
|
425
|
+
// (not axios) because RN's fetch sets the multipart boundary on the
|
|
426
|
+
// Content-Type header correctly. The previous axios fallback omitted
|
|
427
|
+
// a valid boundary, so the server mis-parsed one file as many and
|
|
428
|
+
// rejected the request with HTTP 413 "TOO_MANY_FILES". The only
|
|
429
|
+
// retry is the documented singular-"file" fallback for deployments
|
|
430
|
+
// that 500 on the plural field (bug #10).
|
|
431
|
+
const tryUpload = async () => {
|
|
432
|
+
const fd = new FormData();
|
|
433
|
+
fd.append('files', fileBlob as any);
|
|
434
|
+
try {
|
|
435
|
+
return await uploadFileViaFetch(fd);
|
|
436
|
+
} catch (err: any) {
|
|
437
|
+
if (err?.response?.status === 500) {
|
|
438
|
+
console.warn(
|
|
439
|
+
'upload "files" field returned 500 — retrying with "file" (singular)',
|
|
440
|
+
{ name: fileBlob.name, type: fileBlob.type }
|
|
441
|
+
);
|
|
442
|
+
const fd2 = new FormData();
|
|
443
|
+
fd2.append('file', fileBlob as any);
|
|
444
|
+
return await uploadFileViaFetch(fd2);
|
|
445
|
+
}
|
|
446
|
+
throw err;
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
try {
|
|
451
|
+
const response = await tryUpload();
|
|
452
|
+
// Upload succeeded — the stanza is now in flight. If the
|
|
453
|
+
// server echo arrives within the watchdog window the bubble
|
|
454
|
+
// flips normally; if not, the watchdog still fires and marks
|
|
455
|
+
// it failed. We don't clear the timer on upload success because
|
|
456
|
+
// the XMPP send could still fail silently.
|
|
232
457
|
|
|
233
458
|
for (const item of response.data.results) {
|
|
234
459
|
const messagePayload = {
|
|
@@ -260,7 +485,34 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
260
485
|
// Stanza id == placeholder id so the MUC echo's outer
|
|
261
486
|
// <message id="..."> matches xmppId on the placeholder and
|
|
262
487
|
// insertMessageWithDelimiter merges in place + flips pending.
|
|
263
|
-
|
|
488
|
+
const effectiveMediaClient: any =
|
|
489
|
+
client ||
|
|
490
|
+
[
|
|
491
|
+
getGlobalXmppClient(),
|
|
492
|
+
store.getState()?.chatSettingStore?.client,
|
|
493
|
+
].find((c: any) => c && c.status === 'online');
|
|
494
|
+
if (effectiveMediaClient) {
|
|
495
|
+
effectiveMediaClient.sendMediaMessageStanza(
|
|
496
|
+
activeRoomJID,
|
|
497
|
+
messagePayload,
|
|
498
|
+
id
|
|
499
|
+
);
|
|
500
|
+
} else {
|
|
501
|
+
const anyMediaClient: any =
|
|
502
|
+
client ||
|
|
503
|
+
getGlobalXmppClient() ||
|
|
504
|
+
store.getState()?.chatSettingStore?.client;
|
|
505
|
+
try {
|
|
506
|
+
anyMediaClient?.forceReconnect?.();
|
|
507
|
+
} catch {}
|
|
508
|
+
enqueueOutboundSend({
|
|
509
|
+
optimisticId: id,
|
|
510
|
+
roomJID: activeRoomJID,
|
|
511
|
+
enqueuedAt: Date.now(),
|
|
512
|
+
send: (c) =>
|
|
513
|
+
c.sendMediaMessageStanza(activeRoomJID, messagePayload, id),
|
|
514
|
+
});
|
|
515
|
+
}
|
|
264
516
|
}
|
|
265
517
|
|
|
266
518
|
await handleMessageSent({
|
|
@@ -279,17 +531,43 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
279
531
|
},
|
|
280
532
|
});
|
|
281
533
|
} catch (error: any) {
|
|
534
|
+
// Upload (or stanza send) threw an explicit error. Clear the
|
|
535
|
+
// watchdog so it doesn't double-fire `markMessageFailed`.
|
|
536
|
+
clearTimeout(mediaWatchdog);
|
|
282
537
|
// Surface the real server payload so we can see why the upload
|
|
283
538
|
// was rejected (axios collapses the message to "Request failed
|
|
284
539
|
// with status code N"; the actual reason lives in
|
|
285
540
|
// `error.response.data`).
|
|
541
|
+
const uriStr = typeof data?.uri === 'string' ? data.uri : '';
|
|
542
|
+
const uriScheme = uriStr.match(/^([a-z]+):/i)?.[1] ?? 'unknown';
|
|
286
543
|
console.error('upload failed', {
|
|
287
544
|
status: error?.response?.status,
|
|
288
545
|
statusText: error?.response?.statusText,
|
|
289
546
|
serverBody: error?.response?.data,
|
|
290
547
|
requestUrl: error?.config?.url,
|
|
291
548
|
axiosMessage: error?.message,
|
|
549
|
+
axiosCode: error?.code,
|
|
550
|
+
axiosCauseMessage: error?.cause?.message,
|
|
551
|
+
uri: uriStr,
|
|
552
|
+
uriScheme,
|
|
553
|
+
mime: fileBlob.type,
|
|
554
|
+
fileSizeBytes: data?.size ?? null,
|
|
555
|
+
fileName: fileBlob.name,
|
|
556
|
+
platformOS: Platform.OS,
|
|
557
|
+
platformVersion: Platform.Version,
|
|
292
558
|
});
|
|
559
|
+
dispatch(
|
|
560
|
+
markMessageFailed({
|
|
561
|
+
kind: 'media',
|
|
562
|
+
id,
|
|
563
|
+
roomJID: activeRoomJID,
|
|
564
|
+
data,
|
|
565
|
+
type,
|
|
566
|
+
isReply,
|
|
567
|
+
isChecked,
|
|
568
|
+
mainMessage,
|
|
569
|
+
})
|
|
570
|
+
);
|
|
293
571
|
handleMessageFailed({
|
|
294
572
|
message: 'media',
|
|
295
573
|
roomJID: activeRoomJID,
|
|
@@ -298,7 +576,44 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
298
576
|
});
|
|
299
577
|
}
|
|
300
578
|
},
|
|
301
|
-
[client, config, user, dispatch, handleMessageSent, handleMessageFailed]
|
|
579
|
+
[client, config, user, dispatch, handleMessageSent, handleMessageFailed, reduxStore]
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
// Retry a previously-failed send by replaying the saved payload from
|
|
583
|
+
// the heap. Clears the failure flag first so the bubble flips back to
|
|
584
|
+
// "sending..."; if the retry fails again `markMessageFailed` re-arms
|
|
585
|
+
// it. No-op when the id isn't in the failed map.
|
|
586
|
+
const retryMessage = useCallback(
|
|
587
|
+
async (failedId: string) => {
|
|
588
|
+
const payload = failedMessages[failedId];
|
|
589
|
+
if (!payload) {return;}
|
|
590
|
+
dispatch(clearMessageFailure(failedId));
|
|
591
|
+
handleMessageRetry({
|
|
592
|
+
messageId: failedId,
|
|
593
|
+
roomJID: payload.roomJID,
|
|
594
|
+
messageType: payload.kind,
|
|
595
|
+
});
|
|
596
|
+
if (payload.kind === 'text') {
|
|
597
|
+
await sendMessage(
|
|
598
|
+
payload.body,
|
|
599
|
+
payload.roomJID,
|
|
600
|
+
payload.isReply,
|
|
601
|
+
payload.isChecked,
|
|
602
|
+
payload.mainMessage
|
|
603
|
+
);
|
|
604
|
+
} else {
|
|
605
|
+
await sendMedia(
|
|
606
|
+
payload.data,
|
|
607
|
+
payload.type,
|
|
608
|
+
payload.roomJID,
|
|
609
|
+
payload.isReply,
|
|
610
|
+
payload.isChecked,
|
|
611
|
+
payload.mainMessage,
|
|
612
|
+
failedId
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
},
|
|
616
|
+
[failedMessages, dispatch, handleMessageRetry, sendMessage, sendMedia]
|
|
302
617
|
);
|
|
303
618
|
|
|
304
619
|
// ChatRoom/ThreadWrapper consume this as the "edit branch" of send.
|
|
@@ -355,6 +670,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
355
670
|
sendMessage,
|
|
356
671
|
sendMedia,
|
|
357
672
|
sendEditMessage,
|
|
673
|
+
retryMessage,
|
|
358
674
|
isLastMessageFromUserAndProcessing,
|
|
359
675
|
};
|
|
360
676
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useSyncExternalStore } from 'react';
|
|
2
2
|
import { IRoom } from '../types/types';
|
|
3
|
-
import {
|
|
3
|
+
import { store } from '../roomStore';
|
|
4
4
|
|
|
5
5
|
interface UnreadMessagesMap {
|
|
6
6
|
[roomJid: string]: number;
|
|
@@ -13,21 +13,18 @@ interface UnreadMessagesStats {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export const useUnreadMessagesCounter = (): UnreadMessagesStats => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
});
|
|
29
|
-
return unsubscribe;
|
|
30
|
-
};
|
|
16
|
+
// Notify React on EVERY store change and let useSyncExternalStore's
|
|
17
|
+
// snapshot comparison (Object.is on the `rooms` reference) decide
|
|
18
|
+
// whether to re-render. The previous implementation only fired the
|
|
19
|
+
// callback while iterating rooms that already had `unreadMessages`
|
|
20
|
+
// defined — so when `rooms` became empty (logout, or the last room
|
|
21
|
+
// removed) the loop body never ran, the callback never fired, and the
|
|
22
|
+
// hook never re-rendered: a consumer's badge stayed stuck at its last
|
|
23
|
+
// non-zero count after logout. (It's also cheaper — one callback per
|
|
24
|
+
// change instead of one per unread room. Redux Toolkit keeps the
|
|
25
|
+
// `rooms` slice reference stable across actions that don't touch it,
|
|
26
|
+
// so non-rooms dispatches still don't trigger a re-render.)
|
|
27
|
+
const subscribe = (callback: () => void) => store.subscribe(callback);
|
|
31
28
|
|
|
32
29
|
const rooms = useSyncExternalStore(
|
|
33
30
|
subscribe,
|
package/src/main.ts
CHANGED
|
@@ -28,6 +28,7 @@ export { XmppProvider } from './context/xmppProvider';
|
|
|
28
28
|
|
|
29
29
|
// Hooks that consumers usually need (badge counts, logout, push, etc.).
|
|
30
30
|
export { useUnread } from './hooks/useUnreadMessagesCounter';
|
|
31
|
+
export { useChatRoomFocus } from './hooks/useChatRoomFocus';
|
|
31
32
|
export { logoutService } from './hooks/useLogout';
|
|
32
33
|
export { useQRCodeChat, handleQRChatId } from './hooks/useQRCodeChatHandler';
|
|
33
34
|
export { resendMessage } from './utils/resendMessage';
|
|
@@ -8,8 +8,9 @@ import { User } from '../../types/types';
|
|
|
8
8
|
// } from 'firebase/auth';
|
|
9
9
|
// import { app } from '../../../firebase-config';
|
|
10
10
|
|
|
11
|
-
import http, { getCurrentAppToken } from '../apiClient';
|
|
11
|
+
import http, { getCurrentAppToken, getCurrentBaseURL } from '../apiClient';
|
|
12
12
|
import { store } from '../../roomStore';
|
|
13
|
+
import { pushLog } from '../../utils/devLogger';
|
|
13
14
|
|
|
14
15
|
// login functions
|
|
15
16
|
export async function loginEmail(email: string, password: string) {
|
|
@@ -134,7 +135,64 @@ export function uploadFile(formData: FormData) {
|
|
|
134
135
|
headers: {
|
|
135
136
|
Authorization: token,
|
|
136
137
|
Accept: '*/*',
|
|
137
|
-
'Content-Type':
|
|
138
|
+
'Content-Type': null,
|
|
138
139
|
},
|
|
140
|
+
transformRequest: (data: any, headers: any) => {
|
|
141
|
+
if (headers?.delete) {headers.delete('Content-Type');}
|
|
142
|
+
return data;
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function uploadFileViaFetch(formData: FormData): Promise<{ data: any }> {
|
|
148
|
+
const token = store.getState().chatSettingStore?.user?.token ?? '';
|
|
149
|
+
const baseUrl = getCurrentBaseURL();
|
|
150
|
+
const url = `${baseUrl.replace(/\/$/, '')}/files/`;
|
|
151
|
+
|
|
152
|
+
pushLog('http', `→ POST ${url} (fetch)`, {
|
|
153
|
+
headers: { Authorization: token ? token.slice(0, 16) + '…' : '[empty]', Accept: '*/*' },
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
let res: Response;
|
|
157
|
+
try {
|
|
158
|
+
res = await fetch(url, {
|
|
159
|
+
method: 'POST',
|
|
160
|
+
headers: {
|
|
161
|
+
Authorization: token,
|
|
162
|
+
Accept: '*/*',
|
|
163
|
+
},
|
|
164
|
+
body: formData as any,
|
|
165
|
+
});
|
|
166
|
+
} catch (e: any) {
|
|
167
|
+
pushLog('http', `← ERR fetch /files/`, {
|
|
168
|
+
name: e?.name,
|
|
169
|
+
message: e?.message,
|
|
170
|
+
stack: e?.stack,
|
|
171
|
+
});
|
|
172
|
+
const err: any = new Error(e?.message || 'Network request failed');
|
|
173
|
+
err.code = 'ERR_NETWORK';
|
|
174
|
+
err.cause = e;
|
|
175
|
+
err.config = { url: '/files/' };
|
|
176
|
+
throw err;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!res.ok) {
|
|
180
|
+
let body: any = null;
|
|
181
|
+
try {
|
|
182
|
+
body = await res.json();
|
|
183
|
+
} catch {
|
|
184
|
+
try { body = await res.text(); } catch { body = null; }
|
|
185
|
+
}
|
|
186
|
+
pushLog('http', `← ${res.status} POST /files/ (fetch)`, body);
|
|
187
|
+
const err: any = new Error(`Upload failed: ${res.status}`);
|
|
188
|
+
err.response = { status: res.status, statusText: res.statusText, data: body };
|
|
189
|
+
err.config = { url: '/files/' };
|
|
190
|
+
throw err;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const data = await res.json();
|
|
194
|
+
pushLog('http', `← ${res.status} POST /files/ (fetch)`, {
|
|
195
|
+
resultsCount: Array.isArray(data?.results) ? data.results.length : 'n/a',
|
|
139
196
|
});
|
|
197
|
+
return { data };
|
|
140
198
|
}
|
|
@@ -171,7 +171,8 @@ http.interceptors.response.use(
|
|
|
171
171
|
isRefreshing = true;
|
|
172
172
|
try {
|
|
173
173
|
const tokens = await refresh();
|
|
174
|
-
console.log('tokens', tokens)
|
|
174
|
+
// (was: console.log('tokens', tokens) — dumped the full response
|
|
175
|
+
// incl. access/refresh/ws tokens on every refresh; removed.)
|
|
175
176
|
isRefreshing = false;
|
|
176
177
|
originalRequest.headers.Authorization = tokens.data.token;
|
|
177
178
|
processQueue(tokens.data.token);
|