@droppii-org/chat-mobile 0.2.50 → 0.2.51
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/lib/module/components/StickerPicker/StickerCategoryTabs.js +86 -0
- package/lib/module/components/StickerPicker/StickerCategoryTabs.js.map +1 -0
- package/lib/module/components/StickerPicker/StickerPickerPlaceholder.js +18 -0
- package/lib/module/components/StickerPicker/StickerPickerPlaceholder.js.map +1 -0
- package/lib/module/components/StickerPicker/StickerPickerRowItem.js +35 -0
- package/lib/module/components/StickerPicker/StickerPickerRowItem.js.map +1 -0
- package/lib/module/components/StickerPicker/StickerSectionList.js +110 -0
- package/lib/module/components/StickerPicker/StickerSectionList.js.map +1 -0
- package/lib/module/components/StickerPicker/constants.js +14 -0
- package/lib/module/components/StickerPicker/constants.js.map +1 -0
- package/lib/module/components/StickerPicker/index.js +134 -0
- package/lib/module/components/StickerPicker/index.js.map +1 -0
- package/lib/module/components/messages/stickerMessage/index.js +28 -0
- package/lib/module/components/messages/stickerMessage/index.js.map +1 -0
- package/lib/module/config/api-endpoints.js +4 -1
- package/lib/module/config/api-endpoints.js.map +1 -1
- package/lib/module/hooks/conversation/useGetConversationDetail.js +15 -0
- package/lib/module/hooks/conversation/useGetConversationDetail.js.map +1 -1
- package/lib/module/hooks/flows/useGetConversationFlowMainMenu.js +1 -1
- package/lib/module/hooks/flows/useGetConversationFlowMainMenu.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +45 -18
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/query-keys.js +7 -0
- package/lib/module/hooks/query-keys.js.map +1 -1
- package/lib/module/hooks/stickers/useFetchStickerByCategory.js +12 -0
- package/lib/module/hooks/stickers/useFetchStickerByCategory.js.map +1 -0
- package/lib/module/hooks/stickers/useStickerCategories.js +14 -0
- package/lib/module/hooks/stickers/useStickerCategories.js.map +1 -0
- package/lib/module/hooks/stickers/useStickerHistory.js +16 -0
- package/lib/module/hooks/stickers/useStickerHistory.js.map +1 -0
- package/lib/module/hooks/useChatCompose.js +1 -18
- package/lib/module/hooks/useChatCompose.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatComposer.js +64 -16
- package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetail.js +6 -20
- package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
- package/lib/module/screens/chat-detail/hooks/useChatComposerAnimation.js +15 -4
- package/lib/module/screens/chat-detail/hooks/useChatComposerAnimation.js.map +1 -1
- package/lib/module/screens/chat-detail/hooks/useChatComposerState.js +3 -0
- package/lib/module/screens/chat-detail/hooks/useChatComposerState.js.map +1 -1
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js +5 -6
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js.map +1 -1
- package/lib/module/services/attachmentOrchestrator.js +1 -1
- package/lib/module/services/attachmentOrchestrator.js.map +1 -1
- package/lib/module/services/endpoints.js +4 -1
- package/lib/module/services/endpoints.js.map +1 -1
- package/lib/module/store/conversation.js +1 -20
- package/lib/module/store/conversation.js.map +1 -1
- package/lib/module/translation/resources/i18n.js +3 -1
- package/lib/module/translation/resources/i18n.js.map +1 -1
- package/lib/module/types/chat.js +6 -0
- package/lib/module/types/chat.js.map +1 -1
- package/lib/module/types/sticker.js +2 -0
- package/lib/module/types/sticker.js.map +1 -0
- package/lib/module/utils/conversation.js +1 -24
- package/lib/module/utils/conversation.js.map +1 -1
- package/lib/module/utils/messageUtils.js +2 -0
- package/lib/module/utils/messageUtils.js.map +1 -1
- package/lib/typescript/src/components/StickerPicker/StickerCategoryTabs.d.ts +9 -0
- package/lib/typescript/src/components/StickerPicker/StickerCategoryTabs.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/StickerPickerPlaceholder.d.ts +2 -0
- package/lib/typescript/src/components/StickerPicker/StickerPickerPlaceholder.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/StickerPickerRowItem.d.ts +8 -0
- package/lib/typescript/src/components/StickerPicker/StickerPickerRowItem.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/StickerSectionList.d.ts +15 -0
- package/lib/typescript/src/components/StickerPicker/StickerSectionList.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/constants.d.ts +11 -0
- package/lib/typescript/src/components/StickerPicker/constants.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/index.d.ts +7 -0
- package/lib/typescript/src/components/StickerPicker/index.d.ts.map +1 -0
- package/lib/typescript/src/components/messages/stickerMessage/index.d.ts +3 -0
- package/lib/typescript/src/components/messages/stickerMessage/index.d.ts.map +1 -0
- package/lib/typescript/src/config/api-endpoints.d.ts +3 -0
- package/lib/typescript/src/config/api-endpoints.d.ts.map +1 -1
- package/lib/typescript/src/hooks/conversation/useGetConversationDetail.d.ts +2 -1
- package/lib/typescript/src/hooks/conversation/useGetConversationDetail.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts +5 -3
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/query-keys.d.ts +7 -0
- package/lib/typescript/src/hooks/query-keys.d.ts.map +1 -1
- package/lib/typescript/src/hooks/stickers/useFetchStickerByCategory.d.ts +3 -0
- package/lib/typescript/src/hooks/stickers/useFetchStickerByCategory.d.ts.map +1 -0
- package/lib/typescript/src/hooks/stickers/useStickerCategories.d.ts +3 -0
- package/lib/typescript/src/hooks/stickers/useStickerCategories.d.ts.map +1 -0
- package/lib/typescript/src/hooks/stickers/useStickerHistory.d.ts +3 -0
- package/lib/typescript/src/hooks/stickers/useStickerHistory.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useChatCompose.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts +2 -2
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useChatComposerAnimation.d.ts +2 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useChatComposerAnimation.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useChatComposerState.d.ts +3 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useChatComposerState.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts.map +1 -1
- package/lib/typescript/src/services/endpoints.d.ts +4 -1
- package/lib/typescript/src/services/endpoints.d.ts.map +1 -1
- package/lib/typescript/src/store/conversation.d.ts +0 -3
- package/lib/typescript/src/store/conversation.d.ts.map +1 -1
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
- package/lib/typescript/src/types/chat.d.ts +12 -19
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/types/sticker.d.ts +21 -0
- package/lib/typescript/src/types/sticker.d.ts.map +1 -0
- package/lib/typescript/src/utils/conversation.d.ts +1 -2
- package/lib/typescript/src/utils/conversation.d.ts.map +1 -1
- package/lib/typescript/src/utils/messageUtils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/StickerPicker/StickerCategoryTabs.tsx +103 -0
- package/src/components/StickerPicker/StickerPickerPlaceholder.tsx +16 -0
- package/src/components/StickerPicker/StickerPickerRowItem.tsx +43 -0
- package/src/components/StickerPicker/StickerSectionList.tsx +141 -0
- package/src/components/StickerPicker/constants.ts +20 -0
- package/src/components/StickerPicker/index.tsx +166 -0
- package/src/components/messages/stickerMessage/index.tsx +26 -0
- package/src/config/api-endpoints.ts +6 -0
- package/src/hooks/conversation/useGetConversationDetail.ts +20 -1
- package/src/hooks/flows/useGetConversationFlowMainMenu.ts +1 -1
- package/src/hooks/message/useSendMessage.ts +49 -27
- package/src/hooks/query-keys.ts +10 -0
- package/src/hooks/stickers/useFetchStickerByCategory.ts +15 -0
- package/src/hooks/stickers/useStickerCategories.ts +17 -0
- package/src/hooks/stickers/useStickerHistory.ts +19 -0
- package/src/hooks/useChatCompose.ts +0 -19
- package/src/screens/chat-detail/ChatComposer.tsx +106 -19
- package/src/screens/chat-detail/ChatDetail.tsx +5 -19
- package/src/screens/chat-detail/hooks/useChatComposerAnimation.ts +21 -5
- package/src/screens/chat-detail/hooks/useChatComposerState.ts +7 -0
- package/src/screens/chat-detail/legend/LegendChatMessage.tsx +4 -5
- package/src/services/attachmentOrchestrator.ts +1 -1
- package/src/services/endpoints.ts +6 -1
- package/src/store/conversation.ts +0 -24
- package/src/translation/resources/i18n.ts +3 -0
- package/src/types/chat.ts +13 -21
- package/src/types/sticker.ts +23 -0
- package/src/utils/conversation.ts +0 -28
- package/src/utils/messageUtils.ts +3 -0
|
@@ -16,10 +16,7 @@ import {
|
|
|
16
16
|
type IMessageItemEx,
|
|
17
17
|
} from '../../types/chat';
|
|
18
18
|
import { useChatContext, useChatDetailContext } from '../../context';
|
|
19
|
-
import {
|
|
20
|
-
generateContentBasedOnMessageType,
|
|
21
|
-
getBotId,
|
|
22
|
-
} from '../../utils/conversation';
|
|
19
|
+
import { getBotId } from '../../utils/conversation';
|
|
23
20
|
import { markMessageRevoked, useMessageStore } from '../../store/message';
|
|
24
21
|
import uuid from 'react-native-uuid';
|
|
25
22
|
|
|
@@ -27,34 +24,36 @@ import type { IUrlMetadata } from '../../types/common';
|
|
|
27
24
|
import type { IRunConversationFlowPayload } from '../../types/flows';
|
|
28
25
|
import { DeviceEventEmitter } from 'react-native';
|
|
29
26
|
import { ChatEvent } from '../../types/events';
|
|
27
|
+
import type { StickerItem } from '../../types/sticker';
|
|
28
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
29
|
+
import { stickerQueryKeys } from '../query-keys';
|
|
30
|
+
import { getMessagePreview } from '../../utils/messageUtils';
|
|
30
31
|
|
|
31
32
|
const buildSendParams = (
|
|
32
33
|
message: MessageItem,
|
|
33
34
|
recvID: string,
|
|
34
35
|
groupID: string,
|
|
35
|
-
extendMessageInfo: IMessageItemEx
|
|
36
|
-
plainText: string
|
|
36
|
+
extendMessageInfo: IMessageItemEx
|
|
37
37
|
) => ({
|
|
38
38
|
groupID,
|
|
39
39
|
recvID,
|
|
40
40
|
message: { ...message, ex: JSON.stringify(extendMessageInfo) || '{}' },
|
|
41
|
-
offlinePushInfo: generateOfflinePushInfo(message
|
|
41
|
+
offlinePushInfo: generateOfflinePushInfo(message),
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
export const useSendMessage = () => {
|
|
45
45
|
const applicationType = useChatContext().applicationType;
|
|
46
46
|
const pushNewMessage = useMessageStore((state) => state.pushNewMessage);
|
|
47
47
|
const updateOneMessage = useMessageStore((state) => state.updateOneMessage);
|
|
48
|
-
const deleteOneMessage = useMessageStore((state) => state.deleteOneMessage);
|
|
49
48
|
const { quotedMessage, setQuotedMessage } = useChatDetailContext();
|
|
49
|
+
const queryClient = useQueryClient();
|
|
50
50
|
|
|
51
51
|
const dispatchSend = useCallback(
|
|
52
52
|
async (
|
|
53
53
|
message: MessageItem,
|
|
54
54
|
recvID: string,
|
|
55
55
|
groupID: string,
|
|
56
|
-
extendMessageInfo: IMessageItemEx
|
|
57
|
-
plainText: string
|
|
56
|
+
extendMessageInfo: IMessageItemEx
|
|
58
57
|
) => {
|
|
59
58
|
pushNewMessage({ ...message, status: MessageStatus.Sending });
|
|
60
59
|
|
|
@@ -63,12 +62,10 @@ export const useSendMessage = () => {
|
|
|
63
62
|
message,
|
|
64
63
|
recvID,
|
|
65
64
|
groupID,
|
|
66
|
-
extendMessageInfo
|
|
67
|
-
plainText
|
|
65
|
+
extendMessageInfo
|
|
68
66
|
);
|
|
69
67
|
// console.log('[useSendMessage] dispatchSend params', sendParams);
|
|
70
68
|
const sent = await OpenIMSDK.sendMessage(sendParams);
|
|
71
|
-
deleteOneMessage(message.clientMsgID);
|
|
72
69
|
pushNewMessage(sent);
|
|
73
70
|
} catch {
|
|
74
71
|
updateOneMessage({ ...message, status: MessageStatus.Failed });
|
|
@@ -76,7 +73,7 @@ export const useSendMessage = () => {
|
|
|
76
73
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
77
74
|
DeviceEventEmitter.emit(ChatEvent.ScrollToBottom);
|
|
78
75
|
},
|
|
79
|
-
[pushNewMessage, updateOneMessage
|
|
76
|
+
[pushNewMessage, updateOneMessage]
|
|
80
77
|
);
|
|
81
78
|
|
|
82
79
|
const sendMessage = useCallback(
|
|
@@ -85,11 +82,13 @@ export const useSendMessage = () => {
|
|
|
85
82
|
urlMetadata,
|
|
86
83
|
flow,
|
|
87
84
|
customMessage,
|
|
85
|
+
sticker,
|
|
88
86
|
}: {
|
|
89
87
|
plainText?: string;
|
|
90
88
|
urlMetadata?: IUrlMetadata;
|
|
91
89
|
flow?: IRunConversationFlowPayload;
|
|
92
90
|
customMessage?: CustomMessagePayload;
|
|
91
|
+
sticker?: StickerItem;
|
|
93
92
|
}) => {
|
|
94
93
|
const currentConversation = useConversationStore
|
|
95
94
|
.getState()
|
|
@@ -143,23 +142,39 @@ export const useSendMessage = () => {
|
|
|
143
142
|
messageList.push(message);
|
|
144
143
|
}
|
|
145
144
|
|
|
145
|
+
//sticker msg
|
|
146
|
+
if (!!sticker && !!sticker?.file?.fullUrl) {
|
|
147
|
+
let stickerMessage = await createStickerMessage(sticker?.file?.fullUrl);
|
|
148
|
+
if (!stickerMessage) return;
|
|
149
|
+
messageList.push(stickerMessage);
|
|
150
|
+
}
|
|
151
|
+
|
|
146
152
|
for (const message of messageList) {
|
|
147
153
|
const extendMessageInfo: IMessageItemEx = {
|
|
148
154
|
applicationType,
|
|
149
155
|
urlMetadata,
|
|
150
156
|
flow,
|
|
157
|
+
stickerId: sticker?.id,
|
|
151
158
|
};
|
|
152
159
|
|
|
153
160
|
await dispatchSend(
|
|
154
161
|
message,
|
|
155
162
|
recvID || '',
|
|
156
163
|
groupID || '',
|
|
157
|
-
extendMessageInfo
|
|
158
|
-
plainText || ''
|
|
164
|
+
extendMessageInfo
|
|
159
165
|
);
|
|
160
166
|
}
|
|
167
|
+
if (!!sticker && !!sticker?.id) {
|
|
168
|
+
queryClient.invalidateQueries({ queryKey: stickerQueryKeys.recent() });
|
|
169
|
+
}
|
|
161
170
|
},
|
|
162
|
-
[
|
|
171
|
+
[
|
|
172
|
+
applicationType,
|
|
173
|
+
dispatchSend,
|
|
174
|
+
quotedMessage,
|
|
175
|
+
setQuotedMessage,
|
|
176
|
+
queryClient,
|
|
177
|
+
]
|
|
163
178
|
);
|
|
164
179
|
|
|
165
180
|
const retryMessage = useCallback(
|
|
@@ -185,7 +200,7 @@ export const useSendMessage = () => {
|
|
|
185
200
|
recvID: recvID || '',
|
|
186
201
|
groupID: groupID || '',
|
|
187
202
|
message,
|
|
188
|
-
offlinePushInfo: generateOfflinePushInfo(message
|
|
203
|
+
offlinePushInfo: generateOfflinePushInfo(message),
|
|
189
204
|
};
|
|
190
205
|
|
|
191
206
|
try {
|
|
@@ -196,11 +211,9 @@ export const useSendMessage = () => {
|
|
|
196
211
|
message,
|
|
197
212
|
recvID || '',
|
|
198
213
|
groupID || '',
|
|
199
|
-
JSON.parse(message.ex || '{}') as IMessageItemEx
|
|
200
|
-
''
|
|
214
|
+
JSON.parse(message.ex || '{}') as IMessageItemEx
|
|
201
215
|
)
|
|
202
216
|
);
|
|
203
|
-
deleteOneMessage(message.clientMsgID);
|
|
204
217
|
pushNewMessage(sent);
|
|
205
218
|
} catch {
|
|
206
219
|
updateOneMessage({ ...message, status: MessageStatus.Failed });
|
|
@@ -208,7 +221,7 @@ export const useSendMessage = () => {
|
|
|
208
221
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
209
222
|
DeviceEventEmitter.emit(ChatEvent.ScrollToBottom);
|
|
210
223
|
},
|
|
211
|
-
[pushNewMessage, updateOneMessage
|
|
224
|
+
[pushNewMessage, updateOneMessage]
|
|
212
225
|
);
|
|
213
226
|
|
|
214
227
|
const revokeMessage = useCallback(async (message: MessageItem) => {
|
|
@@ -232,16 +245,13 @@ export const useSendMessage = () => {
|
|
|
232
245
|
};
|
|
233
246
|
};
|
|
234
247
|
|
|
235
|
-
export const generateOfflinePushInfo = (
|
|
236
|
-
contentType: MessageType,
|
|
237
|
-
plainText: string
|
|
238
|
-
) => {
|
|
248
|
+
export const generateOfflinePushInfo = (message: MessageItem) => {
|
|
239
249
|
const conversationData = useConversationStore
|
|
240
250
|
?.getState?.()
|
|
241
251
|
?.getCurrentConversation();
|
|
242
252
|
const operatorUserID = useUserStore.getState().user?.userID || '';
|
|
243
253
|
const title = conversationData?.showName || 'Droppii';
|
|
244
|
-
const desc =
|
|
254
|
+
const desc = getMessagePreview(message);
|
|
245
255
|
return {
|
|
246
256
|
title,
|
|
247
257
|
desc,
|
|
@@ -310,3 +320,15 @@ export const createQuotedMessage = async (params: QuoteMsgParams) => {
|
|
|
310
320
|
});
|
|
311
321
|
return quotedMessage;
|
|
312
322
|
};
|
|
323
|
+
|
|
324
|
+
export const createStickerMessage = async (sticker: string) => {
|
|
325
|
+
let stickerMessage = await OpenIMSDK.createStickerMessage(sticker, uuid.v4())
|
|
326
|
+
.then((data) => {
|
|
327
|
+
return data;
|
|
328
|
+
})
|
|
329
|
+
.catch(({ errCode, errMsg }) => {
|
|
330
|
+
console.error('createStickerMessage', errCode, errMsg);
|
|
331
|
+
return null;
|
|
332
|
+
});
|
|
333
|
+
return stickerMessage;
|
|
334
|
+
};
|
package/src/hooks/query-keys.ts
CHANGED
|
@@ -12,6 +12,8 @@ export const conversationQueryKeys = {
|
|
|
12
12
|
detail: (conversationId: string) =>
|
|
13
13
|
[...conversationQueryKeys.details(), conversationId] as const,
|
|
14
14
|
getStatusBot: (botId: string) => ['getStatusBot', botId] as const,
|
|
15
|
+
conversationTarget: (conversationId: string) =>
|
|
16
|
+
['conversationTarget', conversationId] as const,
|
|
15
17
|
flow: (conversationId: string) => ['conversationFlow', conversationId],
|
|
16
18
|
flowMainMenu: (conversationId: string) => [
|
|
17
19
|
'conversationFlowMainMenu',
|
|
@@ -34,3 +36,11 @@ export const usersQueryKeys = {
|
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
export type ConversationQueryKeys = typeof conversationQueryKeys;
|
|
39
|
+
|
|
40
|
+
export const stickerQueryKeys = {
|
|
41
|
+
all: ['stickers'] as const,
|
|
42
|
+
categories: () => [...stickerQueryKeys.all, 'categories'] as const,
|
|
43
|
+
byCategory: (categoryId: string) =>
|
|
44
|
+
[...stickerQueryKeys.all, 'category', categoryId] as const,
|
|
45
|
+
recent: () => [...stickerQueryKeys.all, 'recent'] as const,
|
|
46
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useMutation } from '@tanstack/react-query';
|
|
2
|
+
import { apiInstance } from '../../services/apis';
|
|
3
|
+
import { ENDPOINTS } from '../../services/endpoints';
|
|
4
|
+
import type { BaseResponse } from '../../types/auth';
|
|
5
|
+
import type { StickerItem } from '../../types/sticker';
|
|
6
|
+
|
|
7
|
+
export const useFetchStickerByCategory = () =>
|
|
8
|
+
useMutation({
|
|
9
|
+
mutationFn: async (categoryId: string) => {
|
|
10
|
+
const res = await apiInstance?.get<BaseResponse<StickerItem[]>>(
|
|
11
|
+
ENDPOINTS.chatService.stickersByCategoryId(categoryId)
|
|
12
|
+
);
|
|
13
|
+
return res?.data?.data || [];
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { apiInstance } from '../../services/apis';
|
|
3
|
+
import { stickerQueryKeys } from '../query-keys';
|
|
4
|
+
import { ENDPOINTS } from '../../services/endpoints';
|
|
5
|
+
import type { BaseResponse } from '../../types/auth';
|
|
6
|
+
import type { StickerCategory } from '../../types/sticker';
|
|
7
|
+
|
|
8
|
+
export const useStickerCategories = () =>
|
|
9
|
+
useQuery({
|
|
10
|
+
queryKey: stickerQueryKeys.categories(),
|
|
11
|
+
queryFn: async () => {
|
|
12
|
+
const res = await apiInstance?.get<BaseResponse<StickerCategory[]>>(
|
|
13
|
+
ENDPOINTS.chatService.stickerCategories()
|
|
14
|
+
);
|
|
15
|
+
return res?.data?.data || [];
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { apiInstance } from '../../services/apis';
|
|
3
|
+
import { stickerQueryKeys } from '../query-keys';
|
|
4
|
+
import { ENDPOINTS } from '../../services/endpoints';
|
|
5
|
+
import type { BaseResponse } from '../../types/auth';
|
|
6
|
+
import type { StickerItem } from '../../types/sticker';
|
|
7
|
+
|
|
8
|
+
export const useStickerHistory = () =>
|
|
9
|
+
useQuery({
|
|
10
|
+
queryKey: stickerQueryKeys.recent(),
|
|
11
|
+
queryFn: async () => {
|
|
12
|
+
const res = await apiInstance?.get<BaseResponse<StickerItem[]>>(
|
|
13
|
+
ENDPOINTS.chatService.stickerHistory()
|
|
14
|
+
);
|
|
15
|
+
return res?.data?.data || [];
|
|
16
|
+
},
|
|
17
|
+
staleTime: 0,
|
|
18
|
+
gcTime: 0,
|
|
19
|
+
});
|
|
@@ -13,9 +13,6 @@ import {
|
|
|
13
13
|
generateAndUploadVideoThumbnails,
|
|
14
14
|
type VideoWithUploadStatus,
|
|
15
15
|
} from '../utils/videoThumbnailUpload';
|
|
16
|
-
import { useConversationStore } from '../store';
|
|
17
|
-
import { DChatCategory } from '../types/chat';
|
|
18
|
-
import { useChatContext } from '../context';
|
|
19
16
|
|
|
20
17
|
export function useChatCompose() {
|
|
21
18
|
const [text, setText] = useState('');
|
|
@@ -25,7 +22,6 @@ export function useChatCompose() {
|
|
|
25
22
|
const linkPreview = useLinkPreview(text);
|
|
26
23
|
const { send: sendAttachments } = useSendAttachment();
|
|
27
24
|
const { sendMessage } = useSendMessage();
|
|
28
|
-
const { applicationType } = useChatContext();
|
|
29
25
|
|
|
30
26
|
const isUploading = useMemo(
|
|
31
27
|
() =>
|
|
@@ -53,20 +49,6 @@ export function useChatCompose() {
|
|
|
53
49
|
const { selectedImages, clearAllImages } = imageAttachment;
|
|
54
50
|
const { selectedFiles, clearAllFiles } = fileAttachment;
|
|
55
51
|
const urlMeta = linkPreview.isVisible ? linkPreview.metadata : undefined;
|
|
56
|
-
const currentConversationId =
|
|
57
|
-
useConversationStore.getState().currentConversationId;
|
|
58
|
-
const targetUserId = useConversationStore.getState().currentUserId;
|
|
59
|
-
const isCreatingConversation =
|
|
60
|
-
useConversationStore.getState().isCreatingConversation;
|
|
61
|
-
|
|
62
|
-
if (targetUserId && !currentConversationId && !isCreatingConversation) {
|
|
63
|
-
await useConversationStore.getState().createConversation({
|
|
64
|
-
chatType: 'SINGLE',
|
|
65
|
-
chatCategory: DChatCategory.BIZ_BIZ,
|
|
66
|
-
applicationType,
|
|
67
|
-
peerUserId: targetUserId,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
52
|
|
|
71
53
|
// --- Attachments ---
|
|
72
54
|
if (selectedImages.length > 0 || selectedFiles.length > 0) {
|
|
@@ -179,7 +161,6 @@ export function useChatCompose() {
|
|
|
179
161
|
sendAttachments,
|
|
180
162
|
sendMessage,
|
|
181
163
|
text,
|
|
182
|
-
applicationType,
|
|
183
164
|
]);
|
|
184
165
|
|
|
185
166
|
return {
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type RefObject,
|
|
9
9
|
} from 'react';
|
|
10
10
|
import {
|
|
11
|
+
Keyboard,
|
|
11
12
|
Platform,
|
|
12
13
|
StyleSheet,
|
|
13
14
|
type LayoutChangeEvent,
|
|
@@ -15,7 +16,10 @@ import {
|
|
|
15
16
|
} from 'react-native';
|
|
16
17
|
import { debounce } from 'lodash';
|
|
17
18
|
import Reanimated from 'react-native-reanimated';
|
|
18
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
KeyboardStickyView,
|
|
21
|
+
useKeyboardState,
|
|
22
|
+
} from 'react-native-keyboard-controller';
|
|
19
23
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
20
24
|
import { KContainer, KColors, KImage, KButton, KLabel } from '@droppii/libs';
|
|
21
25
|
|
|
@@ -30,12 +34,15 @@ import { ChatAttachmentPanel } from './ChatAttachmentPanel';
|
|
|
30
34
|
import { ChatLinkPreview } from './ChatLinkPreview';
|
|
31
35
|
import { ChatMessageInput } from './components/ChatMessageInput';
|
|
32
36
|
import { AttachmentPreview } from '../../components/AttachmentPreview';
|
|
37
|
+
import { StickerPicker } from '../../components/StickerPicker';
|
|
38
|
+
import type { StickerItem } from '../../types/sticker';
|
|
33
39
|
|
|
34
40
|
import {
|
|
35
41
|
DEFAULT_QUICK_ACTIONS,
|
|
36
42
|
getAttachmentPanelHeight,
|
|
37
43
|
DEFAULT_PANNEL_ACTIONS,
|
|
38
44
|
} from './constants';
|
|
45
|
+
import { STICKER_PICKER_HEIGHT } from '../../components/StickerPicker/constants';
|
|
39
46
|
import { DChatPannelActionItemType, type DChatPannelAction } from './types';
|
|
40
47
|
import { useChatComposerState } from './hooks/useChatComposerState';
|
|
41
48
|
import { useChatComposerAnimation } from './hooks/useChatComposerAnimation';
|
|
@@ -47,11 +54,12 @@ import { useAttachmentMapping } from './hooks/useAttachmentMapping';
|
|
|
47
54
|
import type { AttachmentType } from '../../types/attachment';
|
|
48
55
|
import { useChatCompose } from '../../hooks/useChatCompose';
|
|
49
56
|
import { ChatCurrentQuotedMessage } from './ChatCurrentQuotedMessage';
|
|
57
|
+
import { useSendMessage } from '../../hooks/message/useSendMessage';
|
|
50
58
|
|
|
51
59
|
interface ChatComposerInternalProps {
|
|
52
60
|
isEmptyMessage?: boolean;
|
|
53
61
|
pannelActions?: DChatPannelAction[];
|
|
54
|
-
|
|
62
|
+
isComposeDisabled?: boolean;
|
|
55
63
|
composerRef?: RefObject<View | null>;
|
|
56
64
|
onComposerLayout?: (event: LayoutChangeEvent) => void;
|
|
57
65
|
}
|
|
@@ -60,18 +68,22 @@ export const ChatComposer = memo(
|
|
|
60
68
|
({
|
|
61
69
|
isEmptyMessage = false,
|
|
62
70
|
pannelActions,
|
|
63
|
-
|
|
71
|
+
isComposeDisabled = false,
|
|
64
72
|
composerRef,
|
|
65
73
|
onComposerLayout,
|
|
66
74
|
}: ChatComposerInternalProps) => {
|
|
67
75
|
const insets = useSafeAreaInsets();
|
|
76
|
+
const isDisableCompose = isComposeDisabled;
|
|
77
|
+
const isKeyboardVisible = useKeyboardState((state) => state.isVisible);
|
|
68
78
|
|
|
69
79
|
const { isBotConversation, conversationFlow } = useChatDetailContext();
|
|
70
80
|
const { mutate: runFlow, isPending } = useRunFlow();
|
|
71
|
-
|
|
81
|
+
const { sendMessage } = useSendMessage();
|
|
72
82
|
const compose = useChatCompose();
|
|
73
83
|
|
|
74
84
|
const {
|
|
85
|
+
activePanelType,
|
|
86
|
+
setActivePanelType,
|
|
75
87
|
isAttachmentOpen,
|
|
76
88
|
setIsAttachmentOpen,
|
|
77
89
|
isInputFocused,
|
|
@@ -81,16 +93,25 @@ export const ChatComposer = memo(
|
|
|
81
93
|
inputRef,
|
|
82
94
|
} = useChatComposerState(compose.text);
|
|
83
95
|
|
|
84
|
-
const
|
|
96
|
+
const attachmentPanelHeight = useMemo(
|
|
85
97
|
() => getAttachmentPanelHeight(DEFAULT_PANNEL_ACTIONS.length),
|
|
86
98
|
[]
|
|
87
99
|
);
|
|
88
100
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
const panelHeight =
|
|
102
|
+
activePanelType === 'sticker'
|
|
103
|
+
? STICKER_PICKER_HEIGHT
|
|
104
|
+
: attachmentPanelHeight;
|
|
105
|
+
|
|
106
|
+
const {
|
|
107
|
+
accessorySlotStyle,
|
|
108
|
+
toggleAttachmentVisibility,
|
|
109
|
+
openWithHeight,
|
|
110
|
+
closeAttachment,
|
|
111
|
+
} = useChatComposerAnimation({
|
|
112
|
+
panelHeight,
|
|
113
|
+
onAttachmentOpenChange: setIsAttachmentOpen,
|
|
114
|
+
});
|
|
94
115
|
|
|
95
116
|
const handleSend = useCallback(async () => {
|
|
96
117
|
if (compose.isUploading || !compose.canSend) return;
|
|
@@ -103,8 +124,58 @@ export const ChatComposer = memo(
|
|
|
103
124
|
|
|
104
125
|
const handleInputFocus = useCallback(() => {
|
|
105
126
|
setIsInputFocused(true);
|
|
106
|
-
if (isAttachmentOpen)
|
|
107
|
-
|
|
127
|
+
if (isAttachmentOpen) {
|
|
128
|
+
// Use immediate close (no animation) when sticker panel is open to avoid
|
|
129
|
+
// layout conflict between the panel closing and keyboard appearing.
|
|
130
|
+
// Attachment panel is small enough that animation is fine (speedUp=true).
|
|
131
|
+
const immediate = activePanelType === 'sticker';
|
|
132
|
+
closeAttachment(!immediate, immediate);
|
|
133
|
+
setActivePanelType(null);
|
|
134
|
+
}
|
|
135
|
+
}, [
|
|
136
|
+
closeAttachment,
|
|
137
|
+
isAttachmentOpen,
|
|
138
|
+
activePanelType,
|
|
139
|
+
setIsInputFocused,
|
|
140
|
+
setActivePanelType,
|
|
141
|
+
]);
|
|
142
|
+
|
|
143
|
+
const handleToggleAttachment = useCallback(() => {
|
|
144
|
+
if (activePanelType === 'sticker') {
|
|
145
|
+
// switch from sticker to attachment
|
|
146
|
+
setActivePanelType('attachment');
|
|
147
|
+
openWithHeight(attachmentPanelHeight);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
setActivePanelType(isAttachmentOpen ? null : 'attachment');
|
|
151
|
+
toggleAttachmentVisibility();
|
|
152
|
+
}, [
|
|
153
|
+
activePanelType,
|
|
154
|
+
isAttachmentOpen,
|
|
155
|
+
attachmentPanelHeight,
|
|
156
|
+
openWithHeight,
|
|
157
|
+
toggleAttachmentVisibility,
|
|
158
|
+
setActivePanelType,
|
|
159
|
+
]);
|
|
160
|
+
|
|
161
|
+
const handleToggleSticker = useCallback(() => {
|
|
162
|
+
if (activePanelType === 'sticker') {
|
|
163
|
+
closeAttachment();
|
|
164
|
+
setActivePanelType(null);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (isKeyboardVisible) {
|
|
168
|
+
Keyboard.dismiss();
|
|
169
|
+
}
|
|
170
|
+
setActivePanelType('sticker');
|
|
171
|
+
openWithHeight(STICKER_PICKER_HEIGHT);
|
|
172
|
+
}, [
|
|
173
|
+
activePanelType,
|
|
174
|
+
isKeyboardVisible,
|
|
175
|
+
closeAttachment,
|
|
176
|
+
openWithHeight,
|
|
177
|
+
setActivePanelType,
|
|
178
|
+
]);
|
|
108
179
|
|
|
109
180
|
const handleInputBlur = useCallback(() => {
|
|
110
181
|
setIsInputFocused(false);
|
|
@@ -181,6 +252,13 @@ export const ChatComposer = memo(
|
|
|
181
252
|
[insets.bottom, isAttachmentOpen]
|
|
182
253
|
);
|
|
183
254
|
|
|
255
|
+
const handleStickerSelect = useCallback(
|
|
256
|
+
(sticker: StickerItem) => {
|
|
257
|
+
sendMessage({ sticker });
|
|
258
|
+
},
|
|
259
|
+
[sendMessage]
|
|
260
|
+
);
|
|
261
|
+
|
|
184
262
|
const attachments = useAttachmentMapping({
|
|
185
263
|
selectedImages: compose.selectedImages,
|
|
186
264
|
selectedFiles: compose.selectedFiles,
|
|
@@ -211,7 +289,7 @@ export const ChatComposer = memo(
|
|
|
211
289
|
/>
|
|
212
290
|
</KContainer.View>
|
|
213
291
|
<KLabel.Text typo="TextXsNormal">
|
|
214
|
-
|
|
292
|
+
{trans('chat:compose_disabled_seller_inactive')}
|
|
215
293
|
</KLabel.Text>
|
|
216
294
|
</KContainer.View>
|
|
217
295
|
);
|
|
@@ -265,15 +343,19 @@ export const ChatComposer = memo(
|
|
|
265
343
|
style={inputRowStyle}
|
|
266
344
|
>
|
|
267
345
|
<KContainer.Touchable
|
|
268
|
-
onPress={
|
|
346
|
+
onPress={handleToggleAttachment}
|
|
269
347
|
center
|
|
270
348
|
br="round"
|
|
271
349
|
>
|
|
272
350
|
<KImage.VectorIcons
|
|
273
|
-
name={
|
|
351
|
+
name={
|
|
352
|
+
activePanelType === 'attachment'
|
|
353
|
+
? 'close-circle-o'
|
|
354
|
+
: 'plus-circle-o'
|
|
355
|
+
}
|
|
274
356
|
size={24}
|
|
275
357
|
color={
|
|
276
|
-
|
|
358
|
+
activePanelType === 'attachment'
|
|
277
359
|
? KColors.palette.primary.w400
|
|
278
360
|
: KColors.palette.gray.w600
|
|
279
361
|
}
|
|
@@ -290,6 +372,7 @@ export const ChatComposer = memo(
|
|
|
290
372
|
isInputFocused={isInputFocused}
|
|
291
373
|
isMultilineInput={isMultilineInput}
|
|
292
374
|
inputRef={inputRef}
|
|
375
|
+
onEmojiPress={handleToggleSticker}
|
|
293
376
|
/>
|
|
294
377
|
|
|
295
378
|
<KContainer.Touchable
|
|
@@ -308,8 +391,7 @@ export const ChatComposer = memo(
|
|
|
308
391
|
opacity={compose.isUploading ? 0.6 : 1}
|
|
309
392
|
>
|
|
310
393
|
<KImage.VectorIcons
|
|
311
|
-
name="send"
|
|
312
|
-
provider="MaterialCommunityIcons"
|
|
394
|
+
name="send-b"
|
|
313
395
|
size={20}
|
|
314
396
|
color={KColors.white}
|
|
315
397
|
/>
|
|
@@ -335,7 +417,12 @@ export const ChatComposer = memo(
|
|
|
335
417
|
style={[styles.accessorySlot, accessorySlotStyle]}
|
|
336
418
|
pointerEvents={isAttachmentOpen ? 'auto' : 'none'}
|
|
337
419
|
>
|
|
338
|
-
|
|
420
|
+
{activePanelType === 'attachment' && (
|
|
421
|
+
<ChatAttachmentPanel actions={resolvedPannelActons} />
|
|
422
|
+
)}
|
|
423
|
+
{activePanelType === 'sticker' && (
|
|
424
|
+
<StickerPicker onSelectSticker={handleStickerSelect} />
|
|
425
|
+
)}
|
|
339
426
|
</Reanimated.View>
|
|
340
427
|
</KContainer.VisibleView>
|
|
341
428
|
</>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { memo, useCallback, useEffect,
|
|
1
|
+
import { memo, useCallback, useEffect, useRef } from 'react';
|
|
2
2
|
import { DeviceEventEmitter } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { useKeyboardScrollToEnd } from '@legendapp/list/keyboard';
|
|
@@ -26,15 +26,12 @@ import type { ChatDetailProps } from './types';
|
|
|
26
26
|
import { normalizeUrl } from '../../utils/url';
|
|
27
27
|
import { MessageToolboxOverlay } from './messageToolbox/MessageToolboxOverlay';
|
|
28
28
|
import type { MeasuredRect, MessageToolboxRef } from './messageToolbox/types';
|
|
29
|
-
import { DBotStatusValue } from '../../types/chat';
|
|
30
29
|
import {
|
|
31
30
|
useGetConversationDetail,
|
|
32
|
-
|
|
31
|
+
useGetConversationTarget,
|
|
33
32
|
} from '../../hooks/conversation/useGetConversationDetail';
|
|
34
|
-
import { PeerType } from '@droppii/openim-rn-client-sdk';
|
|
35
33
|
import type { MessageItem } from '@droppii/openim-rn-client-sdk';
|
|
36
34
|
import { useMessages } from '../../hooks/message/useMessages';
|
|
37
|
-
import { getBotId } from '../../utils/conversation';
|
|
38
35
|
import { ChatEvent } from '../../types/events';
|
|
39
36
|
import { useSetIsShowFLashMessage } from '../../context/global';
|
|
40
37
|
|
|
@@ -69,19 +66,8 @@ const ChatDetail = memo(
|
|
|
69
66
|
|
|
70
67
|
const conversation = useConversation(conversationId);
|
|
71
68
|
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
if (targetBotId) {
|
|
75
|
-
return targetBotId;
|
|
76
|
-
}
|
|
77
|
-
return getBotId(conversation);
|
|
78
|
-
}
|
|
79
|
-
return undefined;
|
|
80
|
-
}, [conversation, targetBotId]);
|
|
81
|
-
|
|
82
|
-
const { data: botInfo } = useGetStatusConversationBot(botId);
|
|
83
|
-
|
|
84
|
-
const { status: botStatus } = botInfo || {};
|
|
69
|
+
const { data: target } = useGetConversationTarget(conversationId);
|
|
70
|
+
const isComposeDisabled = !!target && !target.isActive;
|
|
85
71
|
|
|
86
72
|
const handleBackDefault = useCallback(() => {
|
|
87
73
|
navigation.goBack();
|
|
@@ -205,7 +191,7 @@ const ChatDetail = memo(
|
|
|
205
191
|
<ChatComposer
|
|
206
192
|
isEmptyMessage={messages?.length === 0}
|
|
207
193
|
pannelActions={pannelActions}
|
|
208
|
-
|
|
194
|
+
isComposeDisabled={isComposeDisabled}
|
|
209
195
|
/>
|
|
210
196
|
|
|
211
197
|
<MediaViewerModal ref={mediaViewerRef} />
|
|
@@ -19,7 +19,8 @@ interface UseChatComposerAnimationReturn {
|
|
|
19
19
|
accessorySlotStyle: any;
|
|
20
20
|
toggleAttachmentVisibility: () => void;
|
|
21
21
|
openAttachment: () => void;
|
|
22
|
-
|
|
22
|
+
openWithHeight: (height: number) => void;
|
|
23
|
+
closeAttachment: (speedUp?: boolean, immediate?: boolean) => void;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export const useChatComposerAnimation = ({
|
|
@@ -43,10 +44,14 @@ export const useChatComposerAnimation = ({
|
|
|
43
44
|
}, [attachmentHeightSV, panelHeight, onAttachmentOpenChange]);
|
|
44
45
|
|
|
45
46
|
const closeAttachment = useCallback(
|
|
46
|
-
(speedUp = false) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
47
|
+
(speedUp = false, immediate = false) => {
|
|
48
|
+
if (immediate) {
|
|
49
|
+
attachmentHeightSV.value = 0;
|
|
50
|
+
} else {
|
|
51
|
+
attachmentHeightSV.value = withTiming(0, {
|
|
52
|
+
duration: ACCESSORY_ANIMATION_MS / (speedUp ? 2 : 1),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
50
55
|
onAttachmentOpenChange(false);
|
|
51
56
|
},
|
|
52
57
|
[attachmentHeightSV, onAttachmentOpenChange]
|
|
@@ -56,6 +61,16 @@ export const useChatComposerAnimation = ({
|
|
|
56
61
|
return { height: attachmentHeightSV.value };
|
|
57
62
|
});
|
|
58
63
|
|
|
64
|
+
const openWithHeight = useCallback(
|
|
65
|
+
(height: number) => {
|
|
66
|
+
attachmentHeightSV.value = withTiming(height, {
|
|
67
|
+
duration: ACCESSORY_ANIMATION_MS,
|
|
68
|
+
});
|
|
69
|
+
onAttachmentOpenChange(true);
|
|
70
|
+
},
|
|
71
|
+
[attachmentHeightSV, onAttachmentOpenChange]
|
|
72
|
+
);
|
|
73
|
+
|
|
59
74
|
const toggleAttachmentVisibility = useCallback(() => {
|
|
60
75
|
// Use animated value as source of truth, not stale state
|
|
61
76
|
const isOpen = attachmentHeightSV.value > 0;
|
|
@@ -84,6 +99,7 @@ export const useChatComposerAnimation = ({
|
|
|
84
99
|
accessorySlotStyle,
|
|
85
100
|
toggleAttachmentVisibility,
|
|
86
101
|
openAttachment,
|
|
102
|
+
openWithHeight,
|
|
87
103
|
closeAttachment,
|
|
88
104
|
};
|
|
89
105
|
};
|