@droppii-org/chat-mobile 0.2.12 → 0.2.14
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/ThreadCard/AvatarSection.js +2 -3
- package/lib/module/components/ThreadCard/AvatarSection.js.map +1 -1
- package/lib/module/components/flows/inputButtons/index.js +77 -0
- package/lib/module/components/flows/inputButtons/index.js.map +1 -0
- package/lib/module/components/messages/linkMessage/index.js +1 -1
- package/lib/module/components/messages/linkMessage/index.js.map +1 -1
- package/lib/module/config/api-endpoints.js +1 -0
- package/lib/module/config/api-endpoints.js.map +1 -1
- package/lib/module/context/ChatDetailContext.js +57 -0
- package/lib/module/context/ChatDetailContext.js.map +1 -0
- package/lib/module/hooks/flows/useCurrentConversationFlow.js +9 -0
- package/lib/module/hooks/flows/useCurrentConversationFlow.js.map +1 -0
- package/lib/module/hooks/flows/useFlow.js +57 -0
- package/lib/module/hooks/flows/useFlow.js.map +1 -0
- package/lib/module/hooks/message/useSendMessage.js +4 -2
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/query-keys.js +4 -1
- package/lib/module/hooks/query-keys.js.map +1 -1
- package/lib/module/hooks/useConversationList.js +1 -1
- package/lib/module/hooks/useConversationList.js.map +1 -1
- package/lib/module/hooks/useLinkPreview/useFetchUrlMetadata.js +2 -3
- package/lib/module/hooks/useLinkPreview/useFetchUrlMetadata.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatComposer.js +40 -2
- package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetail.js +66 -58
- package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatListLegend.js +41 -8
- package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatQuickActions.js +12 -3
- package/lib/module/screens/chat-detail/ChatQuickActions.js.map +1 -1
- package/lib/module/screens/chat-detail/conversationHeader.utils.js +1 -1
- package/lib/module/screens/chat-detail/conversationHeader.utils.js.map +1 -1
- package/lib/module/screens/inbox/Inbox.js +1 -3
- package/lib/module/screens/inbox/Inbox.js.map +1 -1
- package/lib/module/screens/inbox/MessagesTab.js +2 -1
- package/lib/module/screens/inbox/MessagesTab.js.map +1 -1
- package/lib/module/services/endpoints.js +4 -1
- package/lib/module/services/endpoints.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.map +1 -1
- package/lib/module/types/flows.js +17 -0
- package/lib/module/types/flows.js.map +1 -0
- package/lib/module/utils/flows.js +11 -0
- package/lib/module/utils/flows.js.map +1 -0
- package/lib/module/utils/url.js +6 -0
- package/lib/module/utils/url.js.map +1 -1
- package/lib/typescript/src/components/ThreadCard/AvatarSection.d.ts +1 -1
- package/lib/typescript/src/components/ThreadCard/AvatarSection.d.ts.map +1 -1
- package/lib/typescript/src/components/flows/inputButtons/index.d.ts +9 -0
- package/lib/typescript/src/components/flows/inputButtons/index.d.ts.map +1 -0
- package/lib/typescript/src/config/api-endpoints.d.ts +1 -0
- package/lib/typescript/src/config/api-endpoints.d.ts.map +1 -1
- package/lib/typescript/src/context/ChatDetailContext.d.ts +5 -0
- package/lib/typescript/src/context/ChatDetailContext.d.ts.map +1 -0
- package/lib/typescript/src/hooks/flows/useCurrentConversationFlow.d.ts +3 -0
- package/lib/typescript/src/hooks/flows/useCurrentConversationFlow.d.ts.map +1 -0
- package/lib/typescript/src/hooks/flows/useFlow.d.ts +4 -0
- package/lib/typescript/src/hooks/flows/useFlow.d.ts.map +1 -0
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts +3 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/query-keys.d.ts +3 -0
- package/lib/typescript/src/hooks/query-keys.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useConversationList.d.ts +2 -2
- package/lib/typescript/src/hooks/useConversationList.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useLinkPreview/useFetchUrlMetadata.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts +1 -1
- 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/ChatListLegend.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatQuickActions.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/conversationHeader.utils.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/types.d.ts +1 -0
- package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
- package/lib/typescript/src/screens/inbox/Inbox.d.ts +1 -2
- package/lib/typescript/src/screens/inbox/Inbox.d.ts.map +1 -1
- package/lib/typescript/src/screens/inbox/MessagesTab.d.ts +1 -2
- package/lib/typescript/src/screens/inbox/MessagesTab.d.ts.map +1 -1
- package/lib/typescript/src/services/endpoints.d.ts +3 -0
- package/lib/typescript/src/services/endpoints.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 +11 -1
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/types/flows.d.ts +82 -0
- package/lib/typescript/src/types/flows.d.ts.map +1 -0
- package/lib/typescript/src/utils/flows.d.ts +4 -0
- package/lib/typescript/src/utils/flows.d.ts.map +1 -0
- package/lib/typescript/src/utils/url.d.ts +1 -0
- package/lib/typescript/src/utils/url.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/ThreadCard/AvatarSection.tsx +2 -2
- package/src/components/flows/inputButtons/index.tsx +105 -0
- package/src/components/messages/linkMessage/index.tsx +1 -1
- package/src/config/api-endpoints.ts +2 -0
- package/src/context/ChatDetailContext.tsx +85 -0
- package/src/hooks/flows/useCurrentConversationFlow.ts +11 -0
- package/src/hooks/flows/useFlow.ts +63 -0
- package/src/hooks/message/useSendMessage.ts +4 -0
- package/src/hooks/query-keys.ts +6 -0
- package/src/hooks/useConversationList.ts +15 -7
- package/src/hooks/useLinkPreview/useFetchUrlMetadata.ts +1 -2
- package/src/screens/chat-detail/ChatComposer.tsx +39 -1
- package/src/screens/chat-detail/ChatDetail.tsx +87 -73
- package/src/screens/chat-detail/ChatListLegend.tsx +54 -3
- package/src/screens/chat-detail/ChatQuickActions.tsx +10 -3
- package/src/screens/chat-detail/conversationHeader.utils.ts +1 -4
- package/src/screens/chat-detail/types.ts +1 -0
- package/src/screens/inbox/Inbox.tsx +3 -15
- package/src/screens/inbox/MessagesTab.tsx +48 -49
- package/src/services/endpoints.ts +6 -0
- package/src/translation/resources/i18n.ts +2 -0
- package/src/types/chat.ts +16 -1
- package/src/types/flows.ts +102 -0
- package/src/utils/flows.ts +18 -0
- package/src/utils/url.ts +7 -0
|
@@ -13,6 +13,11 @@ import type { DMessageItem } from '../../types/chat';
|
|
|
13
13
|
import { LegendChatMessage } from './legend/LegendChatMessage';
|
|
14
14
|
import { LegendChatDay } from './legend/LegendChatDay';
|
|
15
15
|
import { LegendChatLoadEarlier } from './legend/LegendChatLoadEarlier';
|
|
16
|
+
import { useChatDetailContext } from '../../context/ChatDetailContext';
|
|
17
|
+
import { getFlowInputButtonsNode } from '../../utils/flows';
|
|
18
|
+
import { InputButtonFlow } from '../../components/flows/inputButtons';
|
|
19
|
+
import { useResetFlow, useRunFlow } from '../../hooks/flows/useFlow';
|
|
20
|
+
import type { IRunConversationFlowPayload } from '../../types/flows';
|
|
16
21
|
|
|
17
22
|
export const ChatListLegend = memo(
|
|
18
23
|
({
|
|
@@ -35,6 +40,15 @@ export const ChatListLegend = memo(
|
|
|
35
40
|
[messages]
|
|
36
41
|
);
|
|
37
42
|
|
|
43
|
+
const { isBotConversation, conversationFlow } = useChatDetailContext();
|
|
44
|
+
|
|
45
|
+
const lastMessageId = useMemo(() => {
|
|
46
|
+
const last = messages[messages.length - 1];
|
|
47
|
+
return last?.clientMsgID || last?.serverMsgID || null;
|
|
48
|
+
}, [messages]);
|
|
49
|
+
const { mutate: runFlow } = useRunFlow();
|
|
50
|
+
const { mutate: resetFlow } = useResetFlow();
|
|
51
|
+
|
|
38
52
|
const listRef = useRef<LegendListRef>(null);
|
|
39
53
|
const buttonOpacity = useSharedValue(0);
|
|
40
54
|
const isAtBottomRef = useRef(true);
|
|
@@ -71,6 +85,17 @@ export const ChatListLegend = memo(
|
|
|
71
85
|
[]
|
|
72
86
|
);
|
|
73
87
|
|
|
88
|
+
const onRunFlow = useCallback(
|
|
89
|
+
(payload: IRunConversationFlowPayload) => {
|
|
90
|
+
runFlow(payload);
|
|
91
|
+
},
|
|
92
|
+
[runFlow]
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const onResetFlow = useCallback(() => {
|
|
96
|
+
resetFlow();
|
|
97
|
+
}, [resetFlow]);
|
|
98
|
+
|
|
74
99
|
const renderItem = useCallback(
|
|
75
100
|
({ item, index }: any) => {
|
|
76
101
|
try {
|
|
@@ -78,7 +103,9 @@ export const ChatListLegend = memo(
|
|
|
78
103
|
|
|
79
104
|
const message = item as DMessageItem;
|
|
80
105
|
const isOutgoing = message.sendID === currentUserId;
|
|
81
|
-
|
|
106
|
+
const isLastIncoming =
|
|
107
|
+
!isOutgoing &&
|
|
108
|
+
(message.clientMsgID || message.serverMsgID) === lastMessageId;
|
|
82
109
|
const messageId =
|
|
83
110
|
message.clientMsgID ||
|
|
84
111
|
message.serverMsgID ||
|
|
@@ -86,11 +113,18 @@ export const ChatListLegend = memo(
|
|
|
86
113
|
|
|
87
114
|
const messageData = messageDataMap.get(messageId);
|
|
88
115
|
if (!messageData) {
|
|
89
|
-
return null;
|
|
116
|
+
return null;
|
|
90
117
|
}
|
|
91
118
|
|
|
92
119
|
const { dayStart, createdAt } = messageData;
|
|
93
120
|
|
|
121
|
+
let flowInputButtonsNode = null;
|
|
122
|
+
if (isLastIncoming && isBotConversation) {
|
|
123
|
+
flowInputButtonsNode = getFlowInputButtonsNode(
|
|
124
|
+
conversationFlow?.flowCurrentStep
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
94
128
|
return (
|
|
95
129
|
<>
|
|
96
130
|
{dayStart && <LegendChatDay createdAt={createdAt} />}
|
|
@@ -114,6 +148,13 @@ export const ChatListLegend = memo(
|
|
|
114
148
|
onPressUrl={onPressUrl}
|
|
115
149
|
/>
|
|
116
150
|
)}
|
|
151
|
+
{!!flowInputButtonsNode && (
|
|
152
|
+
<InputButtonFlow
|
|
153
|
+
nodeData={flowInputButtonsNode}
|
|
154
|
+
onResetFlow={onResetFlow}
|
|
155
|
+
onRunFlow={onRunFlow}
|
|
156
|
+
/>
|
|
157
|
+
)}
|
|
117
158
|
</KContainer.View>
|
|
118
159
|
</>
|
|
119
160
|
);
|
|
@@ -136,6 +177,11 @@ export const ChatListLegend = memo(
|
|
|
136
177
|
handleItemLayout,
|
|
137
178
|
onMediaPress,
|
|
138
179
|
onPressUrl,
|
|
180
|
+
isBotConversation,
|
|
181
|
+
conversationFlow,
|
|
182
|
+
onResetFlow,
|
|
183
|
+
onRunFlow,
|
|
184
|
+
lastMessageId,
|
|
139
185
|
]
|
|
140
186
|
);
|
|
141
187
|
|
|
@@ -296,7 +342,12 @@ export const ChatListLegend = memo(
|
|
|
296
342
|
renderItem={renderItem}
|
|
297
343
|
estimatedItemSize={avgItemHeightRef.current}
|
|
298
344
|
keyExtractor={(item) => String(item.clientMsgID || item.serverMsgID)}
|
|
299
|
-
recycleItems
|
|
345
|
+
recycleItems={!isBotConversation}
|
|
346
|
+
extraData={
|
|
347
|
+
!isBotConversation
|
|
348
|
+
? `${conversationFlow?.flowCurrentStep?.id ?? ''}-${lastMessageId ?? ''}`
|
|
349
|
+
: undefined
|
|
350
|
+
}
|
|
300
351
|
alignItemsAtEnd
|
|
301
352
|
maintainVisibleContentPosition={!isLoadingEarlier}
|
|
302
353
|
maintainScrollAtEnd={maintainScrollConfig}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from '@droppii/libs';
|
|
10
10
|
import { useChatActionPress } from './useChatActionPress';
|
|
11
11
|
import type { DChatQuickAction, ChatQuickActionsProps } from './types';
|
|
12
|
+
import { useResetFlow } from '../../hooks/flows/useFlow';
|
|
12
13
|
|
|
13
14
|
const QuickActionItem = memo(
|
|
14
15
|
({
|
|
@@ -69,18 +70,24 @@ export const ChatQuickActions = memo(
|
|
|
69
70
|
renderQuickActions,
|
|
70
71
|
}: ChatQuickActionsProps) => {
|
|
71
72
|
const handleActionPress = useChatActionPress(onActionPress);
|
|
73
|
+
const { mutate: resetFlow } = useResetFlow();
|
|
72
74
|
|
|
73
75
|
const renderItem = useCallback<ListRenderItem<DChatQuickAction>>(
|
|
74
76
|
({ item }) => {
|
|
75
|
-
const onPress = () =>
|
|
77
|
+
const onPress = () => {
|
|
78
|
+
handleActionPress(item);
|
|
79
|
+
if (item.id === 'restart') {
|
|
80
|
+
resetFlow?.();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
76
83
|
|
|
77
84
|
if (renderAction) {
|
|
78
85
|
return <>{renderAction(item, onPress)}</>;
|
|
79
86
|
}
|
|
80
87
|
|
|
81
|
-
return <QuickActionItem action={item} onPress={
|
|
88
|
+
return <QuickActionItem action={item} onPress={onPress} />;
|
|
82
89
|
},
|
|
83
|
-
[handleActionPress, renderAction]
|
|
90
|
+
[handleActionPress, renderAction, resetFlow]
|
|
84
91
|
);
|
|
85
92
|
|
|
86
93
|
const keyExtractor = useCallback((item: DChatQuickAction) => item.id, []);
|
|
@@ -32,10 +32,7 @@ export const getConversationSubtitle = (
|
|
|
32
32
|
return `20 thành viên • ${unreadLabel}`;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
if (
|
|
36
|
-
conversation.peerType === PeerType.Customer ||
|
|
37
|
-
conversation.applicationType === 'MALL'
|
|
38
|
-
) {
|
|
35
|
+
if (conversation.peerType === PeerType.Customer) {
|
|
39
36
|
return '338,5K Đã bán • 4,2K Theo dõi';
|
|
40
37
|
}
|
|
41
38
|
|
|
@@ -79,6 +79,7 @@ export interface ChatComposerProps {
|
|
|
79
79
|
renderQuickActions?: ChatQuickActionsProps['renderQuickActions'];
|
|
80
80
|
renderAttachmentAction?: ChatAttachmentPanelProps['renderAction'];
|
|
81
81
|
attachmentColumns?: number;
|
|
82
|
+
isEmptyMessage: boolean;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
export interface ChatListProps {
|
|
@@ -5,7 +5,6 @@ import { KContainer, KImage, KLabel, KColors } from '@droppii/libs';
|
|
|
5
5
|
import { MessagesTab } from './MessagesTab';
|
|
6
6
|
|
|
7
7
|
interface InboxProps {
|
|
8
|
-
applicationType: string;
|
|
9
8
|
onPressThread?: (item: string) => void;
|
|
10
9
|
onPressSearch?: () => void;
|
|
11
10
|
onPressEdit?: () => void;
|
|
@@ -15,13 +14,7 @@ interface InboxProps {
|
|
|
15
14
|
type TabRoute = { key: string; title: string };
|
|
16
15
|
|
|
17
16
|
const Inbox = memo(
|
|
18
|
-
({
|
|
19
|
-
applicationType,
|
|
20
|
-
onPressThread,
|
|
21
|
-
onPressSearch,
|
|
22
|
-
onPressEdit,
|
|
23
|
-
onPressGroup,
|
|
24
|
-
}: InboxProps) => {
|
|
17
|
+
({ onPressThread, onPressSearch, onPressEdit, onPressGroup }: InboxProps) => {
|
|
25
18
|
const [index, setIndex] = useState(0);
|
|
26
19
|
const [routes] = useState<TabRoute[]>([
|
|
27
20
|
{ key: 'messages', title: 'Tin nhắn' },
|
|
@@ -30,16 +23,11 @@ const Inbox = memo(
|
|
|
30
23
|
const renderScene = useCallback(
|
|
31
24
|
({ route }: { route: TabRoute }) => {
|
|
32
25
|
if (route.key === 'messages') {
|
|
33
|
-
return
|
|
34
|
-
<MessagesTab
|
|
35
|
-
applicationType={applicationType}
|
|
36
|
-
onPressThread={onPressThread}
|
|
37
|
-
/>
|
|
38
|
-
);
|
|
26
|
+
return <MessagesTab onPressThread={onPressThread} />;
|
|
39
27
|
}
|
|
40
28
|
return null;
|
|
41
29
|
},
|
|
42
|
-
[
|
|
30
|
+
[onPressThread]
|
|
43
31
|
);
|
|
44
32
|
|
|
45
33
|
const renderTabBar = useCallback(
|
|
@@ -4,69 +4,68 @@ import { KContainer, KDivider, KLabel, KColors } from '@droppii/libs';
|
|
|
4
4
|
import { useConversationList } from '../../hooks/useConversationList';
|
|
5
5
|
import { ThreadCard } from '../../components/ThreadCard';
|
|
6
6
|
import { useConversationStore } from '../../store';
|
|
7
|
+
import { useChatContext } from '../../context';
|
|
7
8
|
|
|
8
9
|
interface MessagesTabProps {
|
|
9
|
-
applicationType: string;
|
|
10
10
|
onPressThread?: (item: string) => void;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const Separator = () => <KDivider type="line" size="hairline" />;
|
|
14
14
|
const keyExtractor = (item: string) => item;
|
|
15
15
|
|
|
16
|
-
export const MessagesTab = memo(
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
export const MessagesTab = memo(({ onPressThread }: MessagesTabProps) => {
|
|
17
|
+
const data = useConversationStore((state) => state.list);
|
|
18
|
+
const applicationType = useChatContext().applicationType;
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
const { isLoading, refetch, isRefetching } = useConversationList({
|
|
21
|
+
applicationType,
|
|
22
|
+
page: 1,
|
|
23
|
+
});
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
const handleThreadPress = useCallback(
|
|
26
|
+
(params: { item: string; event: GestureResponderEvent }) => {
|
|
27
|
+
onPressThread?.(params.item);
|
|
28
|
+
},
|
|
29
|
+
[onPressThread]
|
|
30
|
+
);
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
const renderItem = useCallback(
|
|
33
|
+
({ item }: { item: string }) => (
|
|
34
|
+
<ThreadCard item={item} onPress={handleThreadPress} />
|
|
35
|
+
),
|
|
36
|
+
[handleThreadPress]
|
|
37
|
+
);
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
const LoadingComponent = (
|
|
40
|
+
<KContainer.View center flex paddingV="3rem">
|
|
41
|
+
<ActivityIndicator size="large" color={KColors.palette.primary.w400} />
|
|
42
|
+
</KContainer.View>
|
|
43
|
+
);
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
const EmptyComponent = isLoading ? null : (
|
|
46
|
+
<KContainer.View center flex paddingV="3rem">
|
|
47
|
+
<KLabel.Text typo="TextSmNormal" color={KColors.palette.gray.w400}>
|
|
48
|
+
Không có tin nhắn nào
|
|
49
|
+
</KLabel.Text>
|
|
50
|
+
</KContainer.View>
|
|
51
|
+
);
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<KContainer.FlatList
|
|
59
|
-
data={data}
|
|
60
|
-
renderItem={renderItem}
|
|
61
|
-
keyExtractor={keyExtractor}
|
|
62
|
-
ItemSeparatorComponent={Separator}
|
|
63
|
-
ListEmptyComponent={EmptyComponent}
|
|
64
|
-
refreshing={isRefetching}
|
|
65
|
-
onRefresh={refetch}
|
|
66
|
-
showsVerticalScrollIndicator={false}
|
|
67
|
-
/>
|
|
68
|
-
);
|
|
53
|
+
if (isLoading && data.length === 0) {
|
|
54
|
+
return LoadingComponent;
|
|
69
55
|
}
|
|
70
|
-
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<KContainer.FlatList
|
|
59
|
+
data={data}
|
|
60
|
+
renderItem={renderItem}
|
|
61
|
+
keyExtractor={keyExtractor}
|
|
62
|
+
ItemSeparatorComponent={Separator}
|
|
63
|
+
ListEmptyComponent={EmptyComponent}
|
|
64
|
+
refreshing={isRefetching}
|
|
65
|
+
onRefresh={refetch}
|
|
66
|
+
showsVerticalScrollIndicator={false}
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
});
|
|
71
70
|
|
|
72
71
|
MessagesTab.displayName = 'MessagesTab';
|
|
@@ -16,6 +16,12 @@ export const ENDPOINTS = {
|
|
|
16
16
|
get urlMetadata() {
|
|
17
17
|
return getApiEndpoint('urlMetadata');
|
|
18
18
|
},
|
|
19
|
+
conversationFlow: (id: string) =>
|
|
20
|
+
`${getApiEndpoint('conversationFlow')}/${id}`,
|
|
21
|
+
resetConversationFlow: (id: string) =>
|
|
22
|
+
`${getApiEndpoint('conversationFlow')}/${id}/bot-flows/reset`,
|
|
23
|
+
runConversationFlow: (id: string) =>
|
|
24
|
+
`${getApiEndpoint('conversationFlow')}/${id}/bot-flows/run`,
|
|
19
25
|
},
|
|
20
26
|
uploaderService: {
|
|
21
27
|
get uploadImage() {
|
package/src/types/chat.ts
CHANGED
|
@@ -5,6 +5,11 @@ import {
|
|
|
5
5
|
} from '@droppii/openim-rn-client-sdk';
|
|
6
6
|
import type { PropsWithChildren } from 'react';
|
|
7
7
|
import type { IUrlMetadata } from './common';
|
|
8
|
+
import type {
|
|
9
|
+
IConversationFlow,
|
|
10
|
+
IConversationFlowStep,
|
|
11
|
+
IRunConversationFlowPayload,
|
|
12
|
+
} from './flows';
|
|
8
13
|
|
|
9
14
|
export const EventProvider = {
|
|
10
15
|
ga: 'ga',
|
|
@@ -66,7 +71,7 @@ export interface DConversationItem extends ConversationItem {
|
|
|
66
71
|
conversationId: string;
|
|
67
72
|
chatCategory: DChatCategory;
|
|
68
73
|
chatType: PeerType;
|
|
69
|
-
applicationType:
|
|
74
|
+
applicationType: DChatApplicationType;
|
|
70
75
|
memberRole: DMemberRole;
|
|
71
76
|
pinnedAt: string | null;
|
|
72
77
|
isMuted: boolean;
|
|
@@ -123,6 +128,7 @@ export interface IMessageItemEx {
|
|
|
123
128
|
content: string;
|
|
124
129
|
};
|
|
125
130
|
urlMetadata?: IUrlMetadata;
|
|
131
|
+
flow?: IRunConversationFlowPayload;
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
export interface MessageStore {
|
|
@@ -135,3 +141,12 @@ export interface MessageStore {
|
|
|
135
141
|
deleteOneMessage: (clientMsgID: string) => void;
|
|
136
142
|
reset: () => void;
|
|
137
143
|
}
|
|
144
|
+
|
|
145
|
+
export interface ChatDetailContextType {
|
|
146
|
+
conversationFlow?: IConversationFlow;
|
|
147
|
+
refetchConversationFlow: () => void;
|
|
148
|
+
isBotConversation: boolean;
|
|
149
|
+
setConverationFlowStep: (step: IConversationFlowStep) => void;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface ChatDetailProviderProps extends PropsWithChildren {}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { PeerType } from '@droppii/openim-rn-client-sdk';
|
|
2
|
+
import type { DChatApplicationType, DChatCategory } from './chat';
|
|
3
|
+
|
|
4
|
+
/** START NODE TYPE */
|
|
5
|
+
export const NodeTypes = {
|
|
6
|
+
BubbleText: 'bubble-text',
|
|
7
|
+
BubbleImage: 'bubble-image',
|
|
8
|
+
InputText: 'input-text',
|
|
9
|
+
InputButtons: 'input-buttons',
|
|
10
|
+
LogicCsTeam: 'logic-cs-team',
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export type NodeTypes = (typeof NodeTypes)[keyof typeof NodeTypes];
|
|
14
|
+
|
|
15
|
+
export const ReactFlowsNodeTypes = {
|
|
16
|
+
Group: 'group',
|
|
17
|
+
Start: 'start',
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
export type ReactFlowsNodeTypes =
|
|
21
|
+
(typeof ReactFlowsNodeTypes)[keyof typeof ReactFlowsNodeTypes];
|
|
22
|
+
|
|
23
|
+
export interface BaseNodeData {
|
|
24
|
+
id: string;
|
|
25
|
+
type: NodeTypes;
|
|
26
|
+
parentId: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface BubbleTextNodeData {
|
|
30
|
+
content?: string;
|
|
31
|
+
plainText?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface BubbleImageNodeData {
|
|
35
|
+
sourceType: 'link' | 'upload' | 'giphy' | 'unsplash' | 'icon';
|
|
36
|
+
url?: string;
|
|
37
|
+
onClickLink?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface InputButtonItem {
|
|
41
|
+
id: string;
|
|
42
|
+
label: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface LogicCsTeamNodeData {
|
|
46
|
+
csTeamId?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface InputButtonsNodeData {
|
|
50
|
+
buttons?: InputButtonItem[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface InputTextNodeData {
|
|
54
|
+
longText?: boolean;
|
|
55
|
+
placeholder?: string;
|
|
56
|
+
buttonLabel?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type NodeDataMap = {
|
|
60
|
+
[NodeTypes.BubbleText]: BubbleTextNodeData;
|
|
61
|
+
[NodeTypes.BubbleImage]: BubbleImageNodeData;
|
|
62
|
+
[NodeTypes.InputText]: InputTextNodeData;
|
|
63
|
+
[NodeTypes.InputButtons]: InputButtonsNodeData;
|
|
64
|
+
[NodeTypes.LogicCsTeam]: LogicCsTeamNodeData;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type GroupChild<T extends NodeTypes = NodeTypes> = {
|
|
68
|
+
data: NodeDataMap[T];
|
|
69
|
+
} & BaseNodeData;
|
|
70
|
+
|
|
71
|
+
export interface GroupNodeData {
|
|
72
|
+
label: string;
|
|
73
|
+
children: GroupChild[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** END NODE TYPE */
|
|
77
|
+
|
|
78
|
+
export interface IConversationFlowStep {
|
|
79
|
+
id: string;
|
|
80
|
+
type: ReactFlowsNodeTypes;
|
|
81
|
+
data: GroupNodeData;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface IConversationFlow {
|
|
85
|
+
conversationId: string;
|
|
86
|
+
chatCategory: DChatCategory;
|
|
87
|
+
chatType: PeerType;
|
|
88
|
+
applicationType: DChatApplicationType;
|
|
89
|
+
flowCurrentStep: IConversationFlowStep | null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface IRunConversationFlowResponse {
|
|
93
|
+
flowNextStep: IConversationFlowStep | null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface IRunConversationFlowPayload {
|
|
97
|
+
groupId: string;
|
|
98
|
+
childId: string | null;
|
|
99
|
+
actionId: string | null;
|
|
100
|
+
//for send msg
|
|
101
|
+
plainText?: string;
|
|
102
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NodeTypes,
|
|
3
|
+
type GroupChild,
|
|
4
|
+
type IConversationFlowStep,
|
|
5
|
+
} from '../types/flows';
|
|
6
|
+
|
|
7
|
+
export const getFlowInputButtonsNode = (
|
|
8
|
+
step?: IConversationFlowStep | null
|
|
9
|
+
) => {
|
|
10
|
+
if (!step) return null;
|
|
11
|
+
const childrenNode = step?.data?.children || [];
|
|
12
|
+
const inputButtonsNode = childrenNode?.find(
|
|
13
|
+
(f) => f.type === NodeTypes.InputButtons
|
|
14
|
+
) as GroupChild<'input-buttons'>;
|
|
15
|
+
return inputButtonsNode;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const DEFAULT_BUTTON_ID = 'default-item-button';
|
package/src/utils/url.ts
CHANGED
|
@@ -32,3 +32,10 @@ const URL_REGEX = new RegExp(
|
|
|
32
32
|
export function extractUrls(text: string): string[] {
|
|
33
33
|
return text.match(URL_REGEX) ?? [];
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
export function normalizeUrl(url: string) {
|
|
37
|
+
if (!/^https?:\/\//i.test(url)) {
|
|
38
|
+
return `https://${url}`;
|
|
39
|
+
}
|
|
40
|
+
return url;
|
|
41
|
+
}
|