@ethora/chat-component-rn 26.5.4 → 26.5.7
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 +66 -0
- package/README.md +25 -4
- package/lib/commonjs/components/ContextMenu/ContextMenuComponents.js +1 -7
- 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 +8 -2
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +2 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +11 -5
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageList.js +10 -2
- package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/Message.js +60 -7
- package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js +1 -38
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +20 -28
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +35 -16
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js +11 -2
- package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js +9 -6
- package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
- package/lib/commonjs/components/UsersList/Checkbox.js +68 -0
- package/lib/commonjs/components/UsersList/Checkbox.js.map +1 -0
- package/lib/commonjs/components/UsersList/StyledComponents.js +1 -7
- package/lib/commonjs/components/UsersList/StyledComponents.js.map +1 -1
- package/lib/commonjs/components/UsersList/UsersList.js +3 -1
- package/lib/commonjs/components/UsersList/UsersList.js.map +1 -1
- package/lib/commonjs/components/styled/MediaFilePreview.js +96 -5
- package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/commonjs/components/styled/MessageImage.js +1 -2
- package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +4 -2
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/VideoMessage.js +2 -10
- package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +71 -2
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/mimeToExtension.js +131 -0
- package/lib/commonjs/helpers/mimeToExtension.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/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/useMessageHeapState.js +6 -2
- package/lib/commonjs/hooks/useMessageHeapState.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +48 -4
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/networking/api-requests/auth.api.js +7 -1
- package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
- package/lib/commonjs/networking/xmppClient.js +87 -1
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/roomHeapSlice.js +26 -8
- package/lib/commonjs/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/module/components/ContextMenu/ContextMenuComponents.js +0 -6
- 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 +8 -2
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +2 -1
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +11 -5
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MainComponents/MessageList.js +11 -3
- package/lib/module/components/MainComponents/MessageList.js.map +1 -1
- package/lib/module/components/MessageBubble/Message.js +60 -7
- package/lib/module/components/MessageBubble/Message.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js +3 -40
- package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +21 -29
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +36 -17
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js +11 -2
- package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js +9 -6
- package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
- package/lib/module/components/UsersList/Checkbox.js +63 -0
- package/lib/module/components/UsersList/Checkbox.js.map +1 -0
- package/lib/module/components/UsersList/StyledComponents.js +0 -6
- package/lib/module/components/UsersList/StyledComponents.js.map +1 -1
- package/lib/module/components/UsersList/UsersList.js +2 -1
- package/lib/module/components/UsersList/UsersList.js.map +1 -1
- package/lib/module/components/styled/MediaFilePreview.js +97 -6
- package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/module/components/styled/MessageImage.js +1 -2
- package/lib/module/components/styled/MessageImage.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +4 -2
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/VideoMessage.js +2 -10
- package/lib/module/components/styled/VideoMessage.js.map +1 -1
- package/lib/module/context/xmppProvider.js +73 -3
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/mimeToExtension.js +124 -0
- package/lib/module/helpers/mimeToExtension.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/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/useMessageHeapState.js +6 -2
- package/lib/module/hooks/useMessageHeapState.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +49 -5
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/networking/api-requests/auth.api.js +7 -1
- package/lib/module/networking/api-requests/auth.api.js.map +1 -1
- package/lib/module/networking/xmppClient.js +87 -1
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/roomHeapSlice.js +24 -7
- package/lib/module/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/typescript/components/ContextMenu/ContextMenuComponents.d.ts +0 -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.map +1 -1
- package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.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/RoomComponents/styled/LastMessageEmoji.d.ts +8 -0
- package/lib/typescript/components/RoomComponents/styled/LastMessageEmoji.d.ts.map +1 -1
- package/lib/typescript/components/UsersList/Checkbox.d.ts +16 -0
- package/lib/typescript/components/UsersList/Checkbox.d.ts.map +1 -0
- package/lib/typescript/components/UsersList/StyledComponents.d.ts +0 -1
- package/lib/typescript/components/UsersList/StyledComponents.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/SendInput.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/mimeToExtension.d.ts +37 -0
- package/lib/typescript/helpers/mimeToExtension.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/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/useMessageHeapState.d.ts +2 -0
- package/lib/typescript/hooks/useMessageHeapState.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/networking/api-requests/auth.api.d.ts.map +1 -1
- package/lib/typescript/networking/xmppClient.d.ts +25 -1
- package/lib/typescript/networking/xmppClient.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/types/types.d.ts +6 -0
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/metro.js +17 -57
- package/package.json +1 -1
- package/src/components/ContextMenu/ContextMenuComponents.tsx +0 -7
- package/src/components/MainComponents/ChatHeader.tsx +5 -1
- package/src/components/MainComponents/ChatRoom.tsx +6 -1
- package/src/components/MainComponents/ChatWrapper.tsx +1 -0
- package/src/components/MainComponents/MediaMessage.tsx +15 -8
- package/src/components/MainComponents/MessageList.tsx +10 -3
- package/src/components/MessageBubble/Message.tsx +64 -10
- package/src/components/MessageBubble/MessageInteractions.tsx +2 -105
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +20 -41
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +30 -12
- package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +22 -1
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +1 -1
- package/src/components/RoomComponents/styled/LastMessageEmoji.tsx +9 -7
- package/src/components/UsersList/Checkbox.tsx +68 -0
- package/src/components/UsersList/StyledComponents.ts +0 -8
- package/src/components/UsersList/UsersList.tsx +1 -1
- package/src/components/styled/MediaFilePreview.tsx +91 -5
- package/src/components/styled/MessageImage.tsx +1 -2
- package/src/components/styled/SendInput.tsx +3 -0
- package/src/components/styled/VideoMessage.tsx +3 -10
- package/src/context/xmppProvider.tsx +90 -2
- package/src/helpers/mimeToExtension.ts +135 -0
- package/src/helpers/resolveInitBeforeLoadUser.ts +79 -0
- package/src/hooks/useChatWrapperInit.ts +51 -46
- package/src/hooks/useEventHandlers.tsx +24 -1
- package/src/hooks/useMessageHeapState.tsx +6 -2
- package/src/hooks/useSendMessage.tsx +75 -4
- package/src/networking/api-requests/auth.api.ts +5 -1
- package/src/networking/xmppClient.ts +95 -1
- package/src/roomStore/roomHeapSlice.ts +47 -4
- package/src/types/types.ts +10 -0
- package/lib/commonjs/components/InputComponents/AudioInput.js +0 -23
- package/lib/commonjs/components/InputComponents/AudioInput.js.map +0 -1
- package/lib/commonjs/components/InputComponents/AudioRecorder.js +0 -101
- package/lib/commonjs/components/InputComponents/AudioRecorder.js.map +0 -1
- package/lib/commonjs/components/InputComponents/MediaInput.js +0 -98
- package/lib/commonjs/components/InputComponents/MediaInput.js.map +0 -1
- package/lib/commonjs/components/InputComponents/RecordingIndicator.js +0 -70
- package/lib/commonjs/components/InputComponents/RecordingIndicator.js.map +0 -1
- package/lib/commonjs/components/Modals/ModalSelectMedia/ModalSelectMedia.js +0 -207
- package/lib/commonjs/components/Modals/ModalSelectMedia/ModalSelectMedia.js.map +0 -1
- package/lib/commonjs/components/OperationalModal/OperationalModal.js +0 -83
- package/lib/commonjs/components/OperationalModal/OperationalModal.js.map +0 -1
- package/lib/module/components/InputComponents/AudioInput.js +0 -18
- package/lib/module/components/InputComponents/AudioInput.js.map +0 -1
- package/lib/module/components/InputComponents/AudioRecorder.js +0 -95
- package/lib/module/components/InputComponents/AudioRecorder.js.map +0 -1
- package/lib/module/components/InputComponents/MediaInput.js +0 -92
- package/lib/module/components/InputComponents/MediaInput.js.map +0 -1
- package/lib/module/components/InputComponents/RecordingIndicator.js +0 -65
- package/lib/module/components/InputComponents/RecordingIndicator.js.map +0 -1
- package/lib/module/components/Modals/ModalSelectMedia/ModalSelectMedia.js +0 -200
- package/lib/module/components/Modals/ModalSelectMedia/ModalSelectMedia.js.map +0 -1
- package/lib/module/components/OperationalModal/OperationalModal.js +0 -77
- package/lib/module/components/OperationalModal/OperationalModal.js.map +0 -1
- package/lib/typescript/components/InputComponents/AudioInput.d.ts +0 -9
- package/lib/typescript/components/InputComponents/AudioInput.d.ts.map +0 -1
- package/lib/typescript/components/InputComponents/AudioRecorder.d.ts +0 -9
- package/lib/typescript/components/InputComponents/AudioRecorder.d.ts.map +0 -1
- package/lib/typescript/components/InputComponents/MediaInput.d.ts +0 -16
- package/lib/typescript/components/InputComponents/MediaInput.d.ts.map +0 -1
- package/lib/typescript/components/InputComponents/RecordingIndicator.d.ts +0 -4
- package/lib/typescript/components/InputComponents/RecordingIndicator.d.ts.map +0 -1
- package/lib/typescript/components/Modals/ModalSelectMedia/ModalSelectMedia.d.ts +0 -9
- package/lib/typescript/components/Modals/ModalSelectMedia/ModalSelectMedia.d.ts.map +0 -1
- package/lib/typescript/components/OperationalModal/OperationalModal.d.ts +0 -9
- package/lib/typescript/components/OperationalModal/OperationalModal.d.ts.map +0 -1
- package/src/components/InputComponents/AudioInput.tsx +0 -24
- package/src/components/InputComponents/AudioRecorder.tsx +0 -100
- package/src/components/InputComponents/MediaInput.tsx +0 -113
- package/src/components/InputComponents/RecordingIndicator.tsx +0 -77
- package/src/components/Modals/ModalSelectMedia/ModalSelectMedia.tsx +0 -283
- package/src/components/OperationalModal/OperationalModal.tsx +0 -78
|
@@ -23,10 +23,17 @@ interface MessageEditedEvent {
|
|
|
23
23
|
user: any;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
interface MessageRetryEvent {
|
|
27
|
+
messageId: string;
|
|
28
|
+
roomJID: string;
|
|
29
|
+
messageType: 'text' | 'media';
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
export interface EventHandlersHook {
|
|
27
33
|
handleMessageSent: (event: MessageSentEvent) => Promise<void>;
|
|
28
34
|
handleMessageFailed: (event: MessageFailedEvent) => void;
|
|
29
35
|
handleMessageEdited: (event: MessageEditedEvent) => void;
|
|
36
|
+
handleMessageRetry: (event: MessageRetryEvent) => void;
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
export const useEventHandlers = (config?: IConfig): EventHandlersHook => {
|
|
@@ -77,5 +84,21 @@ export const useEventHandlers = (config?: IConfig): EventHandlersHook => {
|
|
|
77
84
|
[config]
|
|
78
85
|
);
|
|
79
86
|
|
|
80
|
-
|
|
87
|
+
const handleMessageRetry = useCallback(
|
|
88
|
+
(event: MessageRetryEvent) => {
|
|
89
|
+
try {
|
|
90
|
+
config?.eventHandlers?.onMessageRetry?.(event);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error('Error in message retry handler:', error);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
[config]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
handleMessageSent,
|
|
100
|
+
handleMessageFailed,
|
|
101
|
+
handleMessageEdited,
|
|
102
|
+
handleMessageRetry,
|
|
103
|
+
};
|
|
81
104
|
};
|
|
@@ -3,9 +3,13 @@ import { RootState } from '../roomStore';
|
|
|
3
3
|
|
|
4
4
|
export const useMessageHeapState = () => {
|
|
5
5
|
const queue = useSelector(
|
|
6
|
-
(state: RootState) => state.roomHeapSlice
|
|
6
|
+
(state: RootState) => state.roomHeapSlice?.messageHeap
|
|
7
|
+
);
|
|
8
|
+
const failedMessages = useSelector(
|
|
9
|
+
(state: RootState) => state.roomHeapSlice?.failedMessages
|
|
7
10
|
);
|
|
8
11
|
const idSet = new Set(queue?.map((m) => m.id) ?? []);
|
|
12
|
+
const failedIdSet = new Set(Object.keys(failedMessages || {}));
|
|
9
13
|
|
|
10
|
-
return { queue, idSet };
|
|
14
|
+
return { queue, idSet, failedMessages, failedIdSet };
|
|
11
15
|
};
|
|
@@ -3,7 +3,11 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
3
3
|
import { useXmppClient } from '../context/xmppProvider';
|
|
4
4
|
import { useDispatch, useSelector } from 'react-redux';
|
|
5
5
|
import { addRoomMessage, setEditAction } from '../roomStore/roomsSlice';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
addMessageToHeap,
|
|
8
|
+
clearMessageFailure,
|
|
9
|
+
markMessageFailed,
|
|
10
|
+
} from '../roomStore/roomHeapSlice';
|
|
7
11
|
import { uploadFile } from '../networking/api-requests/auth.api';
|
|
8
12
|
import { RootState } from '../roomStore';
|
|
9
13
|
import { useEventHandlers } from './useEventHandlers';
|
|
@@ -38,8 +42,13 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
38
42
|
handleMessageSent,
|
|
39
43
|
handleMessageFailed,
|
|
40
44
|
handleMessageEdited,
|
|
45
|
+
handleMessageRetry,
|
|
41
46
|
} = useEventHandlers(config);
|
|
42
47
|
|
|
48
|
+
const failedMessages = useSelector(
|
|
49
|
+
(state: RootState) => state.roomHeapSlice?.failedMessages || {}
|
|
50
|
+
);
|
|
51
|
+
|
|
43
52
|
const sendMessage = useCallback(
|
|
44
53
|
async (
|
|
45
54
|
message: string,
|
|
@@ -140,6 +149,17 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
140
149
|
messageType: 'text',
|
|
141
150
|
});
|
|
142
151
|
} catch (error) {
|
|
152
|
+
dispatch(
|
|
153
|
+
markMessageFailed({
|
|
154
|
+
kind: 'text',
|
|
155
|
+
id: optimisticId,
|
|
156
|
+
roomJID: activeRoomJID,
|
|
157
|
+
body: message,
|
|
158
|
+
isReply,
|
|
159
|
+
isChecked,
|
|
160
|
+
mainMessage,
|
|
161
|
+
})
|
|
162
|
+
);
|
|
143
163
|
handleMessageFailed({
|
|
144
164
|
message,
|
|
145
165
|
roomJID: activeRoomJID,
|
|
@@ -158,11 +178,12 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
158
178
|
activeRoomJID: string,
|
|
159
179
|
isReply: boolean = false,
|
|
160
180
|
isChecked: boolean = false,
|
|
161
|
-
mainMessage: string = ''
|
|
181
|
+
mainMessage: string = '',
|
|
182
|
+
existingId?: string
|
|
162
183
|
) => {
|
|
163
184
|
client?.onCriticalSend?.(activeRoomJID);
|
|
164
185
|
|
|
165
|
-
const id = `send-media-message:${uuidv4()}`;
|
|
186
|
+
const id = existingId || `send-media-message:${uuidv4()}`;
|
|
166
187
|
const optimisticTimestamp = Date.now();
|
|
167
188
|
const optimisticDate = new Date(optimisticTimestamp).toISOString();
|
|
168
189
|
const selfId =
|
|
@@ -171,7 +192,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
171
192
|
`${user?.firstName || ''} ${user?.lastName || ''}`.trim() || selfId;
|
|
172
193
|
const fileSizeStr = data?.size != null ? String(data.size) : '';
|
|
173
194
|
|
|
174
|
-
if (!config?.disableSentLogic) {
|
|
195
|
+
if (!config?.disableSentLogic && !existingId) {
|
|
175
196
|
dispatch(
|
|
176
197
|
addRoomMessage({
|
|
177
198
|
roomJID: activeRoomJID,
|
|
@@ -290,6 +311,18 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
290
311
|
requestUrl: error?.config?.url,
|
|
291
312
|
axiosMessage: error?.message,
|
|
292
313
|
});
|
|
314
|
+
dispatch(
|
|
315
|
+
markMessageFailed({
|
|
316
|
+
kind: 'media',
|
|
317
|
+
id,
|
|
318
|
+
roomJID: activeRoomJID,
|
|
319
|
+
data,
|
|
320
|
+
type,
|
|
321
|
+
isReply,
|
|
322
|
+
isChecked,
|
|
323
|
+
mainMessage,
|
|
324
|
+
})
|
|
325
|
+
);
|
|
293
326
|
handleMessageFailed({
|
|
294
327
|
message: 'media',
|
|
295
328
|
roomJID: activeRoomJID,
|
|
@@ -301,6 +334,43 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
301
334
|
[client, config, user, dispatch, handleMessageSent, handleMessageFailed]
|
|
302
335
|
);
|
|
303
336
|
|
|
337
|
+
// Retry a previously-failed send by replaying the saved payload from
|
|
338
|
+
// the heap. Clears the failure flag first so the bubble flips back to
|
|
339
|
+
// "sending..."; if the retry fails again `markMessageFailed` re-arms
|
|
340
|
+
// it. No-op when the id isn't in the failed map.
|
|
341
|
+
const retryMessage = useCallback(
|
|
342
|
+
async (failedId: string) => {
|
|
343
|
+
const payload = failedMessages[failedId];
|
|
344
|
+
if (!payload) {return;}
|
|
345
|
+
dispatch(clearMessageFailure(failedId));
|
|
346
|
+
handleMessageRetry({
|
|
347
|
+
messageId: failedId,
|
|
348
|
+
roomJID: payload.roomJID,
|
|
349
|
+
messageType: payload.kind,
|
|
350
|
+
});
|
|
351
|
+
if (payload.kind === 'text') {
|
|
352
|
+
await sendMessage(
|
|
353
|
+
payload.body,
|
|
354
|
+
payload.roomJID,
|
|
355
|
+
payload.isReply,
|
|
356
|
+
payload.isChecked,
|
|
357
|
+
payload.mainMessage
|
|
358
|
+
);
|
|
359
|
+
} else {
|
|
360
|
+
await sendMedia(
|
|
361
|
+
payload.data,
|
|
362
|
+
payload.type,
|
|
363
|
+
payload.roomJID,
|
|
364
|
+
payload.isReply,
|
|
365
|
+
payload.isChecked,
|
|
366
|
+
payload.mainMessage,
|
|
367
|
+
failedId
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
[failedMessages, dispatch, handleMessageRetry, sendMessage, sendMedia]
|
|
372
|
+
);
|
|
373
|
+
|
|
304
374
|
// ChatRoom/ThreadWrapper consume this as the "edit branch" of send.
|
|
305
375
|
// It mirrors the edit path inside `sendMessage` so callers can wire it
|
|
306
376
|
// up directly when `editAction.isEdit` is true.
|
|
@@ -355,6 +425,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
355
425
|
sendMessage,
|
|
356
426
|
sendMedia,
|
|
357
427
|
sendEditMessage,
|
|
428
|
+
retryMessage,
|
|
358
429
|
isLastMessageFromUserAndProcessing,
|
|
359
430
|
};
|
|
360
431
|
};
|
|
@@ -134,7 +134,11 @@ export function uploadFile(formData: FormData) {
|
|
|
134
134
|
headers: {
|
|
135
135
|
Authorization: token,
|
|
136
136
|
Accept: '*/*',
|
|
137
|
-
'Content-Type':
|
|
137
|
+
'Content-Type': null,
|
|
138
|
+
},
|
|
139
|
+
transformRequest: (data: any, headers: any) => {
|
|
140
|
+
if (headers?.delete) {headers.delete('Content-Type');}
|
|
141
|
+
return data;
|
|
138
142
|
},
|
|
139
143
|
});
|
|
140
144
|
}
|
|
@@ -26,6 +26,25 @@ import { pushLog as devPushLog } from '../utils/devLogger';
|
|
|
26
26
|
// Canonical production XMPP WSS endpoint (standard wss/443, no port suffix).
|
|
27
27
|
const DEFAULT_DEV_SERVER = 'xmpp.chat.ethora.com';
|
|
28
28
|
|
|
29
|
+
// @xmpp/client surfaces SASL/stream errors in a few shapes depending on
|
|
30
|
+
// where it fails — XMPPError on stream:error, SASLError on SASL bind, or
|
|
31
|
+
// a generic Error whose message contains "not-authorized". Match all of
|
|
32
|
+
// them so we trigger the credentials refresh path consistently.
|
|
33
|
+
function isNotAuthorizedError(err: any): boolean {
|
|
34
|
+
if (!err) {return false;}
|
|
35
|
+
const condition =
|
|
36
|
+
err?.condition ||
|
|
37
|
+
err?.name ||
|
|
38
|
+
err?.type ||
|
|
39
|
+
err?.error?.condition ||
|
|
40
|
+
'';
|
|
41
|
+
if (typeof condition === 'string' && condition.includes('not-authorized')) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
const message = (err?.message || err?.text || '').toString();
|
|
45
|
+
return /not-authorized|SASLError/i.test(message);
|
|
46
|
+
}
|
|
47
|
+
|
|
29
48
|
type HistorySource = 'active' | 'send_ack' | 'background' | 'default';
|
|
30
49
|
|
|
31
50
|
interface HistoryOptions {
|
|
@@ -40,6 +59,11 @@ interface MamInFlightEntry {
|
|
|
40
59
|
startedAt: number;
|
|
41
60
|
}
|
|
42
61
|
|
|
62
|
+
export type XmppCredentialsProvider = () => Promise<{
|
|
63
|
+
username: string;
|
|
64
|
+
password: string;
|
|
65
|
+
}>;
|
|
66
|
+
|
|
43
67
|
export class XmppClient {
|
|
44
68
|
client!: Client;
|
|
45
69
|
xmppSettings?: xmppSettingsInterface;
|
|
@@ -56,6 +80,13 @@ export class XmppClient {
|
|
|
56
80
|
reconnectDelay = 2000;
|
|
57
81
|
suppressReconnect = false;
|
|
58
82
|
|
|
83
|
+
// Set when SASL fails with `not-authorized` (typically a stale JWT-
|
|
84
|
+
// derived XMPP password after idle). Triggers the credentialsProvider
|
|
85
|
+
// refresh path in reconnect().
|
|
86
|
+
lastAuthError: 'not-authorized' | null = null;
|
|
87
|
+
private credentialsProvider: XmppCredentialsProvider | null = null;
|
|
88
|
+
private credentialsRefreshInFlight: Promise<void> | null = null;
|
|
89
|
+
|
|
59
90
|
// ---- QoS state (mirrors web XmppClient) ----------------------------
|
|
60
91
|
presencesReady = false;
|
|
61
92
|
disableLastRead = false;
|
|
@@ -74,6 +105,23 @@ export class XmppClient {
|
|
|
74
105
|
return this.client && this.client.status === 'online';
|
|
75
106
|
}
|
|
76
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Inject (or replace) the callback used by reconnect() to fetch fresh
|
|
110
|
+
* XMPP credentials after a `not-authorized` SASL failure. The provider
|
|
111
|
+
* is responsible for refreshing whatever upstream token is needed
|
|
112
|
+
* (REST JWT, /users/client, etc.) and returning the resulting
|
|
113
|
+
* username + password.
|
|
114
|
+
*/
|
|
115
|
+
setCredentialsProvider(provider: XmppCredentialsProvider | null) {
|
|
116
|
+
this.credentialsProvider = provider;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Swap in fresh credentials before the next reconnect. */
|
|
120
|
+
updateCredentials(username: string, password: string) {
|
|
121
|
+
this.username = username;
|
|
122
|
+
this.password = password;
|
|
123
|
+
}
|
|
124
|
+
|
|
77
125
|
constructor(
|
|
78
126
|
username: string,
|
|
79
127
|
password: string,
|
|
@@ -285,6 +333,9 @@ export class XmppClient {
|
|
|
285
333
|
this.attachEventListeners();
|
|
286
334
|
this.client.start().catch((error: any) => {
|
|
287
335
|
console.error('Error starting xmpp client:', error);
|
|
336
|
+
if (isNotAuthorizedError(error)) {
|
|
337
|
+
this.lastAuthError = 'not-authorized';
|
|
338
|
+
}
|
|
288
339
|
this.status = 'error';
|
|
289
340
|
});
|
|
290
341
|
} catch (error) {
|
|
@@ -320,6 +371,9 @@ export class XmppClient {
|
|
|
320
371
|
|
|
321
372
|
this.client.on('error', (error: any) => {
|
|
322
373
|
console.error('XMPP client error:', error);
|
|
374
|
+
if (isNotAuthorizedError(error)) {
|
|
375
|
+
this.lastAuthError = 'not-authorized';
|
|
376
|
+
}
|
|
323
377
|
try {
|
|
324
378
|
devPushLog(
|
|
325
379
|
'xmpp',
|
|
@@ -385,9 +439,25 @@ export class XmppClient {
|
|
|
385
439
|
setTimeout(() => this.reconnect(), delay);
|
|
386
440
|
}
|
|
387
441
|
|
|
388
|
-
reconnect() {
|
|
442
|
+
async reconnect() {
|
|
389
443
|
if (this.suppressReconnect) {return;}
|
|
390
444
|
console.log('Attempting to reconnect xmpp client...');
|
|
445
|
+
|
|
446
|
+
// If the last failure was a SASL `not-authorized` (typically a stale
|
|
447
|
+
// JWT-derived XMPP password after idle), try to fetch fresh creds
|
|
448
|
+
// before retrying. Without this, reconnect retries with the same
|
|
449
|
+
// stale password forever and the user has to kill the app.
|
|
450
|
+
if (this.lastAuthError === 'not-authorized' && this.credentialsProvider) {
|
|
451
|
+
try {
|
|
452
|
+
await this.refreshCredentialsOnce();
|
|
453
|
+
} catch (err) {
|
|
454
|
+
console.warn(
|
|
455
|
+
'XMPP credential refresh failed; reconnecting with cached creds',
|
|
456
|
+
err
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
391
461
|
if (this.client) {
|
|
392
462
|
this.client.stop().finally(() => {
|
|
393
463
|
this.initializeClient();
|
|
@@ -397,6 +467,30 @@ export class XmppClient {
|
|
|
397
467
|
}
|
|
398
468
|
}
|
|
399
469
|
|
|
470
|
+
/**
|
|
471
|
+
* Single-flight wrapper around credentialsProvider. Multiple concurrent
|
|
472
|
+
* reconnect() calls (e.g. from the provider's reconnect effect firing
|
|
473
|
+
* twice quickly) share one in-flight request and update `this.password`
|
|
474
|
+
* exactly once.
|
|
475
|
+
*/
|
|
476
|
+
private refreshCredentialsOnce(): Promise<void> {
|
|
477
|
+
if (this.credentialsRefreshInFlight) {return this.credentialsRefreshInFlight;}
|
|
478
|
+
if (!this.credentialsProvider) {return Promise.resolve();}
|
|
479
|
+
const provider = this.credentialsProvider;
|
|
480
|
+
this.credentialsRefreshInFlight = (async () => {
|
|
481
|
+
try {
|
|
482
|
+
const fresh = await provider();
|
|
483
|
+
if (fresh?.username && fresh?.password) {
|
|
484
|
+
this.updateCredentials(fresh.username, fresh.password);
|
|
485
|
+
this.lastAuthError = null;
|
|
486
|
+
}
|
|
487
|
+
} finally {
|
|
488
|
+
this.credentialsRefreshInFlight = null;
|
|
489
|
+
}
|
|
490
|
+
})();
|
|
491
|
+
return this.credentialsRefreshInFlight;
|
|
492
|
+
}
|
|
493
|
+
|
|
400
494
|
async disconnect(options?: { suppressReconnect?: boolean }): Promise<void> {
|
|
401
495
|
if (options?.suppressReconnect) {this.suppressReconnect = true;}
|
|
402
496
|
return this.close();
|
|
@@ -2,18 +2,43 @@ import { createSlice, PayloadAction, type Slice } from '@reduxjs/toolkit';
|
|
|
2
2
|
import type { WritableDraft } from 'immer';
|
|
3
3
|
import { IMessage } from '../types/types';
|
|
4
4
|
|
|
5
|
+
// Saved alongside a failed-message id so the retry button can resend
|
|
6
|
+
// without the bubble needing to remember the original draft itself.
|
|
7
|
+
// `kind === 'text'` carries the plain body; `kind === 'media'` carries
|
|
8
|
+
// the upload payload so we don't have to make the user re-pick the file.
|
|
9
|
+
export type FailedMessagePayload =
|
|
10
|
+
| {
|
|
11
|
+
kind: 'text';
|
|
12
|
+
id: string;
|
|
13
|
+
roomJID: string;
|
|
14
|
+
body: string;
|
|
15
|
+
isReply?: boolean;
|
|
16
|
+
isChecked?: boolean;
|
|
17
|
+
mainMessage?: string;
|
|
18
|
+
}
|
|
19
|
+
| {
|
|
20
|
+
kind: 'media';
|
|
21
|
+
id: string;
|
|
22
|
+
roomJID: string;
|
|
23
|
+
data: any;
|
|
24
|
+
type: string;
|
|
25
|
+
isReply?: boolean;
|
|
26
|
+
isChecked?: boolean;
|
|
27
|
+
mainMessage?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
5
30
|
export interface roomHeapSliceState {
|
|
6
31
|
messageHeap: IMessage[];
|
|
32
|
+
// Keyed by message id so the bubble's `isFailed = failedMessages[id]`
|
|
33
|
+
// check is O(1). Carries enough payload data to actually retry.
|
|
34
|
+
failedMessages: Record<string, FailedMessagePayload>;
|
|
7
35
|
}
|
|
8
36
|
|
|
9
37
|
const initialState: roomHeapSliceState = {
|
|
10
38
|
messageHeap: [],
|
|
39
|
+
failedMessages: {},
|
|
11
40
|
};
|
|
12
41
|
|
|
13
|
-
// Reducers extracted as a named const so we can give the slice an
|
|
14
|
-
// explicit Slice<State, typeof reducers, Name> type. Without that, tsc's
|
|
15
|
-
// declaration emission inlines immer's internal WritableNonArrayDraft
|
|
16
|
-
// type and fails with TS4023.
|
|
17
42
|
const reducers = {
|
|
18
43
|
addMessageToHeap: (state: WritableDraft<roomHeapSliceState>, action: PayloadAction<IMessage>) => {
|
|
19
44
|
state.messageHeap.push(action.payload);
|
|
@@ -26,6 +51,22 @@ const reducers = {
|
|
|
26
51
|
},
|
|
27
52
|
clearHeap: (state: WritableDraft<roomHeapSliceState>) => {
|
|
28
53
|
state.messageHeap = [];
|
|
54
|
+
state.failedMessages = {};
|
|
55
|
+
},
|
|
56
|
+
markMessageFailed: (
|
|
57
|
+
state: WritableDraft<roomHeapSliceState>,
|
|
58
|
+
action: PayloadAction<FailedMessagePayload>
|
|
59
|
+
) => {
|
|
60
|
+
state.failedMessages[action.payload.id] = action.payload;
|
|
61
|
+
// Drop from the pending heap — the bubble looks at both, and
|
|
62
|
+
// showing "sending..." alongside a failure indicator is confusing.
|
|
63
|
+
const index = state.messageHeap.findIndex((m) => m.id === action.payload.id);
|
|
64
|
+
if (index !== -1) {
|
|
65
|
+
state.messageHeap.splice(index, 1);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
clearMessageFailure: (state: WritableDraft<roomHeapSliceState>, action: PayloadAction<string>) => {
|
|
69
|
+
delete state.failedMessages[action.payload];
|
|
29
70
|
},
|
|
30
71
|
};
|
|
31
72
|
|
|
@@ -39,6 +80,8 @@ export const {
|
|
|
39
80
|
addMessageToHeap,
|
|
40
81
|
clearHeap,
|
|
41
82
|
removeMessageFromHeapById,
|
|
83
|
+
markMessageFailed,
|
|
84
|
+
clearMessageFailure,
|
|
42
85
|
} = roomHeapSlice.actions;
|
|
43
86
|
|
|
44
87
|
export default roomHeapSlice.reducer;
|
package/src/types/types.ts
CHANGED
|
@@ -249,6 +249,11 @@ export interface IConfig {
|
|
|
249
249
|
disableHeader?: boolean;
|
|
250
250
|
disableMedia?: boolean;
|
|
251
251
|
chatHeaderBurgerMenu?: boolean;
|
|
252
|
+
// Hide the burger icon entirely (the icon that opens the chatHeader-
|
|
253
|
+
// BurgerMenu dropdown). `chatHeaderBurgerMenu` controls dropdown
|
|
254
|
+
// visibility only — set this flag when you want neither the icon nor
|
|
255
|
+
// the dropdown to render (e.g. patient-facing apps with a single room).
|
|
256
|
+
disableChatHeaderBurgerMenuIcon?: boolean;
|
|
252
257
|
chatHeaderAdditional?: { enabled: boolean; element: any };
|
|
253
258
|
headerMenu?: () => void;
|
|
254
259
|
headerChatMenu?: () => void;
|
|
@@ -420,6 +425,11 @@ export interface IConfig {
|
|
|
420
425
|
roomJID: string;
|
|
421
426
|
user: any;
|
|
422
427
|
}) => void;
|
|
428
|
+
onMessageRetry?: (event: {
|
|
429
|
+
messageId: string;
|
|
430
|
+
roomJID: string;
|
|
431
|
+
messageType: 'text' | 'media';
|
|
432
|
+
}) => void;
|
|
423
433
|
};
|
|
424
434
|
}
|
|
425
435
|
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
var _react = _interopRequireDefault(require("react"));
|
|
8
|
-
var _AudioRecorder = _interopRequireDefault(require("../InputComponents/AudioRecorder"));
|
|
9
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
10
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
-
const AudioInput = ({
|
|
12
|
-
isRecording,
|
|
13
|
-
setIsRecording,
|
|
14
|
-
handleSendClick
|
|
15
|
-
}) => {
|
|
16
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_AudioRecorder.default, {
|
|
17
|
-
setIsRecording: setIsRecording,
|
|
18
|
-
isRecording: isRecording,
|
|
19
|
-
handleSendClick: handleSendClick
|
|
20
|
-
});
|
|
21
|
-
};
|
|
22
|
-
var _default = exports.default = AudioInput;
|
|
23
|
-
//# sourceMappingURL=AudioInput.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireDefault","require","_AudioRecorder","_jsxRuntime","e","__esModule","default","AudioInput","isRecording","setIsRecording","handleSendClick","jsx","_default","exports"],"sourceRoot":"../../../../src","sources":["components/InputComponents/AudioInput.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,cAAA,GAAAF,sBAAA,CAAAC,OAAA;AAA6D,IAAAE,WAAA,GAAAF,OAAA;AAAA,SAAAD,uBAAAI,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAQ7D,MAAMG,UAAqC,GAAGA,CAAC;EAC7CC,WAAW;EACXC,cAAc;EACdC;AACF,CAAC,KAAK;EACJ,oBACE,IAAAP,WAAA,CAAAQ,GAAA,EAACT,cAAA,CAAAI,OAAa;IACZG,cAAc,EAAEA,cAAe;IAC/BD,WAAW,EAAEA,WAAY;IACzBE,eAAe,EAAEA;EAAgB,CAClC,CAAC;AAEN,CAAC;AAAC,IAAAE,QAAA,GAAAC,OAAA,CAAAP,OAAA,GAEaC,UAAU","ignoreList":[]}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
-
var _StyledInputComponents = require("../styled/StyledInputComponents/StyledInputComponents");
|
|
9
|
-
var _icons = require("../../assets/icons");
|
|
10
|
-
var _Button = _interopRequireDefault(require("../styled/Button"));
|
|
11
|
-
var _RecordingIndicator = _interopRequireDefault(require("./RecordingIndicator"));
|
|
12
|
-
var _reactNative = require("react-native");
|
|
13
|
-
var _reactNativeAudioRecorderPlayer = _interopRequireDefault(require("react-native-audio-recorder-player"));
|
|
14
|
-
var _reactNativeFs = _interopRequireDefault(require("react-native-fs"));
|
|
15
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
16
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
|
-
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
18
|
-
const AudioRecorder = ({
|
|
19
|
-
setIsRecording,
|
|
20
|
-
isRecording,
|
|
21
|
-
handleSendClick
|
|
22
|
-
}) => {
|
|
23
|
-
const audioRecorderPlayer = (0, _react.useRef)(new _reactNativeAudioRecorderPlayer.default()).current;
|
|
24
|
-
const [timer, setTimer] = (0, _react.useState)('00:00');
|
|
25
|
-
const [audioPath, setAudioPath] = (0, _react.useState)(null);
|
|
26
|
-
(0, _react.useEffect)(() => {
|
|
27
|
-
return () => {
|
|
28
|
-
audioRecorderPlayer.stopRecorder();
|
|
29
|
-
audioRecorderPlayer.removeRecordBackListener();
|
|
30
|
-
};
|
|
31
|
-
}, [audioRecorderPlayer]);
|
|
32
|
-
const startRecording = async () => {
|
|
33
|
-
try {
|
|
34
|
-
const path = _reactNative.Platform.select({
|
|
35
|
-
ios: `${_reactNativeFs.default.DocumentDirectoryPath}/recording.m4a`,
|
|
36
|
-
android: `${_reactNativeFs.default.CachesDirectoryPath}/recording.mp4`
|
|
37
|
-
});
|
|
38
|
-
const uri = await audioRecorderPlayer.startRecorder(path);
|
|
39
|
-
setAudioPath(uri);
|
|
40
|
-
audioRecorderPlayer.addRecordBackListener(e => {
|
|
41
|
-
const minutes = Math.floor(e.currentPosition / 60000);
|
|
42
|
-
const seconds = Math.floor(e.currentPosition % 60000 / 1000);
|
|
43
|
-
setTimer(`${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`);
|
|
44
|
-
});
|
|
45
|
-
setIsRecording(true);
|
|
46
|
-
} catch (error) {
|
|
47
|
-
console.error('Error starting recording:', error);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
const stopRecording = async () => {
|
|
51
|
-
try {
|
|
52
|
-
await audioRecorderPlayer.stopRecorder();
|
|
53
|
-
audioRecorderPlayer.removeRecordBackListener();
|
|
54
|
-
setIsRecording(false);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
console.error('Error stopping recording:', error);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
const sendAudio = () => {
|
|
60
|
-
if (audioPath) {
|
|
61
|
-
console.log('Audio sent:', audioPath);
|
|
62
|
-
handleSendClick(audioPath);
|
|
63
|
-
resetState();
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
const resetState = () => {
|
|
67
|
-
setAudioPath(null);
|
|
68
|
-
setTimer('00:00');
|
|
69
|
-
setIsRecording(false);
|
|
70
|
-
};
|
|
71
|
-
return isRecording ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_StyledInputComponents.RecordContainer, {
|
|
72
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
73
|
-
style: {
|
|
74
|
-
display: 'flex',
|
|
75
|
-
alignItems: 'center'
|
|
76
|
-
},
|
|
77
|
-
children: [isRecording && /*#__PURE__*/(0, _jsxRuntime.jsx)(_RecordingIndicator.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_StyledInputComponents.Timer, {
|
|
78
|
-
children: timer
|
|
79
|
-
})]
|
|
80
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
81
|
-
style: {
|
|
82
|
-
display: 'flex',
|
|
83
|
-
gap: 8
|
|
84
|
-
},
|
|
85
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
|
|
86
|
-
onPress: stopRecording,
|
|
87
|
-
EndIcon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.RemoveIcon, {}),
|
|
88
|
-
unstyled: true
|
|
89
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
|
|
90
|
-
onPress: sendAudio,
|
|
91
|
-
EndIcon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.SendIcon, {}),
|
|
92
|
-
unstyled: true
|
|
93
|
-
})]
|
|
94
|
-
})]
|
|
95
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
|
|
96
|
-
onPress: startRecording,
|
|
97
|
-
EndIcon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.RecordIcon, {})
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
var _default = exports.default = AudioRecorder;
|
|
101
|
-
//# sourceMappingURL=AudioRecorder.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_StyledInputComponents","_icons","_Button","_interopRequireDefault","_RecordingIndicator","_reactNative","_reactNativeAudioRecorderPlayer","_reactNativeFs","_jsxRuntime","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","AudioRecorder","setIsRecording","isRecording","handleSendClick","audioRecorderPlayer","useRef","AudioRecorderPlayer","current","timer","setTimer","useState","audioPath","setAudioPath","useEffect","stopRecorder","removeRecordBackListener","startRecording","path","Platform","select","ios","RNFS","DocumentDirectoryPath","android","CachesDirectoryPath","uri","startRecorder","addRecordBackListener","minutes","Math","floor","currentPosition","seconds","toString","padStart","error","console","stopRecording","sendAudio","log","resetState","jsxs","RecordContainer","children","View","style","display","alignItems","jsx","Timer","gap","onPress","EndIcon","RemoveIcon","unstyled","SendIcon","RecordIcon","_default","exports"],"sourceRoot":"../../../../src","sources":["components/InputComponents/AudioRecorder.tsx"],"mappings":"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","ignoreList":[]}
|