react-native-chatbot-ai 0.1.21 → 0.1.22
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/Drawer/DeleteSessionPopup.js +19 -5
- package/lib/module/components/Drawer/DeleteSessionPopup.js.map +1 -1
- package/lib/module/components/Drawer/DrawerContent.js +17 -5
- package/lib/module/components/Drawer/DrawerContent.js.map +1 -1
- package/lib/module/components/Drawer/RenameSessionPopup.js +1 -1
- package/lib/module/components/Drawer/RenameSessionPopup.js.map +1 -1
- package/lib/module/components/Drawer/SearchInput.js +10 -3
- package/lib/module/components/Drawer/SearchInput.js.map +1 -1
- package/lib/module/components/Drawer/SessionItem.js +4 -3
- package/lib/module/components/Drawer/SessionItem.js.map +1 -1
- package/lib/module/components/Drawer/SessionOptionsBottomSheet.js +10 -3
- package/lib/module/components/Drawer/SessionOptionsBottomSheet.js.map +1 -1
- package/lib/module/components/Drawer/ShareSessionPopup.js +8 -4
- package/lib/module/components/Drawer/ShareSessionPopup.js.map +1 -1
- package/lib/module/components/chat/ChatEmpty.js +15 -4
- package/lib/module/components/chat/ChatEmpty.js.map +1 -1
- package/lib/module/components/chat/ChatHeader.js +10 -4
- package/lib/module/components/chat/ChatHeader.js.map +1 -1
- package/lib/module/components/chat/ChatMessageList.js +14 -1
- package/lib/module/components/chat/ChatMessageList.js.map +1 -1
- package/lib/module/components/chat/SuggestionItem.js +2 -1
- package/lib/module/components/chat/SuggestionItem.js.map +1 -1
- package/lib/module/components/chat/footer/index.js +77 -15
- package/lib/module/components/chat/footer/index.js.map +1 -1
- package/lib/module/components/chat/footer/item/UploadImageItem.js +21 -1
- package/lib/module/components/chat/footer/item/UploadImageItem.js.map +1 -1
- package/lib/module/components/chat/index.js +7 -6
- package/lib/module/components/chat/index.js.map +1 -1
- package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js +7 -4
- package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js.map +1 -1
- package/lib/module/components/chat/item/DeeplinkItem.js +30 -2
- package/lib/module/components/chat/item/DeeplinkItem.js.map +1 -1
- package/lib/module/components/chat/item/MessageActionsBar.js +8 -2
- package/lib/module/components/chat/item/MessageActionsBar.js.map +1 -1
- package/lib/module/components/product/CardHorizontal.js +44 -7
- package/lib/module/components/product/CardHorizontal.js.map +1 -1
- package/lib/module/constants/events.js +33 -0
- package/lib/module/constants/events.js.map +1 -1
- package/lib/module/context/ChatContext.js +6 -3
- package/lib/module/context/ChatContext.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +21 -3
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/message/useStreamMessage.js +10 -3
- package/lib/module/hooks/message/useStreamMessage.js.map +1 -1
- package/lib/module/hooks/messageActions/useAudioPlayer.js +30 -4
- package/lib/module/hooks/messageActions/useAudioPlayer.js.map +1 -1
- package/lib/module/hooks/messageActions/useFeedback.js +9 -1
- package/lib/module/hooks/messageActions/useFeedback.js.map +1 -1
- package/lib/module/hooks/messageActions/useShareMessage.js +9 -1
- package/lib/module/hooks/messageActions/useShareMessage.js.map +1 -1
- package/lib/module/hooks/session/useSearchSessions.js +5 -1
- package/lib/module/hooks/session/useSearchSessions.js.map +1 -1
- package/lib/module/hooks/upload/useImageUpload.js +2 -1
- package/lib/module/hooks/upload/useImageUpload.js.map +1 -1
- package/lib/module/store/session.js +6 -3
- package/lib/module/store/session.js.map +1 -1
- package/lib/module/translation/index.js +21 -25
- package/lib/module/translation/index.js.map +1 -1
- package/lib/module/translation/resources/{vi.js → i18n.js} +5 -2
- package/lib/module/translation/resources/i18n.js.map +1 -0
- package/lib/module/types/chat.js +12 -1
- package/lib/module/types/chat.js.map +1 -1
- package/lib/typescript/src/components/Drawer/DeleteSessionPopup.d.ts +1 -1
- package/lib/typescript/src/components/Drawer/DeleteSessionPopup.d.ts.map +1 -1
- package/lib/typescript/src/components/Drawer/DrawerContent.d.ts.map +1 -1
- package/lib/typescript/src/components/Drawer/SearchInput.d.ts.map +1 -1
- package/lib/typescript/src/components/Drawer/SessionOptionsBottomSheet.d.ts +1 -1
- package/lib/typescript/src/components/Drawer/SessionOptionsBottomSheet.d.ts.map +1 -1
- package/lib/typescript/src/components/Drawer/ShareSessionPopup.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/ChatEmpty.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/ChatHeader.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/ChatMessageList.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/SuggestionItem.d.ts +3 -2
- package/lib/typescript/src/components/chat/SuggestionItem.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/footer/index.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/footer/item/UploadImageItem.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/index.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/item/ChatAIAnswerMessageItem.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/item/DeeplinkItem.d.ts +2 -1
- package/lib/typescript/src/components/chat/item/DeeplinkItem.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/item/MessageActionsBar.d.ts.map +1 -1
- package/lib/typescript/src/components/product/CardHorizontal.d.ts +3 -2
- package/lib/typescript/src/components/product/CardHorizontal.d.ts.map +1 -1
- package/lib/typescript/src/constants/events.d.ts +33 -0
- package/lib/typescript/src/constants/events.d.ts.map +1 -1
- package/lib/typescript/src/context/ChatContext.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts +2 -2
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useStreamMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/messageActions/useAudioPlayer.d.ts.map +1 -1
- package/lib/typescript/src/hooks/messageActions/useFeedback.d.ts.map +1 -1
- package/lib/typescript/src/hooks/messageActions/useShareMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/session/useSearchSessions.d.ts +1 -1
- package/lib/typescript/src/hooks/session/useSearchSessions.d.ts.map +1 -1
- package/lib/typescript/src/hooks/upload/useImageUpload.d.ts +1 -1
- package/lib/typescript/src/hooks/upload/useImageUpload.d.ts.map +1 -1
- package/lib/typescript/src/store/session.d.ts.map +1 -1
- package/lib/typescript/src/translation/index.d.ts +3 -4
- package/lib/typescript/src/translation/index.d.ts.map +1 -1
- package/lib/typescript/src/translation/resources/i18n.d.ts +5 -0
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -0
- package/lib/typescript/src/types/chat.d.ts +14 -1
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/package.json +2 -5
- package/src/components/Drawer/DeleteSessionPopup.tsx +22 -5
- package/src/components/Drawer/DrawerContent.tsx +20 -5
- package/src/components/Drawer/RenameSessionPopup.tsx +1 -1
- package/src/components/Drawer/SearchInput.tsx +11 -2
- package/src/components/Drawer/SessionItem.tsx +3 -3
- package/src/components/Drawer/SessionOptionsBottomSheet.tsx +11 -3
- package/src/components/Drawer/ShareSessionPopup.tsx +7 -4
- package/src/components/chat/ChatEmpty.tsx +15 -5
- package/src/components/chat/ChatHeader.tsx +9 -4
- package/src/components/chat/ChatMessageList.tsx +16 -1
- package/src/components/chat/SuggestionItem.tsx +4 -3
- package/src/components/chat/footer/index.tsx +95 -14
- package/src/components/chat/footer/item/UploadImageItem.tsx +21 -1
- package/src/components/chat/index.tsx +8 -11
- package/src/components/chat/item/ChatAIAnswerMessageItem.tsx +17 -6
- package/src/components/chat/item/DeeplinkItem.tsx +30 -2
- package/src/components/chat/item/MessageActionsBar.tsx +7 -1
- package/src/components/chat/item/actions/ActionButton.tsx +0 -1
- package/src/components/product/CardHorizontal.tsx +45 -10
- package/src/constants/events.ts +34 -0
- package/src/context/ChatContext.tsx +3 -0
- package/src/hooks/message/useSendMessage.ts +47 -4
- package/src/hooks/message/useStreamMessage.ts +15 -4
- package/src/hooks/messageActions/useAudioPlayer.ts +31 -2
- package/src/hooks/messageActions/useCopyToClipboard.ts +0 -1
- package/src/hooks/messageActions/useFeedback.ts +10 -1
- package/src/hooks/messageActions/useShareMessage.ts +9 -1
- package/src/hooks/session/useSearchSessions.ts +6 -1
- package/src/hooks/upload/useImageUpload.ts +6 -2
- package/src/store/session.ts +4 -2
- package/src/translation/index.ts +27 -19
- package/src/translation/resources/{vi.ts → i18n.ts} +5 -1
- package/src/types/chat.ts +19 -1
- package/src/utils/textCleaner.ts +0 -1
- package/lib/module/translation/resources/vi.js.map +0 -1
- package/lib/typescript/src/translation/resources/vi.d.ts +0 -31
- package/lib/typescript/src/translation/resources/vi.d.ts.map +0 -1
|
@@ -5,7 +5,9 @@ import ChatEmpty from './ChatEmpty';
|
|
|
5
5
|
import ChatItem from './item';
|
|
6
6
|
import { KSpacingValue, KColors, KImage, KContainer } from '@droppii/libs';
|
|
7
7
|
import type { IMessageItem } from '../../types';
|
|
8
|
-
import { events } from '../../constants/events';
|
|
8
|
+
import { events, GAEvents } from '../../constants/events';
|
|
9
|
+
import { useChatContext } from '../../context/ChatContext';
|
|
10
|
+
import useSessionStore from '../../store/session';
|
|
9
11
|
|
|
10
12
|
const FlatListComponent = FlatList as unknown as ComponentType<any>;
|
|
11
13
|
|
|
@@ -14,6 +16,9 @@ interface IChatMessageListProps {
|
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
const ChatMessageList = ({ messageList = [] }: IChatMessageListProps) => {
|
|
19
|
+
const logGA = useChatContext().logGA;
|
|
20
|
+
const sessionId = useSessionStore((state) => state.sessionId);
|
|
21
|
+
|
|
17
22
|
const flatListRef = useRef<any>(null);
|
|
18
23
|
const scrollOffsetRef = useRef(0);
|
|
19
24
|
const [showScrollToBottom, setShowScrollToBottom] = useState(false);
|
|
@@ -53,6 +58,16 @@ const ChatMessageList = ({ messageList = [] }: IChatMessageListProps) => {
|
|
|
53
58
|
};
|
|
54
59
|
}, []);
|
|
55
60
|
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!sessionId) {
|
|
63
|
+
logGA(GAEvents.newChatPageView);
|
|
64
|
+
} else {
|
|
65
|
+
logGA(GAEvents.chatDetailPageView, {
|
|
66
|
+
conversation_id: sessionId,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}, [sessionId, logGA]);
|
|
70
|
+
|
|
56
71
|
return (
|
|
57
72
|
<View style={{ flex: 1 }}>
|
|
58
73
|
<FlatListComponent
|
|
@@ -13,10 +13,11 @@ import { StyleSheet } from 'react-native';
|
|
|
13
13
|
|
|
14
14
|
interface SuggestionItemProps {
|
|
15
15
|
item: ISuggestionItem;
|
|
16
|
-
|
|
16
|
+
index: number;
|
|
17
|
+
onPressItem: (item: ISuggestionItem, index: number) => void;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
const SuggestionItem = ({ item, onPressItem }: SuggestionItemProps) => {
|
|
20
|
+
const SuggestionItem = ({ item, index, onPressItem }: SuggestionItemProps) => {
|
|
20
21
|
const icon = useMemo(() => {
|
|
21
22
|
switch (item.category) {
|
|
22
23
|
case SuggestionCategory.product:
|
|
@@ -81,7 +82,7 @@ const SuggestionItem = ({ item, onPressItem }: SuggestionItemProps) => {
|
|
|
81
82
|
return (
|
|
82
83
|
<KContainer.Touchable
|
|
83
84
|
style={styles.container}
|
|
84
|
-
onPress={() => onPressItem(item)}
|
|
85
|
+
onPress={() => onPressItem(item, index)}
|
|
85
86
|
>
|
|
86
87
|
{icon}
|
|
87
88
|
<KLabel.Text flex typo="TextNmNormal">
|
|
@@ -44,9 +44,13 @@ import {
|
|
|
44
44
|
IMessageItem,
|
|
45
45
|
ISuggestionItem,
|
|
46
46
|
MessageType,
|
|
47
|
+
SendActionLogType,
|
|
47
48
|
} from '../../../types';
|
|
48
49
|
import UIUtils from '../../../utils/ui';
|
|
49
|
-
import trans from '../../../translation';
|
|
50
|
+
import { trans } from '../../../translation';
|
|
51
|
+
import { useChatContext } from '../../../context/ChatContext';
|
|
52
|
+
import { GAEvents } from '../../../constants/events';
|
|
53
|
+
import useSessionStore from '../../../store/session';
|
|
50
54
|
|
|
51
55
|
const { Popover } = renderers;
|
|
52
56
|
export interface ImageUpload extends Image {
|
|
@@ -66,13 +70,17 @@ export type UploadItem = ImageUpload | FileUpload;
|
|
|
66
70
|
const MAX_FILE_UPLOAD = 3;
|
|
67
71
|
const MAX_FILE_SIZE = 30 * 1024 * 1024;
|
|
68
72
|
const MAX_IMAGE_SIZE = 7 * 1024 * 1024;
|
|
73
|
+
const SCROLL_IDLE_TIME = 60000;
|
|
69
74
|
|
|
70
75
|
interface IChatFooterProps {
|
|
71
76
|
lastMessage?: IMessageItem;
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
80
|
+
const idleTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
81
|
+
const hasScrolledRef = useRef(false);
|
|
75
82
|
const menuRef = useRef(null);
|
|
83
|
+
const logGA = useChatContext().logGA;
|
|
76
84
|
const { onSendMessage, stopStream } = useSendMessage();
|
|
77
85
|
const [message, setMessage] = useState('');
|
|
78
86
|
const isStreaming = useStreamMessageStore((state) => state.isStreaming);
|
|
@@ -139,7 +147,12 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
139
147
|
return [...prev, ...uniqueImages];
|
|
140
148
|
});
|
|
141
149
|
}
|
|
142
|
-
|
|
150
|
+
|
|
151
|
+
logGA(GAEvents.chatDetailMultimodalTap, {
|
|
152
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
153
|
+
button: 'image',
|
|
154
|
+
});
|
|
155
|
+
}, [fileUpload, logGA]);
|
|
143
156
|
|
|
144
157
|
const onPressCameraPicker = useCallback(async () => {
|
|
145
158
|
Keyboard.dismiss();
|
|
@@ -168,7 +181,11 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
168
181
|
return [...prev, { ...newImage, uploadType: 'image' }];
|
|
169
182
|
});
|
|
170
183
|
}
|
|
171
|
-
|
|
184
|
+
logGA(GAEvents.chatDetailMultimodalTap, {
|
|
185
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
186
|
+
button: 'image',
|
|
187
|
+
});
|
|
188
|
+
}, [fileUpload, logGA]);
|
|
172
189
|
|
|
173
190
|
const menuItems = useMemo(() => {
|
|
174
191
|
return [
|
|
@@ -188,6 +205,9 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
188
205
|
const onPressSend = useCallback(() => {
|
|
189
206
|
if (isStreaming) {
|
|
190
207
|
stopStream();
|
|
208
|
+
logGA(GAEvents.chatDetailStopChatBtnTap, {
|
|
209
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
210
|
+
});
|
|
191
211
|
return;
|
|
192
212
|
}
|
|
193
213
|
const attachments: IAttachment[] = fileUpload.map((i) => ({
|
|
@@ -201,10 +221,10 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
201
221
|
: i.type) as IAttachment['mime_type'],
|
|
202
222
|
}));
|
|
203
223
|
|
|
204
|
-
onSendMessage(message?.trim(), attachments);
|
|
224
|
+
onSendMessage(message?.trim(), attachments, SendActionLogType.sendBtn);
|
|
205
225
|
setMessage('');
|
|
206
226
|
setFileUpload([]);
|
|
207
|
-
}, [message, isStreaming, onSendMessage, stopStream, fileUpload]);
|
|
227
|
+
}, [message, isStreaming, onSendMessage, stopStream, fileUpload, logGA]);
|
|
208
228
|
|
|
209
229
|
const handleUploadSuccess = useCallback((item: UploadItem) => {
|
|
210
230
|
if (item.uploadType === 'image') {
|
|
@@ -305,18 +325,37 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
305
325
|
return [...prev, { ...newDocument, uploadType: 'file' }];
|
|
306
326
|
});
|
|
307
327
|
}
|
|
308
|
-
|
|
328
|
+
logGA(GAEvents.chatDetailMultimodalTap, {
|
|
329
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
330
|
+
button: 'file',
|
|
331
|
+
});
|
|
332
|
+
}, [fileUpload, logGA]);
|
|
309
333
|
|
|
310
|
-
const onPressItemSuggestion = debounce(
|
|
311
|
-
|
|
312
|
-
|
|
334
|
+
const onPressItemSuggestion = debounce(
|
|
335
|
+
(item: ISuggestionItem, index: number) => {
|
|
336
|
+
onSendMessage(
|
|
337
|
+
item.content,
|
|
338
|
+
undefined,
|
|
339
|
+
SendActionLogType.promptSuggestion
|
|
340
|
+
);
|
|
341
|
+
logGA(GAEvents.chatDetailInConvPrmSuggTap, {
|
|
342
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
343
|
+
group_id: lastMessage?.group_suggestion_id,
|
|
344
|
+
suggestion_id: item.suggestion_id,
|
|
345
|
+
suggestion_content: item.content,
|
|
346
|
+
suggestion_cate: item.category,
|
|
347
|
+
order: index,
|
|
348
|
+
});
|
|
349
|
+
},
|
|
350
|
+
200
|
|
351
|
+
);
|
|
313
352
|
|
|
314
353
|
const renderSuggestionItem = useCallback(
|
|
315
|
-
(item: ISuggestionItem) => {
|
|
354
|
+
(item: ISuggestionItem, index: number) => {
|
|
316
355
|
return (
|
|
317
356
|
<KContainer.Touchable
|
|
318
357
|
style={styles.suggestionItem}
|
|
319
|
-
onPress={() => onPressItemSuggestion(item)}
|
|
358
|
+
onPress={() => onPressItemSuggestion(item, index)}
|
|
320
359
|
>
|
|
321
360
|
<KLabel.Text typo="TextSmNormal">{item?.content || ''}</KLabel.Text>
|
|
322
361
|
</KContainer.Touchable>
|
|
@@ -325,17 +364,58 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
325
364
|
[onPressItemSuggestion]
|
|
326
365
|
);
|
|
327
366
|
|
|
367
|
+
const clearIdleTimer = () => {
|
|
368
|
+
if (idleTimerRef.current) {
|
|
369
|
+
clearTimeout(idleTimerRef.current);
|
|
370
|
+
idleTimerRef.current = null;
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
const onUserIdleAfterScroll = useCallback(() => {
|
|
375
|
+
logGA(GAEvents.chatDetailInConvPrmSuggScroll, {
|
|
376
|
+
group_id: lastMessage?.group_suggestion_id,
|
|
377
|
+
message_id: lastMessage?.id,
|
|
378
|
+
});
|
|
379
|
+
}, [lastMessage, logGA]);
|
|
380
|
+
|
|
381
|
+
const resetIdleTimer = useCallback(() => {
|
|
382
|
+
clearIdleTimer();
|
|
383
|
+
|
|
384
|
+
hasScrolledRef.current = true;
|
|
385
|
+
|
|
386
|
+
idleTimerRef.current = setTimeout(() => {
|
|
387
|
+
if (hasScrolledRef.current) {
|
|
388
|
+
onUserIdleAfterScroll();
|
|
389
|
+
}
|
|
390
|
+
}, SCROLL_IDLE_TIME);
|
|
391
|
+
}, [onUserIdleAfterScroll]);
|
|
392
|
+
|
|
393
|
+
const handleScroll = () => {
|
|
394
|
+
resetIdleTimer();
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const handleMomentumEnd = () => {
|
|
398
|
+
resetIdleTimer();
|
|
399
|
+
};
|
|
400
|
+
|
|
328
401
|
return (
|
|
329
402
|
<KContainer.View style={styles.container}>
|
|
330
403
|
<KContainer.VisibleView visible={isShowSuggestions}>
|
|
331
404
|
<FlatListComponent
|
|
332
405
|
data={lastMessage?.suggestions || []}
|
|
333
|
-
renderItem={({
|
|
334
|
-
|
|
335
|
-
|
|
406
|
+
renderItem={({
|
|
407
|
+
item,
|
|
408
|
+
index,
|
|
409
|
+
}: {
|
|
410
|
+
item: ISuggestionItem;
|
|
411
|
+
index: number;
|
|
412
|
+
}) => renderSuggestionItem(item, index)}
|
|
336
413
|
horizontal
|
|
337
414
|
keyExtractor={(item: ISuggestionItem) => item.suggestion_id}
|
|
338
415
|
contentContainerStyle={styles.suggessionContainer}
|
|
416
|
+
onScroll={handleScroll}
|
|
417
|
+
onMomentumScrollEnd={handleMomentumEnd}
|
|
418
|
+
scrollEventThrottle={200}
|
|
339
419
|
/>
|
|
340
420
|
</KContainer.VisibleView>
|
|
341
421
|
<KContainer.VisibleView visible={fileUpload.length > 0}>
|
|
@@ -429,6 +509,7 @@ const styles = StyleSheet.create({
|
|
|
429
509
|
borderBottomWidth: 0,
|
|
430
510
|
borderTopLeftRadius: KSpacingValue['1.25rem'],
|
|
431
511
|
borderTopRightRadius: KSpacingValue['1.25rem'],
|
|
512
|
+
backgroundColor: KColors.white,
|
|
432
513
|
},
|
|
433
514
|
actions: {
|
|
434
515
|
flexDirection: 'row',
|
|
@@ -9,6 +9,9 @@ import { ImageUpload } from '..';
|
|
|
9
9
|
import { StyleSheet } from 'react-native';
|
|
10
10
|
import { useImageUpload } from '../../../../hooks/upload/useImageUpload';
|
|
11
11
|
import UIUtils from '../../../../utils/ui';
|
|
12
|
+
import { useChatContext } from '../../../../context/ChatContext';
|
|
13
|
+
import { GAEvents } from '../../../../constants/events';
|
|
14
|
+
import useSessionStore from '../../../../store/session';
|
|
12
15
|
|
|
13
16
|
interface Props {
|
|
14
17
|
item: ImageUpload;
|
|
@@ -17,9 +20,10 @@ interface Props {
|
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
const UploadImageItem = ({ item, onSuccess, onRemove }: Props) => {
|
|
23
|
+
const logGA = useChatContext().logGA;
|
|
20
24
|
const { isSuccess, isUploading, progress } = useImageUpload({
|
|
21
25
|
file: item,
|
|
22
|
-
onSuccess: (data: any) => {
|
|
26
|
+
onSuccess: (data: any, duration?: number) => {
|
|
23
27
|
const mItem = {
|
|
24
28
|
...item,
|
|
25
29
|
remoteUrl: data?.[0]?.publicUrl,
|
|
@@ -27,6 +31,14 @@ const UploadImageItem = ({ item, onSuccess, onRemove }: Props) => {
|
|
|
27
31
|
};
|
|
28
32
|
if (mItem.remoteUrl) {
|
|
29
33
|
onSuccess?.(mItem);
|
|
34
|
+
logGA(GAEvents.chatDetailMultimodalUpload, {
|
|
35
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
36
|
+
file_type: 'image',
|
|
37
|
+
duration: duration || 0,
|
|
38
|
+
size_mb: item.size / 1024 / 1024,
|
|
39
|
+
status: 'success',
|
|
40
|
+
format: item.mime,
|
|
41
|
+
});
|
|
30
42
|
}
|
|
31
43
|
},
|
|
32
44
|
onError: () => {
|
|
@@ -35,6 +47,14 @@ const UploadImageItem = ({ item, onSuccess, onRemove }: Props) => {
|
|
|
35
47
|
theme: 'danger',
|
|
36
48
|
});
|
|
37
49
|
onRemove?.(item);
|
|
50
|
+
logGA(GAEvents.chatDetailMultimodalUpload, {
|
|
51
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
52
|
+
file_type: 'image',
|
|
53
|
+
duration: 0,
|
|
54
|
+
size_mb: item.size / 1024 / 1024,
|
|
55
|
+
status: 'failed',
|
|
56
|
+
format: item.mime,
|
|
57
|
+
});
|
|
38
58
|
},
|
|
39
59
|
});
|
|
40
60
|
|
|
@@ -2,12 +2,8 @@ import { KContainer } from '@droppii/libs';
|
|
|
2
2
|
import ChatHeader from './ChatHeader';
|
|
3
3
|
import ChatMessageList from './ChatMessageList';
|
|
4
4
|
import ChatFooter from './footer';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
// Type assertion to fix TypeScript issue with React Native components
|
|
9
|
-
const KeyboardAvoidingViewComponent =
|
|
10
|
-
KeyboardAvoidingView as unknown as ComponentType<any>;
|
|
5
|
+
import { StyleSheet } from 'react-native';
|
|
6
|
+
import { KeyboardAvoidingView } from 'react-native-keyboard-controller';
|
|
11
7
|
import { useMessage } from '../../hooks/message/useMessage';
|
|
12
8
|
|
|
13
9
|
const ChatBotAI = () => {
|
|
@@ -16,15 +12,16 @@ const ChatBotAI = () => {
|
|
|
16
12
|
const lastMessage = messageState?.messages?.[0];
|
|
17
13
|
|
|
18
14
|
return (
|
|
19
|
-
<KContainer.Page>
|
|
20
|
-
<
|
|
15
|
+
<KContainer.Page flex>
|
|
16
|
+
<KeyboardAvoidingView
|
|
21
17
|
style={styles.container}
|
|
22
|
-
behavior={
|
|
18
|
+
behavior={'padding'}
|
|
19
|
+
keyboardVerticalOffset={0}
|
|
23
20
|
>
|
|
24
21
|
<ChatHeader />
|
|
25
22
|
<ChatMessageList messageList={messageState?.messages || []} />
|
|
26
23
|
<ChatFooter lastMessage={lastMessage} />
|
|
27
|
-
</
|
|
24
|
+
</KeyboardAvoidingView>
|
|
28
25
|
</KContainer.Page>
|
|
29
26
|
);
|
|
30
27
|
};
|
|
@@ -32,5 +29,5 @@ const ChatBotAI = () => {
|
|
|
32
29
|
export default ChatBotAI;
|
|
33
30
|
|
|
34
31
|
const styles = StyleSheet.create({
|
|
35
|
-
container: {
|
|
32
|
+
container: { flexGrow: 1 },
|
|
36
33
|
});
|
|
@@ -21,7 +21,7 @@ import ProductHorizontalCard from '../../product/CardHorizontal';
|
|
|
21
21
|
import ChatTable from './ChatTable';
|
|
22
22
|
import DeeplinkItem from './DeeplinkItem';
|
|
23
23
|
import { useChatContext } from '../../../context/ChatContext';
|
|
24
|
-
import trans from '../../../translation';
|
|
24
|
+
import { trans } from '../../../translation';
|
|
25
25
|
import MessageActionsBar from './MessageActionsBar';
|
|
26
26
|
import useProductsStore from '../../../store/products';
|
|
27
27
|
|
|
@@ -169,20 +169,27 @@ export function useStreamingMarkdownBlocks(text: string) {
|
|
|
169
169
|
|
|
170
170
|
class CustomRenderer extends Renderer implements RendererInterface {
|
|
171
171
|
constructor(
|
|
172
|
-
openImageViewer?: (images: { url: string }[], index: number) => void
|
|
172
|
+
openImageViewer?: (images: { url: string }[], index: number) => void,
|
|
173
|
+
messageId?: string
|
|
173
174
|
) {
|
|
174
175
|
super();
|
|
175
176
|
this.openImageViewer = openImageViewer;
|
|
177
|
+
this.messageId = messageId;
|
|
176
178
|
}
|
|
177
179
|
|
|
178
180
|
openImageViewer?: (images: { url: string }[], index: number) => void;
|
|
181
|
+
messageId?: string;
|
|
179
182
|
|
|
180
183
|
html(text: string): ReactNode {
|
|
181
184
|
const match = /^<!--\s*@component:(\w+)\(id:([\w-]+)\)\s*-->/.exec(text);
|
|
182
185
|
switch (match?.[1]) {
|
|
183
186
|
case 'product':
|
|
184
187
|
return (
|
|
185
|
-
<ProductHorizontalCard
|
|
188
|
+
<ProductHorizontalCard
|
|
189
|
+
productId={match?.[2]}
|
|
190
|
+
key={this.getKey()}
|
|
191
|
+
messageId={this.messageId}
|
|
192
|
+
/>
|
|
186
193
|
);
|
|
187
194
|
default:
|
|
188
195
|
return (
|
|
@@ -305,7 +312,11 @@ class CustomRenderer extends Renderer implements RendererInterface {
|
|
|
305
312
|
link(children: string | ReactNode[], href: string, _styles?: any): ReactNode {
|
|
306
313
|
if (href?.startsWith('/@component:deeplink')) {
|
|
307
314
|
return (
|
|
308
|
-
<DeeplinkItem
|
|
315
|
+
<DeeplinkItem
|
|
316
|
+
key={this.getKey()}
|
|
317
|
+
href={href}
|
|
318
|
+
messageId={this.messageId}
|
|
319
|
+
>
|
|
309
320
|
{children}
|
|
310
321
|
</DeeplinkItem>
|
|
311
322
|
);
|
|
@@ -402,8 +413,8 @@ const ChatAIAnswerMessageItem = ({
|
|
|
402
413
|
const products = useProductsStore((state) => state.products);
|
|
403
414
|
|
|
404
415
|
const renderer = useMemo(
|
|
405
|
-
() => new CustomRenderer(openImageViewer),
|
|
406
|
-
[openImageViewer]
|
|
416
|
+
() => new CustomRenderer(openImageViewer, item.id),
|
|
417
|
+
[openImageViewer, item.id]
|
|
407
418
|
);
|
|
408
419
|
const tokenizer = useMemo(() => new CustomTokenizer(), []);
|
|
409
420
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { KContainer, KLabel, KColors } from '@droppii/libs';
|
|
2
2
|
import { useCallback, useMemo } from 'react';
|
|
3
3
|
import { useChatContext } from '../../../context/ChatContext';
|
|
4
|
+
import { GAEvents } from '../../../constants/events';
|
|
5
|
+
import useSessionStore from '../../../store/session';
|
|
4
6
|
|
|
5
7
|
interface DeeplinkItemProps {
|
|
6
8
|
children?: React.ReactNode;
|
|
7
9
|
href?: string;
|
|
10
|
+
messageId?: string;
|
|
8
11
|
}
|
|
9
12
|
|
|
10
13
|
export function parseDeepLinkHref(href: string): Record<string, string> | null {
|
|
@@ -26,8 +29,9 @@ export function parseDeepLinkHref(href: string): Record<string, string> | null {
|
|
|
26
29
|
return result;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
const DeeplinkItem = ({ children, href }: DeeplinkItemProps) => {
|
|
32
|
+
const DeeplinkItem = ({ children, href, messageId }: DeeplinkItemProps) => {
|
|
30
33
|
const pushLinkTo = useChatContext().pushLinkTo;
|
|
34
|
+
const logGA = useChatContext().logGA;
|
|
31
35
|
const csTeamId = useChatContext().csTeamId;
|
|
32
36
|
|
|
33
37
|
const linkData = useMemo(() => {
|
|
@@ -52,11 +56,35 @@ const DeeplinkItem = ({ children, href }: DeeplinkItemProps) => {
|
|
|
52
56
|
|
|
53
57
|
const onPressDeeplink = useCallback(() => {
|
|
54
58
|
if (linkData) {
|
|
59
|
+
const data = parseDeepLinkHref(href || '');
|
|
55
60
|
pushLinkTo?.(linkData, {
|
|
56
61
|
source_from: 'chatbot',
|
|
57
62
|
});
|
|
63
|
+
if (data?.type === 'gift') {
|
|
64
|
+
logGA(GAEvents.chatDetailGiftDetailBtnTap, {
|
|
65
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
66
|
+
message_id: messageId,
|
|
67
|
+
gift_id: data?.id,
|
|
68
|
+
});
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (data?.type === 'faq') {
|
|
72
|
+
logGA(GAEvents.chatDetailFAQTap, {
|
|
73
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
74
|
+
message_id: messageId,
|
|
75
|
+
deeplink_id: data?.id,
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (data?.type === 'cx-support') {
|
|
80
|
+
logGA(GAEvents.chatDetailLivechatBtnTap, {
|
|
81
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
82
|
+
message_id: messageId,
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
58
86
|
}
|
|
59
|
-
}, [linkData, pushLinkTo]);
|
|
87
|
+
}, [linkData, pushLinkTo, logGA, href, messageId]);
|
|
60
88
|
|
|
61
89
|
return (
|
|
62
90
|
<KContainer.Touchable onPress={onPressDeeplink}>
|
|
@@ -35,6 +35,8 @@ import ActionButton from './actions/ActionButton';
|
|
|
35
35
|
const { Popover } = renderers;
|
|
36
36
|
|
|
37
37
|
import type { IMessageItem } from '../../../types/dto';
|
|
38
|
+
import { useChatContext } from '../../../context/ChatContext';
|
|
39
|
+
import { GAEvents } from '../../../constants/events';
|
|
38
40
|
|
|
39
41
|
interface MessageActionsBarProps {
|
|
40
42
|
messageId: string;
|
|
@@ -54,6 +56,7 @@ const MessageActionsBar = ({
|
|
|
54
56
|
// Refs
|
|
55
57
|
const likeMenuRef = useRef(null);
|
|
56
58
|
const dislikeMenuRef = useRef(null);
|
|
59
|
+
const logGA = useChatContext().logGA;
|
|
57
60
|
|
|
58
61
|
// Hooks
|
|
59
62
|
const { feedback, isLikeActive, isDislikeActive, selectReason } = useFeedback(
|
|
@@ -94,8 +97,11 @@ const MessageActionsBar = ({
|
|
|
94
97
|
|
|
95
98
|
// Handlers
|
|
96
99
|
const handleCopy = useCallback(() => {
|
|
100
|
+
logGA(GAEvents.chatDetailCopyBtnTap, {
|
|
101
|
+
message_id: messageId,
|
|
102
|
+
});
|
|
97
103
|
copyToClipboard(messageContent);
|
|
98
|
-
}, [messageContent, copyToClipboard]);
|
|
104
|
+
}, [messageContent, copyToClipboard, logGA, messageId]);
|
|
99
105
|
|
|
100
106
|
// Audio button states
|
|
101
107
|
const getAudioButtonProps = useCallback(() => {
|
|
@@ -11,25 +11,29 @@ import {
|
|
|
11
11
|
KPromotionTag,
|
|
12
12
|
} from '@droppii/libs';
|
|
13
13
|
import { PTManager } from '../../utils/prototype';
|
|
14
|
-
import { useMemo } from 'react';
|
|
14
|
+
import { useCallback, useMemo } from 'react';
|
|
15
15
|
import { StyleSheet } from 'react-native';
|
|
16
16
|
import useProductsStore from '../../store/products';
|
|
17
17
|
import { PRODUCT_STATUSES } from '../../types';
|
|
18
18
|
import { useChatContext } from '../../context/ChatContext';
|
|
19
19
|
import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
|
|
20
|
+
import { GAEvents } from '../../constants/events';
|
|
21
|
+
import useSessionStore from '../../store/session';
|
|
20
22
|
|
|
21
23
|
interface IProductHorizontalCardProps {
|
|
22
24
|
productId?: string;
|
|
25
|
+
messageId?: string;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
const
|
|
26
|
-
const { productId } = props;
|
|
28
|
+
const ProductHorizontalCard = (props: IProductHorizontalCardProps) => {
|
|
29
|
+
const { productId, messageId } = props;
|
|
27
30
|
const item = useProductsStore((state) =>
|
|
28
31
|
state.products.find((p) => p.id === productId)
|
|
29
32
|
);
|
|
30
33
|
const onAddToCart = useChatContext()?.onAddToCart;
|
|
31
34
|
const onBuyNow = useChatContext()?.onBuyNow;
|
|
32
35
|
const onNavigateToProduct = useChatContext()?.onNavigateToProduct;
|
|
36
|
+
const logGA = useChatContext()?.logGA;
|
|
33
37
|
|
|
34
38
|
const {
|
|
35
39
|
avgRating,
|
|
@@ -132,6 +136,40 @@ const ProducHorizontalCard = (props: IProductHorizontalCardProps) => {
|
|
|
132
136
|
return !isSuspended && !isSoldOut && typeof onBuyNow === 'function';
|
|
133
137
|
}, [isSuspended, isSoldOut, onBuyNow]);
|
|
134
138
|
|
|
139
|
+
const onPress = useCallback(() => {
|
|
140
|
+
if (!item) return;
|
|
141
|
+
onNavigateToProduct?.(item);
|
|
142
|
+
logGA(GAEvents.chatDetailProductCardTap, {
|
|
143
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
144
|
+
product_id: item.id,
|
|
145
|
+
position_in_list: -1, //TODO: fix
|
|
146
|
+
});
|
|
147
|
+
}, [onNavigateToProduct, logGA, item]);
|
|
148
|
+
|
|
149
|
+
const onPressAddToCart = useCallback(() => {
|
|
150
|
+
if (!item) return;
|
|
151
|
+
onAddToCart?.(item);
|
|
152
|
+
logGA(GAEvents.chatDetailAddToCartBtnTap, {
|
|
153
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
154
|
+
product_id: item.id,
|
|
155
|
+
position_in_list: -1, //TODO: fix
|
|
156
|
+
pdp_id: item.pdpId,
|
|
157
|
+
message_id: messageId,
|
|
158
|
+
});
|
|
159
|
+
}, [onAddToCart, logGA, item, messageId]);
|
|
160
|
+
|
|
161
|
+
const onPressBuyNow = useCallback(() => {
|
|
162
|
+
if (!item) return;
|
|
163
|
+
onBuyNow?.(item);
|
|
164
|
+
logGA(GAEvents.chatDetailBuyNowBtnTap, {
|
|
165
|
+
conversation_id: useSessionStore.getState().sessionId,
|
|
166
|
+
product_id: item.id,
|
|
167
|
+
position_in_list: -1, //TODO: fix
|
|
168
|
+
pdp_id: item.pdpId,
|
|
169
|
+
message_id: messageId,
|
|
170
|
+
});
|
|
171
|
+
}, [onBuyNow, logGA, item, messageId]);
|
|
172
|
+
|
|
135
173
|
if (!item) {
|
|
136
174
|
return (
|
|
137
175
|
<KContainer.View style={styles.container}>
|
|
@@ -170,10 +208,7 @@ const ProducHorizontalCard = (props: IProductHorizontalCardProps) => {
|
|
|
170
208
|
}
|
|
171
209
|
|
|
172
210
|
return (
|
|
173
|
-
<KContainer.Touchable
|
|
174
|
-
style={styles.container}
|
|
175
|
-
onPress={() => onNavigateToProduct?.(item)}
|
|
176
|
-
>
|
|
211
|
+
<KContainer.Touchable style={styles.container} onPress={onPress}>
|
|
177
212
|
<KContainer.View style={styles.image}>
|
|
178
213
|
<KImage.Base
|
|
179
214
|
uri={imageUrl}
|
|
@@ -294,7 +329,7 @@ const ProducHorizontalCard = (props: IProductHorizontalCardProps) => {
|
|
|
294
329
|
</KLabel.Text>
|
|
295
330
|
<KContainer.View style={styles.actionsRow}>
|
|
296
331
|
<KButton.Base
|
|
297
|
-
onPress={
|
|
332
|
+
onPress={onPressAddToCart}
|
|
298
333
|
background={KColors.palette.primary.w25}
|
|
299
334
|
tintColor={KColors.primary.normal}
|
|
300
335
|
icon={{
|
|
@@ -305,7 +340,7 @@ const ProducHorizontalCard = (props: IProductHorizontalCardProps) => {
|
|
|
305
340
|
disabled={!isEnabledAddToCart}
|
|
306
341
|
/>
|
|
307
342
|
<KButton.Solid
|
|
308
|
-
onPress={
|
|
343
|
+
onPress={onPressBuyNow}
|
|
309
344
|
size="sm"
|
|
310
345
|
label="Mua ngay"
|
|
311
346
|
kind="primary"
|
|
@@ -318,7 +353,7 @@ const ProducHorizontalCard = (props: IProductHorizontalCardProps) => {
|
|
|
318
353
|
);
|
|
319
354
|
};
|
|
320
355
|
|
|
321
|
-
export default
|
|
356
|
+
export default ProductHorizontalCard;
|
|
322
357
|
|
|
323
358
|
const styles = StyleSheet.create({
|
|
324
359
|
abs: {
|
package/src/constants/events.ts
CHANGED
|
@@ -5,3 +5,37 @@ export const events = {
|
|
|
5
5
|
expandThinkingStep: 'expand_thinking_step',
|
|
6
6
|
updateMessageError: 'update_message_error',
|
|
7
7
|
};
|
|
8
|
+
|
|
9
|
+
export const GAEvents = {
|
|
10
|
+
newChatPageView: 'NewChat_Page_View',
|
|
11
|
+
chatDetailPageView: 'ChatDetail_Page_View',
|
|
12
|
+
chatDetailSendBtnTap: 'ChatDetail_SendBtn_Tap',
|
|
13
|
+
chatDetailLikeDislikeBtnTap: 'ChatDetail_LikeDislikeBtn_Tap',
|
|
14
|
+
chatDetailCopyBtnTap: 'ChatDetail_CopyBtn_Tap',
|
|
15
|
+
chatDetailVoiceBtnTap: 'ChatDetail_VoiceBtn_Tap',
|
|
16
|
+
chatDetailExportPDFBtnTap: 'ChatDetail_ExportPDFBtn_Tap',
|
|
17
|
+
chatDetailShareMessBtnTap: 'ChatDetail_ShareMessBtn_Tap',
|
|
18
|
+
chatDetailStopChatBtnTap: 'ChatDetail_StopChatBtn_Tap',
|
|
19
|
+
chatDetailMultimodalTap: 'ChatDetail_Multimodal_Tap',
|
|
20
|
+
chatDetailMultimodalUpload: 'ChatDetail_Multimodal_Upload',
|
|
21
|
+
chatDetailMultimodalSend: 'ChatDetail_Multimodal_Send',
|
|
22
|
+
chatDetailProductCardTap: 'ChatDetail_ProductCard_Tap',
|
|
23
|
+
chatDetailAddToCartBtnTap: 'ChatDetail_AddToCartBtn_Tap',
|
|
24
|
+
chatDetailBuyNowBtnTap: 'ChatDetail_BuyNowBtn_Tap',
|
|
25
|
+
newChatCreateBtnTap: 'NewChat_CreateBtn_Tap',
|
|
26
|
+
chatDetailShoppingCartBtnTap: 'ChatDetail_ShoppingCartBtn_Tap',
|
|
27
|
+
chatDetailShareBtnTap: 'ChatDetail_ShareBtn_Tap',
|
|
28
|
+
shareChatModalCopyBtnTap: 'ShareChatModal_CopyBtn_Tap',
|
|
29
|
+
chatDetailRenameBtnTap: 'ChatDetail_RenameBtn_Tap',
|
|
30
|
+
renameModalSaveBtnTap: 'RenameModal_SaveBtn_Tap',
|
|
31
|
+
deleteChatModalDeleteBtnTap: 'DeleteChatModal_DeleteBtn_Tap',
|
|
32
|
+
sidebarSearchConversationTap: 'Sidebar_SearchConversation_Tap',
|
|
33
|
+
sidebarSearchConversationSend: 'Sidebar_SearchConversation_Send',
|
|
34
|
+
newChatNewChatPrmSuggTap: 'NewChat_NewChatPrmSugg_Tap',
|
|
35
|
+
chatDetailInConvPrmSuggTap: 'ChatDetail_InConvPrmSugg_Tap',
|
|
36
|
+
chatDetailInConvPrmSuggScroll: 'ChatDetail_InConvPrmSugg_Scroll',
|
|
37
|
+
chatDetailInConvPrmSuggReturn: 'ChatDetail_InConvPrmSugg_Return',
|
|
38
|
+
chatDetailLivechatBtnTap: 'ChatDetail_LivechatBtn_Tap',
|
|
39
|
+
chatDetailFAQTap: 'ChatDetail_FAQ_Tap',
|
|
40
|
+
chatDetailGiftDetailBtnTap: 'ChatDetail_GiftDetailBtn_Tap',
|
|
41
|
+
};
|
|
@@ -16,6 +16,7 @@ export const ChatContext = createContext<ChatContextType>({
|
|
|
16
16
|
openDrawer: () => {},
|
|
17
17
|
closeDrawer: () => {},
|
|
18
18
|
chatbotUrl: '',
|
|
19
|
+
logGA: () => {},
|
|
19
20
|
});
|
|
20
21
|
|
|
21
22
|
export const useChatContext = () => useContext(ChatContext);
|
|
@@ -40,6 +41,7 @@ export const ChatProvider = (props: ChatProviderProps) => {
|
|
|
40
41
|
csTeamId,
|
|
41
42
|
pushLinkTo,
|
|
42
43
|
chatbotUrl,
|
|
44
|
+
logGA,
|
|
43
45
|
} = props;
|
|
44
46
|
|
|
45
47
|
return (
|
|
@@ -57,6 +59,7 @@ export const ChatProvider = (props: ChatProviderProps) => {
|
|
|
57
59
|
openDrawer,
|
|
58
60
|
closeDrawer,
|
|
59
61
|
chatbotUrl,
|
|
62
|
+
logGA,
|
|
60
63
|
}}
|
|
61
64
|
>
|
|
62
65
|
<ReanimatedDrawerExample ref={ref}>
|