@ethora/chat-component-rn 26.5.7 → 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 +133 -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/ChatRoom.js +64 -38
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +57 -13
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +4 -2
- 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 +165 -28
- 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 +84 -39
- 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 +140 -24
- 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 +77 -47
- 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 +47 -28
- package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/commonjs/components/styled/MessageImage.js +49 -9
- 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 +49 -27
- 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 -14
- 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 +244 -32
- 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/normalizeRoomJid.js +20 -0
- package/lib/commonjs/helpers/normalizeRoomJid.js.map +1 -0
- package/lib/commonjs/hooks/useChatRoomFocus.js +87 -0
- package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -0
- 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/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 +201 -10
- 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 +67 -0
- 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 +294 -35
- 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/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/ChatRoom.js +65 -39
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +57 -13
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +4 -2
- 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 +166 -29
- 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 +85 -40
- 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 +143 -25
- 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 +79 -49
- 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 +47 -28
- package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/module/components/styled/MessageImage.js +51 -11
- 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 +50 -28
- 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 -15
- 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 +246 -34
- 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/normalizeRoomJid.js +15 -0
- package/lib/module/helpers/normalizeRoomJid.js.map +1 -0
- package/lib/module/hooks/useChatRoomFocus.js +82 -0
- package/lib/module/hooks/useChatRoomFocus.js.map +1 -0
- 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/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 +203 -12
- 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 +67 -1
- 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 +294 -35
- 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/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/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.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/normalizeRoomJid.d.ts +2 -0
- package/lib/typescript/helpers/normalizeRoomJid.d.ts.map +1 -0
- package/lib/typescript/hooks/useChatRoomFocus.d.ts +42 -0
- package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -0
- package/lib/typescript/hooks/useHeapSender.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.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 +33 -4
- 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/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 +4 -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/ChatRoom.tsx +81 -66
- package/src/components/MainComponents/ChatWrapper.tsx +99 -21
- package/src/components/MainComponents/MediaMessage.tsx +3 -0
- package/src/components/MainComponents/MessageContainer.tsx +4 -2
- package/src/components/MainComponents/MessageList.tsx +175 -28
- package/src/components/MainComponents/ReduxWrapper.tsx +19 -9
- package/src/components/MainComponents/SystemMessage.tsx +38 -26
- package/src/components/MessageBubble/Message.tsx +91 -62
- 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 +152 -25
- 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 +70 -58
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +19 -15
- package/src/components/Modals/styledModalComponents.tsx +4 -9
- package/src/components/styled/MediaFilePreview.tsx +46 -26
- package/src/components/styled/MessageImage.tsx +58 -13
- package/src/components/styled/NewMessageLabel.tsx +8 -5
- package/src/components/styled/SendInput.tsx +64 -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 -11
- package/src/context/MessageNotificationContext.tsx +8 -8
- package/src/context/xmppProvider.tsx +247 -30
- 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/normalizeRoomJid.ts +6 -0
- package/src/hooks/useChatRoomFocus.ts +95 -0
- package/src/hooks/useHeapSender.tsx +2 -1
- package/src/hooks/useLogout.tsx +3 -3
- package/src/hooks/usePushNotifications.ts +21 -8
- package/src/hooks/useRoomState.tsx +4 -0
- package/src/hooks/useSendMessage.tsx +258 -13
- package/src/hooks/useUnreadMessagesCounter.ts +13 -16
- package/src/main.ts +1 -0
- package/src/networking/api-requests/auth.api.ts +55 -1
- 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 +317 -43
- package/src/roomStore/Middleware/unreadMidlleware.tsx +23 -5
- 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 +15 -0
- package/src/utils/installPromiseRejectionTracker.ts +91 -0
- package/src/utils/resendMessage.ts +2 -1
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)),
|
|
@@ -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,
|
|
@@ -1,18 +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
7
|
import {
|
|
7
8
|
addMessageToHeap,
|
|
8
9
|
clearMessageFailure,
|
|
9
10
|
markMessageFailed,
|
|
10
11
|
} from '../roomStore/roomHeapSlice';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
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';
|
|
13
16
|
import { useEventHandlers } from './useEventHandlers';
|
|
14
17
|
import type { IConfig, IMessage } from '../types/types';
|
|
15
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
|
+
|
|
16
28
|
// Monotonic counter for stanza ids. Bumped on each send within a single
|
|
17
29
|
// process. Two rapid sends in the same millisecond used to collide on
|
|
18
30
|
// `send-text-message-${Date.now()}`; that collision made
|
|
@@ -23,9 +35,18 @@ let __sendIdSeq = 0;
|
|
|
23
35
|
const nextStanzaId = (prefix: string): string =>
|
|
24
36
|
`${prefix}-${Date.now()}-${(__sendIdSeq = (__sendIdSeq + 1) >>> 0)}`;
|
|
25
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
|
+
|
|
26
43
|
export const useSendMessage = (_configOverride?: IConfig) => {
|
|
27
44
|
const { client } = useXmppClient();
|
|
28
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>();
|
|
29
50
|
|
|
30
51
|
// Split selectors so each returns a primitive/stable reference — the
|
|
31
52
|
// single-object selector above caused a "returned a different result
|
|
@@ -120,16 +141,85 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
120
141
|
);
|
|
121
142
|
}
|
|
122
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
|
+
|
|
123
179
|
try {
|
|
124
|
-
|
|
125
|
-
|
|
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;
|
|
126
216
|
}
|
|
127
217
|
// Pass the optimistic id as the stanza id so the server echoes
|
|
128
218
|
// it back with the same value — the reducer's dedupe lookup
|
|
129
219
|
// matches and the bubble flips from pending → delivered in-place
|
|
130
220
|
// (instead of rendering two copies, which is what happens when
|
|
131
221
|
// ids don't match).
|
|
132
|
-
|
|
222
|
+
effectiveClient.sendMessage(
|
|
133
223
|
activeRoomJID,
|
|
134
224
|
user.firstName,
|
|
135
225
|
user.lastName,
|
|
@@ -149,6 +239,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
149
239
|
messageType: 'text',
|
|
150
240
|
});
|
|
151
241
|
} catch (error) {
|
|
242
|
+
clearTimeout(watchdogTimer);
|
|
152
243
|
dispatch(
|
|
153
244
|
markMessageFailed({
|
|
154
245
|
kind: 'text',
|
|
@@ -168,7 +259,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
168
259
|
});
|
|
169
260
|
}
|
|
170
261
|
},
|
|
171
|
-
[editAction, client, user, dispatch, handleMessageSent, handleMessageEdited, handleMessageFailed]
|
|
262
|
+
[editAction, client, user, dispatch, handleMessageSent, handleMessageEdited, handleMessageFailed, reduxStore]
|
|
172
263
|
);
|
|
173
264
|
|
|
174
265
|
const sendMedia = useCallback(
|
|
@@ -183,6 +274,36 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
183
274
|
) => {
|
|
184
275
|
client?.onCriticalSend?.(activeRoomJID);
|
|
185
276
|
|
|
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
|
+
|
|
186
307
|
const id = existingId || `send-media-message:${uuidv4()}`;
|
|
187
308
|
const optimisticTimestamp = Date.now();
|
|
188
309
|
const optimisticDate = new Date(optimisticTimestamp).toISOString();
|
|
@@ -245,11 +366,94 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
245
366
|
);
|
|
246
367
|
}
|
|
247
368
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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);
|
|
251
404
|
|
|
252
|
-
|
|
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
|
+
};
|
|
422
|
+
|
|
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.
|
|
253
457
|
|
|
254
458
|
for (const item of response.data.results) {
|
|
255
459
|
const messagePayload = {
|
|
@@ -281,7 +485,34 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
281
485
|
// Stanza id == placeholder id so the MUC echo's outer
|
|
282
486
|
// <message id="..."> matches xmppId on the placeholder and
|
|
283
487
|
// insertMessageWithDelimiter merges in place + flips pending.
|
|
284
|
-
|
|
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
|
+
}
|
|
285
516
|
}
|
|
286
517
|
|
|
287
518
|
await handleMessageSent({
|
|
@@ -300,16 +531,30 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
300
531
|
},
|
|
301
532
|
});
|
|
302
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);
|
|
303
537
|
// Surface the real server payload so we can see why the upload
|
|
304
538
|
// was rejected (axios collapses the message to "Request failed
|
|
305
539
|
// with status code N"; the actual reason lives in
|
|
306
540
|
// `error.response.data`).
|
|
541
|
+
const uriStr = typeof data?.uri === 'string' ? data.uri : '';
|
|
542
|
+
const uriScheme = uriStr.match(/^([a-z]+):/i)?.[1] ?? 'unknown';
|
|
307
543
|
console.error('upload failed', {
|
|
308
544
|
status: error?.response?.status,
|
|
309
545
|
statusText: error?.response?.statusText,
|
|
310
546
|
serverBody: error?.response?.data,
|
|
311
547
|
requestUrl: error?.config?.url,
|
|
312
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,
|
|
313
558
|
});
|
|
314
559
|
dispatch(
|
|
315
560
|
markMessageFailed({
|
|
@@ -331,7 +576,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
331
576
|
});
|
|
332
577
|
}
|
|
333
578
|
},
|
|
334
|
-
[client, config, user, dispatch, handleMessageSent, handleMessageFailed]
|
|
579
|
+
[client, config, user, dispatch, handleMessageSent, handleMessageFailed, reduxStore]
|
|
335
580
|
);
|
|
336
581
|
|
|
337
582
|
// Retry a previously-failed send by replaying the saved payload from
|
|
@@ -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) {
|
|
@@ -142,3 +143,56 @@ export function uploadFile(formData: FormData) {
|
|
|
142
143
|
},
|
|
143
144
|
});
|
|
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',
|
|
196
|
+
});
|
|
197
|
+
return { data };
|
|
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);
|