react-native-chatbot-ai 0.1.19 → 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 +113 -0
- package/lib/module/components/Drawer/DeleteSessionPopup.js.map +1 -0
- package/lib/module/components/Drawer/DrawerContent.js +21 -8
- package/lib/module/components/Drawer/DrawerContent.js.map +1 -1
- package/lib/module/components/Drawer/RenameSessionPopup.js +121 -0
- package/lib/module/components/Drawer/RenameSessionPopup.js.map +1 -0
- 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 +36 -20
- package/lib/module/components/Drawer/SessionItem.js.map +1 -1
- package/lib/module/components/Drawer/SessionList.js +2 -5
- package/lib/module/components/Drawer/SessionList.js.map +1 -1
- package/lib/module/components/Drawer/SessionOptionsBottomSheet.js +129 -0
- package/lib/module/components/Drawer/SessionOptionsBottomSheet.js.map +1 -0
- package/lib/module/components/Drawer/ShareSessionPopup.js +132 -0
- package/lib/module/components/Drawer/ShareSessionPopup.js.map +1 -0
- 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 +75 -24
- 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 +36 -5
- 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 +243 -0
- package/lib/module/components/chat/item/MessageActionsBar.js.map +1 -0
- package/lib/module/components/chat/item/actions/ActionButton.js +56 -0
- package/lib/module/components/chat/item/actions/ActionButton.js.map +1 -0
- package/lib/module/components/portal/BottomSheet.js +245 -0
- package/lib/module/components/portal/BottomSheet.js.map +1 -0
- package/lib/module/components/portal/Popup.js +278 -0
- package/lib/module/components/portal/Popup.js.map +1 -0
- package/lib/module/components/portal/index.js +11 -5
- package/lib/module/components/portal/index.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/constants/index.js +5 -1
- package/lib/module/constants/index.js.map +1 -1
- package/lib/module/constants/query.js +5 -1
- package/lib/module/constants/query.js.map +1 -1
- package/lib/module/context/ChatContext.js +9 -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/index.js +13 -0
- package/lib/module/hooks/messageActions/index.js.map +1 -0
- package/lib/module/hooks/messageActions/useAudioPlayer.js +269 -0
- package/lib/module/hooks/messageActions/useAudioPlayer.js.map +1 -0
- package/lib/module/hooks/messageActions/useCopyToClipboard.js +38 -0
- package/lib/module/hooks/messageActions/useCopyToClipboard.js.map +1 -0
- package/lib/module/hooks/messageActions/useFeedback.js +93 -0
- package/lib/module/hooks/messageActions/useFeedback.js.map +1 -0
- package/lib/module/hooks/messageActions/useSendFeedback.js +24 -0
- package/lib/module/hooks/messageActions/useSendFeedback.js.map +1 -0
- package/lib/module/hooks/messageActions/useShareMessage.js +128 -0
- package/lib/module/hooks/messageActions/useShareMessage.js.map +1 -0
- package/lib/module/hooks/session/useDeleteSession.js +23 -0
- package/lib/module/hooks/session/useDeleteSession.js.map +1 -0
- package/lib/module/hooks/session/useRenameSession.js +28 -0
- package/lib/module/hooks/session/useRenameSession.js.map +1 -0
- package/lib/module/hooks/session/useSearchSessions.js +5 -1
- package/lib/module/hooks/session/useSearchSessions.js.map +1 -1
- package/lib/module/hooks/session/useShareSession.js +16 -0
- package/lib/module/hooks/session/useShareSession.js.map +1 -0
- package/lib/module/hooks/upload/useImageUpload.js +2 -1
- package/lib/module/hooks/upload/useImageUpload.js.map +1 -1
- package/lib/module/services/endpoints.js +6 -1
- package/lib/module/services/endpoints.js.map +1 -1
- package/lib/module/services/index.js +1 -0
- package/lib/module/services/index.js.map +1 -1
- package/lib/module/services/playbackService.js +22 -0
- package/lib/module/services/playbackService.js.map +1 -0
- package/lib/module/store/audioPlayer.js +75 -0
- package/lib/module/store/audioPlayer.js.map +1 -0
- package/lib/module/store/messageActions.js +160 -0
- package/lib/module/store/messageActions.js.map +1 -0
- 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/i18n.js +39 -0
- 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/module/types/index.js +1 -0
- package/lib/module/types/index.js.map +1 -1
- package/lib/module/types/messageActions.js +56 -0
- package/lib/module/types/messageActions.js.map +1 -0
- package/lib/module/utils/textCleaner.js +67 -0
- package/lib/module/utils/textCleaner.js.map +1 -0
- package/lib/module/utils/ui.js +27 -1
- package/lib/module/utils/ui.js.map +1 -1
- package/lib/typescript/src/components/Drawer/DeleteSessionPopup.d.ts +3 -0
- package/lib/typescript/src/components/Drawer/DeleteSessionPopup.d.ts.map +1 -0
- package/lib/typescript/src/components/Drawer/DrawerContent.d.ts.map +1 -1
- package/lib/typescript/src/components/Drawer/RenameSessionPopup.d.ts +3 -0
- package/lib/typescript/src/components/Drawer/RenameSessionPopup.d.ts.map +1 -0
- package/lib/typescript/src/components/Drawer/SearchInput.d.ts.map +1 -1
- package/lib/typescript/src/components/Drawer/SessionItem.d.ts.map +1 -1
- package/lib/typescript/src/components/Drawer/SessionList.d.ts.map +1 -1
- package/lib/typescript/src/components/Drawer/SessionOptionsBottomSheet.d.ts +3 -0
- package/lib/typescript/src/components/Drawer/SessionOptionsBottomSheet.d.ts.map +1 -0
- package/lib/typescript/src/components/Drawer/ShareSessionPopup.d.ts +3 -0
- package/lib/typescript/src/components/Drawer/ShareSessionPopup.d.ts.map +1 -0
- 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 +16 -0
- package/lib/typescript/src/components/chat/item/MessageActionsBar.d.ts.map +1 -0
- package/lib/typescript/src/components/chat/item/actions/ActionButton.d.ts +19 -0
- package/lib/typescript/src/components/chat/item/actions/ActionButton.d.ts.map +1 -0
- package/lib/typescript/src/components/portal/BottomSheet.d.ts +8 -0
- package/lib/typescript/src/components/portal/BottomSheet.d.ts.map +1 -0
- package/lib/typescript/src/components/portal/Popup.d.ts +4 -0
- package/lib/typescript/src/components/portal/Popup.d.ts.map +1 -0
- package/lib/typescript/src/components/portal/index.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/constants/index.d.ts +5 -1
- package/lib/typescript/src/constants/index.d.ts.map +1 -1
- package/lib/typescript/src/constants/query.d.ts +4 -0
- package/lib/typescript/src/constants/query.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/index.d.ts +10 -0
- package/lib/typescript/src/hooks/messageActions/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/messageActions/useAudioPlayer.d.ts +14 -0
- package/lib/typescript/src/hooks/messageActions/useAudioPlayer.d.ts.map +1 -0
- package/lib/typescript/src/hooks/messageActions/useCopyToClipboard.d.ts +9 -0
- package/lib/typescript/src/hooks/messageActions/useCopyToClipboard.d.ts.map +1 -0
- package/lib/typescript/src/hooks/messageActions/useFeedback.d.ts +18 -0
- package/lib/typescript/src/hooks/messageActions/useFeedback.d.ts.map +1 -0
- package/lib/typescript/src/hooks/messageActions/useSendFeedback.d.ts +6 -0
- package/lib/typescript/src/hooks/messageActions/useSendFeedback.d.ts.map +1 -0
- package/lib/typescript/src/hooks/messageActions/useShareMessage.d.ts +12 -0
- package/lib/typescript/src/hooks/messageActions/useShareMessage.d.ts.map +1 -0
- package/lib/typescript/src/hooks/session/useDeleteSession.d.ts +2 -0
- package/lib/typescript/src/hooks/session/useDeleteSession.d.ts.map +1 -0
- package/lib/typescript/src/hooks/session/useRenameSession.d.ts +2 -0
- package/lib/typescript/src/hooks/session/useRenameSession.d.ts.map +1 -0
- 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/session/useShareSession.d.ts +2 -0
- package/lib/typescript/src/hooks/session/useShareSession.d.ts.map +1 -0
- 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/services/endpoints.d.ts +5 -0
- package/lib/typescript/src/services/endpoints.d.ts.map +1 -1
- package/lib/typescript/src/services/index.d.ts +1 -0
- package/lib/typescript/src/services/index.d.ts.map +1 -1
- package/lib/typescript/src/services/playbackService.d.ts +2 -0
- package/lib/typescript/src/services/playbackService.d.ts.map +1 -0
- package/lib/typescript/src/store/audioPlayer.d.ts +27 -0
- package/lib/typescript/src/store/audioPlayer.d.ts.map +1 -0
- package/lib/typescript/src/store/messageActions.d.ts +9 -0
- package/lib/typescript/src/store/messageActions.d.ts.map +1 -0
- 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 +16 -1
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/types/dto.d.ts +11 -0
- package/lib/typescript/src/types/dto.d.ts.map +1 -1
- package/lib/typescript/src/types/index.d.ts +1 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/lib/typescript/src/types/messageActions.d.ts +85 -0
- package/lib/typescript/src/types/messageActions.d.ts.map +1 -0
- package/lib/typescript/src/types/ui.d.ts +16 -1
- package/lib/typescript/src/types/ui.d.ts.map +1 -1
- package/lib/typescript/src/utils/textCleaner.d.ts +30 -0
- package/lib/typescript/src/utils/textCleaner.d.ts.map +1 -0
- package/lib/typescript/src/utils/ui.d.ts +12 -1
- package/lib/typescript/src/utils/ui.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/components/Drawer/DeleteSessionPopup.tsx +121 -0
- package/src/components/Drawer/DrawerContent.tsx +23 -7
- package/src/components/Drawer/RenameSessionPopup.tsx +145 -0
- package/src/components/Drawer/SearchInput.tsx +11 -2
- package/src/components/Drawer/SessionItem.tsx +22 -8
- package/src/components/Drawer/SessionList.tsx +0 -2
- package/src/components/Drawer/SessionOptionsBottomSheet.tsx +138 -0
- package/src/components/Drawer/ShareSessionPopup.tsx +145 -0
- package/src/components/chat/ChatEmpty.tsx +15 -5
- package/src/components/chat/ChatHeader.tsx +9 -4
- package/src/components/chat/ChatMessageList.tsx +78 -18
- 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 +55 -6
- package/src/components/chat/item/DeeplinkItem.tsx +30 -2
- package/src/components/chat/item/MessageActionsBar.tsx +326 -0
- package/src/components/chat/item/actions/ActionButton.tsx +65 -0
- package/src/components/portal/BottomSheet.tsx +307 -0
- package/src/components/portal/Popup.tsx +345 -0
- package/src/components/portal/index.tsx +5 -1
- package/src/components/product/CardHorizontal.tsx +45 -10
- package/src/constants/events.ts +34 -0
- package/src/constants/index.ts +6 -1
- package/src/constants/query.ts +4 -0
- package/src/context/ChatContext.tsx +6 -0
- package/src/hooks/message/useSendMessage.ts +47 -4
- package/src/hooks/message/useStreamMessage.ts +15 -4
- package/src/hooks/messageActions/index.ts +10 -0
- package/src/hooks/messageActions/useAudioPlayer.ts +346 -0
- package/src/hooks/messageActions/useCopyToClipboard.ts +38 -0
- package/src/hooks/messageActions/useFeedback.ts +114 -0
- package/src/hooks/messageActions/useSendFeedback.ts +31 -0
- package/src/hooks/messageActions/useShareMessage.ts +146 -0
- package/src/hooks/session/useDeleteSession.ts +25 -0
- package/src/hooks/session/useRenameSession.ts +37 -0
- package/src/hooks/session/useSearchSessions.ts +6 -1
- package/src/hooks/session/useShareSession.ts +22 -0
- package/src/hooks/upload/useImageUpload.ts +6 -2
- package/src/ignore.d.ts +20 -1
- package/src/services/endpoints.ts +10 -0
- package/src/services/index.ts +1 -0
- package/src/services/playbackService.ts +22 -0
- package/src/store/audioPlayer.ts +112 -0
- package/src/store/messageActions.ts +161 -0
- package/src/store/session.ts +4 -2
- package/src/translation/index.ts +27 -19
- package/src/translation/resources/i18n.ts +45 -0
- package/src/types/chat.ts +21 -1
- package/src/types/dto.ts +14 -0
- package/src/types/index.ts +1 -0
- package/src/types/messageActions.ts +131 -0
- package/src/types/ui.ts +19 -1
- package/src/utils/textCleaner.ts +65 -0
- package/src/utils/ui.tsx +29 -2
- package/lib/module/translation/resources/vi.js +0 -12
- package/lib/module/translation/resources/vi.js.map +0 -1
- package/lib/typescript/src/translation/resources/vi.d.ts +0 -11
- package/lib/typescript/src/translation/resources/vi.d.ts.map +0 -1
- package/src/translation/resources/vi.ts +0 -10
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
import {
|
|
3
|
+
KContainer,
|
|
4
|
+
KLabel,
|
|
5
|
+
KColors,
|
|
6
|
+
KSpacingValue,
|
|
7
|
+
KImage,
|
|
8
|
+
} from '@droppii/libs';
|
|
9
|
+
import UIUtils from '../../utils/ui';
|
|
10
|
+
import { trans } from '../../translation';
|
|
11
|
+
import { SessionSearchItem } from '../../types/dto';
|
|
12
|
+
import { openRenameSessionPopup } from './RenameSessionPopup';
|
|
13
|
+
import { openShareSessionPopup } from './ShareSessionPopup';
|
|
14
|
+
import { openDeleteSessionPopup } from './DeleteSessionPopup';
|
|
15
|
+
import { GAEvents } from '../../constants/events';
|
|
16
|
+
|
|
17
|
+
interface OptionItemProps {
|
|
18
|
+
icon: string;
|
|
19
|
+
label: string;
|
|
20
|
+
onPress: () => void;
|
|
21
|
+
isDanger?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const OptionItem = ({ icon, label, onPress, isDanger }: OptionItemProps) => {
|
|
25
|
+
const color = isDanger ? KColors.danger.normal : KColors.gray.dark;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
<KContainer.Touchable onPress={onPress} style={styles.optionItem}>
|
|
30
|
+
<KImage.VectorIcons name={icon} size={20} color={color} />
|
|
31
|
+
{/* @ts-ignore */}
|
|
32
|
+
<KLabel.Text typo="TextMdMedium" color={color} style={styles.optionLabel}>
|
|
33
|
+
{label}
|
|
34
|
+
</KLabel.Text>
|
|
35
|
+
</KContainer.Touchable>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const openSessionOptionsBottomSheet = (
|
|
40
|
+
session: SessionSearchItem,
|
|
41
|
+
closeDrawer?: () => void,
|
|
42
|
+
logGA?: (event: string, params?: any) => void
|
|
43
|
+
) => {
|
|
44
|
+
const handleRename = () => {
|
|
45
|
+
UIUtils.bottomSheet.dismiss();
|
|
46
|
+
// Close drawer first, then open popup
|
|
47
|
+
closeDrawer?.();
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
openRenameSessionPopup(session);
|
|
50
|
+
}, 300);
|
|
51
|
+
logGA?.(GAEvents.chatDetailRenameBtnTap, {
|
|
52
|
+
conversation_id: session?.id,
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const handleShare = () => {
|
|
57
|
+
UIUtils.bottomSheet.dismiss();
|
|
58
|
+
// Close drawer first, then open popup
|
|
59
|
+
closeDrawer?.();
|
|
60
|
+
setTimeout(() => {
|
|
61
|
+
openShareSessionPopup(session);
|
|
62
|
+
}, 300);
|
|
63
|
+
logGA?.(GAEvents.chatDetailShareBtnTap, {
|
|
64
|
+
conversation_id: session?.id,
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const handleDelete = () => {
|
|
69
|
+
UIUtils.bottomSheet.dismiss();
|
|
70
|
+
// Close drawer first, then open popup
|
|
71
|
+
closeDrawer?.();
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
openDeleteSessionPopup(session, logGA);
|
|
74
|
+
}, 300);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const OptionsContent = () => {
|
|
78
|
+
return (
|
|
79
|
+
// @ts-ignore
|
|
80
|
+
<KContainer.View style={styles.container}>
|
|
81
|
+
<OptionItem
|
|
82
|
+
icon="edit-o"
|
|
83
|
+
label={trans('chatbot:session_rename')}
|
|
84
|
+
onPress={handleRename}
|
|
85
|
+
/>
|
|
86
|
+
{/* @ts-ignore */}
|
|
87
|
+
<KContainer.View style={styles.divider} />
|
|
88
|
+
<OptionItem
|
|
89
|
+
icon="share-o"
|
|
90
|
+
label={trans('chatbot:session_share')}
|
|
91
|
+
onPress={handleShare}
|
|
92
|
+
/>
|
|
93
|
+
{/* @ts-ignore */}
|
|
94
|
+
<KContainer.View style={styles.divider} />
|
|
95
|
+
<OptionItem
|
|
96
|
+
icon="trash-alt-o-1"
|
|
97
|
+
label={trans('chatbot:session_delete')}
|
|
98
|
+
onPress={handleDelete}
|
|
99
|
+
isDanger
|
|
100
|
+
/>
|
|
101
|
+
</KContainer.View>
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
UIUtils.bottomSheet.open({
|
|
106
|
+
header: {
|
|
107
|
+
title: {
|
|
108
|
+
text: trans('chatbot:session_options_title'),
|
|
109
|
+
},
|
|
110
|
+
showCloseButton: true,
|
|
111
|
+
},
|
|
112
|
+
body: {
|
|
113
|
+
renderContent: () => <OptionsContent />,
|
|
114
|
+
},
|
|
115
|
+
touchOutsideToDismiss: true,
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const styles = StyleSheet.create({
|
|
120
|
+
container: {
|
|
121
|
+
paddingHorizontal: KSpacingValue['1rem'],
|
|
122
|
+
paddingVertical: KSpacingValue['0.5rem'],
|
|
123
|
+
},
|
|
124
|
+
optionItem: {
|
|
125
|
+
flexDirection: 'row',
|
|
126
|
+
alignItems: 'center',
|
|
127
|
+
paddingVertical: KSpacingValue['1rem'],
|
|
128
|
+
paddingHorizontal: KSpacingValue['0.5rem'],
|
|
129
|
+
},
|
|
130
|
+
optionLabel: {
|
|
131
|
+
marginLeft: KSpacingValue['0.75rem'],
|
|
132
|
+
},
|
|
133
|
+
divider: {
|
|
134
|
+
height: 1,
|
|
135
|
+
backgroundColor: KColors.border.light,
|
|
136
|
+
marginHorizontal: KSpacingValue['0.5rem'],
|
|
137
|
+
},
|
|
138
|
+
});
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { useCallback, useState, useEffect } from 'react';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
import {
|
|
4
|
+
KContainer,
|
|
5
|
+
KLabel,
|
|
6
|
+
KColors,
|
|
7
|
+
KSpacingValue,
|
|
8
|
+
KInput,
|
|
9
|
+
} from '@droppii/libs';
|
|
10
|
+
import { useShareSession } from '../../hooks/session/useShareSession';
|
|
11
|
+
import UIUtils from '../../utils/ui';
|
|
12
|
+
import { trans } from '../../translation';
|
|
13
|
+
import { SessionSearchItem } from '../../types/dto';
|
|
14
|
+
import Clipboard from '@react-native-clipboard/clipboard';
|
|
15
|
+
import { useChatContext } from '../../context/ChatContext';
|
|
16
|
+
import { GAEvents } from '../../constants/events';
|
|
17
|
+
|
|
18
|
+
const truncateText = (text: string, maxLength: number) => {
|
|
19
|
+
if (text.length <= maxLength) return text;
|
|
20
|
+
return text.substring(0, maxLength) + '…';
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
interface ShareContentProps {
|
|
24
|
+
session: SessionSearchItem;
|
|
25
|
+
onConfirmRef: React.RefObject<(() => Promise<void>) | null>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const ShareContent = ({ session, onConfirmRef }: ShareContentProps) => {
|
|
29
|
+
const { mutateAsync: shareSession } = useShareSession();
|
|
30
|
+
const { chatbotUrl, logGA } = useChatContext();
|
|
31
|
+
const [shareUrl, setShareUrl] = useState('');
|
|
32
|
+
|
|
33
|
+
// Generate share URL based on chatbotUrl
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
setShareUrl(`${chatbotUrl}/shared/${session.id}`);
|
|
36
|
+
}, [chatbotUrl, session.id]);
|
|
37
|
+
|
|
38
|
+
// Expose handleConfirm via ref
|
|
39
|
+
onConfirmRef.current = useCallback(async () => {
|
|
40
|
+
try {
|
|
41
|
+
const response = await shareSession(session.id);
|
|
42
|
+
if (response) {
|
|
43
|
+
// Copy the generated share URL to clipboard
|
|
44
|
+
Clipboard.setString(shareUrl);
|
|
45
|
+
UIUtils.toast.showSuccess(trans('chatbot:share_session_success'));
|
|
46
|
+
UIUtils.popup.dismiss();
|
|
47
|
+
logGA(GAEvents.shareChatModalCopyBtnTap, {
|
|
48
|
+
conversation_id: session.id,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
UIUtils.toast.showError(err);
|
|
53
|
+
}
|
|
54
|
+
}, [session.id, shareSession, shareUrl, logGA]);
|
|
55
|
+
|
|
56
|
+
const truncatedName = truncateText(session.title, 50);
|
|
57
|
+
const descriptionTemplate = trans('chatbot:share_session_description');
|
|
58
|
+
const parts = descriptionTemplate.split('{sessionName}');
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
<KContainer.View style={styles.container}>
|
|
63
|
+
{/* @ts-ignore */}
|
|
64
|
+
<KLabel.Text
|
|
65
|
+
typo="TextMdNormal"
|
|
66
|
+
color={KColors.gray.dark}
|
|
67
|
+
style={styles.description}
|
|
68
|
+
>
|
|
69
|
+
{parts[0]}
|
|
70
|
+
{/* @ts-ignore */}
|
|
71
|
+
<KLabel.Text typo="TextMdBold" color={KColors.gray.dark}>
|
|
72
|
+
{truncatedName}
|
|
73
|
+
</KLabel.Text>
|
|
74
|
+
{parts[1]}
|
|
75
|
+
</KLabel.Text>
|
|
76
|
+
|
|
77
|
+
{/* Share URL Input */}
|
|
78
|
+
{/* @ts-ignore */}
|
|
79
|
+
<KContainer.View style={[styles.inputWrapper]}>
|
|
80
|
+
<KInput.TextBox
|
|
81
|
+
value={shareUrl}
|
|
82
|
+
label={trans('chatbot:share_session_link_label')}
|
|
83
|
+
labelTypo="TextMdBold"
|
|
84
|
+
disabled
|
|
85
|
+
withBorder
|
|
86
|
+
height={40}
|
|
87
|
+
border="entire"
|
|
88
|
+
radius="borderless"
|
|
89
|
+
/>
|
|
90
|
+
</KContainer.View>
|
|
91
|
+
</KContainer.View>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const openShareSessionPopup = (session: SessionSearchItem) => {
|
|
96
|
+
const onConfirmRef = { current: null } as React.RefObject<
|
|
97
|
+
(() => Promise<void>) | null
|
|
98
|
+
>;
|
|
99
|
+
|
|
100
|
+
UIUtils.popup.open({
|
|
101
|
+
header: {
|
|
102
|
+
title: {
|
|
103
|
+
text: trans('chatbot:share_session_title'),
|
|
104
|
+
},
|
|
105
|
+
showCloseButton: true,
|
|
106
|
+
alignment: 'left',
|
|
107
|
+
},
|
|
108
|
+
body: {
|
|
109
|
+
scrollable: false,
|
|
110
|
+
renderContent: () => (
|
|
111
|
+
<ShareContent session={session} onConfirmRef={onConfirmRef} />
|
|
112
|
+
),
|
|
113
|
+
},
|
|
114
|
+
actions: {
|
|
115
|
+
type: 'horizontal-button',
|
|
116
|
+
buttons: [
|
|
117
|
+
{
|
|
118
|
+
kind: 'light',
|
|
119
|
+
label: trans('chatbot:share_session_cancel'),
|
|
120
|
+
weight: 'medium',
|
|
121
|
+
onPress: () => UIUtils.popup.dismiss(),
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
kind: 'primary',
|
|
125
|
+
label: trans('chatbot:share_session_confirm'),
|
|
126
|
+
weight: 'medium',
|
|
127
|
+
onPress: () => onConfirmRef.current?.(),
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const styles = StyleSheet.create({
|
|
135
|
+
container: {
|
|
136
|
+
paddingVertical: KSpacingValue['1rem'],
|
|
137
|
+
paddingHorizontal: KSpacingValue['1rem'],
|
|
138
|
+
},
|
|
139
|
+
description: {
|
|
140
|
+
marginBottom: KSpacingValue['1rem'],
|
|
141
|
+
},
|
|
142
|
+
inputWrapper: {
|
|
143
|
+
paddingBottom: KSpacingValue['0.5rem'],
|
|
144
|
+
},
|
|
145
|
+
});
|
|
@@ -4,15 +4,24 @@ import { useFetchSuggestions } from '../../hooks/suggestions/useFetchSuggestions
|
|
|
4
4
|
import SuggestionItem from './SuggestionItem';
|
|
5
5
|
import { useSendMessage } from '../../hooks/message/useSendMessage';
|
|
6
6
|
import debounce from 'lodash/debounce';
|
|
7
|
-
import { type ISuggestionItem } from '../../types';
|
|
8
|
-
import trans from '../../translation';
|
|
7
|
+
import { SendActionLogType, type ISuggestionItem } from '../../types';
|
|
8
|
+
import { trans } from '../../translation';
|
|
9
|
+
import { useChatContext } from '../../context/ChatContext';
|
|
10
|
+
import { GAEvents } from '../../constants/events';
|
|
9
11
|
|
|
10
12
|
const ChatEmpty = () => {
|
|
11
13
|
const { data } = useFetchSuggestions();
|
|
12
14
|
const { onSendMessage } = useSendMessage();
|
|
15
|
+
const logGA = useChatContext().logGA;
|
|
13
16
|
|
|
14
|
-
const onPress = debounce((item: ISuggestionItem) => {
|
|
15
|
-
|
|
17
|
+
const onPress = debounce((item: ISuggestionItem, index: number) => {
|
|
18
|
+
logGA(GAEvents.newChatNewChatPrmSuggTap, {
|
|
19
|
+
suggestion_id: item.suggestion_id,
|
|
20
|
+
suggestion_content: item.content,
|
|
21
|
+
suggestion_cate: item.category,
|
|
22
|
+
order: index,
|
|
23
|
+
});
|
|
24
|
+
onSendMessage(item.content, undefined, SendActionLogType.promptSuggestion);
|
|
16
25
|
}, 200);
|
|
17
26
|
|
|
18
27
|
return (
|
|
@@ -31,10 +40,11 @@ const ChatEmpty = () => {
|
|
|
31
40
|
{trans('chat_empty_description_2')}
|
|
32
41
|
</KLabel.Text>
|
|
33
42
|
</KContainer.View>
|
|
34
|
-
{data?.suggestions?.map((item: ISuggestionItem) => (
|
|
43
|
+
{data?.suggestions?.map((item: ISuggestionItem, index: number) => (
|
|
35
44
|
<SuggestionItem
|
|
36
45
|
key={item.suggestion_id}
|
|
37
46
|
item={item}
|
|
47
|
+
index={index}
|
|
38
48
|
onPressItem={onPress}
|
|
39
49
|
/>
|
|
40
50
|
))}
|
|
@@ -12,6 +12,8 @@ import { ImageBackground, StatusBar, StyleSheet } from 'react-native';
|
|
|
12
12
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
13
13
|
import useSessionStore from '../../store/session';
|
|
14
14
|
import { useChatContext } from '../../context/ChatContext';
|
|
15
|
+
import { SessionLogType } from '../../types/chat';
|
|
16
|
+
import { GAEvents } from '../../constants/events';
|
|
15
17
|
|
|
16
18
|
// Type assertion to fix TypeScript issue with React Native components
|
|
17
19
|
const StatusBarComponent = StatusBar as unknown as ComponentType<{
|
|
@@ -23,11 +25,14 @@ const ImageBackgroundComponent =
|
|
|
23
25
|
export const ChatHeader = () => {
|
|
24
26
|
const insets = useSafeAreaInsets();
|
|
25
27
|
const setSessionId = useSessionStore((state) => state.setSessionId);
|
|
26
|
-
const { cartButton, openDrawer } = useChatContext();
|
|
28
|
+
const { cartButton, openDrawer, logGA } = useChatContext();
|
|
27
29
|
|
|
28
|
-
const onPressNewSession = () => {
|
|
29
|
-
setSessionId(undefined);
|
|
30
|
-
|
|
30
|
+
const onPressNewSession = useCallback(() => {
|
|
31
|
+
setSessionId(undefined, SessionLogType.newChatBtn);
|
|
32
|
+
logGA(GAEvents.newChatCreateBtnTap, {
|
|
33
|
+
button_type: 'quick_button',
|
|
34
|
+
});
|
|
35
|
+
}, [setSessionId, logGA]);
|
|
31
36
|
|
|
32
37
|
const renderStatusBar = useCallback(() => {
|
|
33
38
|
return (
|
|
@@ -1,25 +1,38 @@
|
|
|
1
|
-
import { FlatList, StyleSheet, DeviceEventEmitter } from 'react-native';
|
|
1
|
+
import { FlatList, StyleSheet, DeviceEventEmitter, View } from 'react-native';
|
|
2
2
|
import type { ComponentType } from 'react';
|
|
3
|
+
import { useCallback, useRef, useEffect, useState } from 'react';
|
|
3
4
|
import ChatEmpty from './ChatEmpty';
|
|
4
5
|
import ChatItem from './item';
|
|
5
|
-
import { KSpacingValue } from '@droppii/libs';
|
|
6
|
+
import { KSpacingValue, KColors, KImage, KContainer } from '@droppii/libs';
|
|
6
7
|
import type { IMessageItem } from '../../types';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
8
|
+
import { events, GAEvents } from '../../constants/events';
|
|
9
|
+
import { useChatContext } from '../../context/ChatContext';
|
|
10
|
+
import useSessionStore from '../../store/session';
|
|
10
11
|
|
|
11
|
-
// Type assertion to fix TypeScript issue with React Native components
|
|
12
12
|
const FlatListComponent = FlatList as unknown as ComponentType<any>;
|
|
13
13
|
|
|
14
14
|
interface IChatMessageListProps {
|
|
15
15
|
messageList?: IMessageItem[];
|
|
16
16
|
}
|
|
17
|
+
|
|
17
18
|
const ChatMessageList = ({ messageList = [] }: IChatMessageListProps) => {
|
|
19
|
+
const logGA = useChatContext().logGA;
|
|
20
|
+
const sessionId = useSessionStore((state) => state.sessionId);
|
|
21
|
+
|
|
18
22
|
const flatListRef = useRef<any>(null);
|
|
19
23
|
const scrollOffsetRef = useRef(0);
|
|
24
|
+
const [showScrollToBottom, setShowScrollToBottom] = useState(false);
|
|
20
25
|
|
|
21
26
|
const onScroll = useCallback((event: any) => {
|
|
22
|
-
|
|
27
|
+
const offsetY = event?.nativeEvent?.contentOffset?.y ?? 0;
|
|
28
|
+
scrollOffsetRef.current = offsetY;
|
|
29
|
+
|
|
30
|
+
const threshold = 50;
|
|
31
|
+
setShowScrollToBottom(offsetY > threshold);
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
const scrollToBottom = useCallback(() => {
|
|
35
|
+
flatListRef.current?.scrollToOffset({ offset: 0, animated: true }); // inverted => bottom = offset 0
|
|
23
36
|
}, []);
|
|
24
37
|
|
|
25
38
|
useEffect(() => {
|
|
@@ -45,19 +58,51 @@ const ChatMessageList = ({ messageList = [] }: IChatMessageListProps) => {
|
|
|
45
58
|
};
|
|
46
59
|
}, []);
|
|
47
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
|
+
|
|
48
71
|
return (
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
72
|
+
<View style={{ flex: 1 }}>
|
|
73
|
+
<FlatListComponent
|
|
74
|
+
ref={flatListRef}
|
|
75
|
+
data={messageList}
|
|
76
|
+
renderItem={({
|
|
77
|
+
item,
|
|
78
|
+
index,
|
|
79
|
+
}: {
|
|
80
|
+
item: IMessageItem;
|
|
81
|
+
index: number;
|
|
82
|
+
}) => <ChatItem item={item} index={index} />}
|
|
83
|
+
keyExtractor={(item: IMessageItem) => item.id}
|
|
84
|
+
contentContainerStyle={styles.container}
|
|
85
|
+
inverted
|
|
86
|
+
ListEmptyComponent={<ChatEmpty />}
|
|
87
|
+
onScroll={onScroll}
|
|
88
|
+
scrollEventThrottle={16}
|
|
89
|
+
/>
|
|
90
|
+
|
|
91
|
+
{showScrollToBottom && (
|
|
92
|
+
<KContainer.Touchable
|
|
93
|
+
style={styles.scrollButton}
|
|
94
|
+
onPress={scrollToBottom}
|
|
95
|
+
activeOpacity={0.7}
|
|
96
|
+
center
|
|
97
|
+
>
|
|
98
|
+
<KImage.VectorIcons
|
|
99
|
+
name="arrow-down-o"
|
|
100
|
+
size={16}
|
|
101
|
+
color={KColors.palette.gray.w400}
|
|
102
|
+
/>
|
|
103
|
+
</KContainer.Touchable>
|
|
54
104
|
)}
|
|
55
|
-
|
|
56
|
-
contentContainerStyle={styles.container}
|
|
57
|
-
inverted
|
|
58
|
-
ListEmptyComponent={<ChatEmpty />}
|
|
59
|
-
onScroll={onScroll}
|
|
60
|
-
/>
|
|
105
|
+
</View>
|
|
61
106
|
);
|
|
62
107
|
};
|
|
63
108
|
|
|
@@ -70,4 +115,19 @@ const styles = StyleSheet.create({
|
|
|
70
115
|
paddingVertical: KSpacingValue['1rem'],
|
|
71
116
|
justifyContent: 'flex-end',
|
|
72
117
|
},
|
|
118
|
+
scrollButton: {
|
|
119
|
+
position: 'absolute',
|
|
120
|
+
bottom: 20,
|
|
121
|
+
right: 16,
|
|
122
|
+
backgroundColor: KColors.white,
|
|
123
|
+
width: 32,
|
|
124
|
+
height: 32,
|
|
125
|
+
borderRadius: 16,
|
|
126
|
+
shadowColor: '#000',
|
|
127
|
+
shadowOpacity: 0.15,
|
|
128
|
+
shadowRadius: 4,
|
|
129
|
+
elevation: 4,
|
|
130
|
+
justifyContent: 'center',
|
|
131
|
+
alignItems: 'center',
|
|
132
|
+
},
|
|
73
133
|
});
|
|
@@ -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',
|