react-native-chatbot-ai 0.1.37 → 0.1.39

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.
Files changed (52) hide show
  1. package/lib/module/components/Drawer/RenameSessionPopup.js +2 -1
  2. package/lib/module/components/Drawer/RenameSessionPopup.js.map +1 -1
  3. package/lib/module/components/Drawer/SessionOptionsBottomSheet.js +1 -1
  4. package/lib/module/components/Drawer/SessionOptionsBottomSheet.js.map +1 -1
  5. package/lib/module/components/chat/ChatEmpty.js +2 -6
  6. package/lib/module/components/chat/ChatEmpty.js.map +1 -1
  7. package/lib/module/components/chat/ChatMessageList.js +21 -30
  8. package/lib/module/components/chat/ChatMessageList.js.map +1 -1
  9. package/lib/module/components/chat/footer/index.js +2 -1
  10. package/lib/module/components/chat/footer/index.js.map +1 -1
  11. package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js +7 -1
  12. package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js.map +1 -1
  13. package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js +2 -6
  14. package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js.map +1 -1
  15. package/lib/module/components/chat/item/index.js +5 -5
  16. package/lib/module/components/chat/item/index.js.map +1 -1
  17. package/lib/module/components/portal/Popup.js +6 -0
  18. package/lib/module/components/portal/Popup.js.map +1 -1
  19. package/lib/module/constants/events.js +0 -1
  20. package/lib/module/constants/events.js.map +1 -1
  21. package/lib/module/hooks/message/useMessage.js +22 -10
  22. package/lib/module/hooks/message/useMessage.js.map +1 -1
  23. package/lib/module/hooks/message/useSendMessage.js +1 -1
  24. package/lib/module/hooks/message/useSendMessage.js.map +1 -1
  25. package/lib/module/hooks/message/useStreamMessage.js +9 -11
  26. package/lib/module/hooks/message/useStreamMessage.js.map +1 -1
  27. package/lib/typescript/src/components/chat/ChatMessageList.d.ts.map +1 -1
  28. package/lib/typescript/src/components/chat/footer/index.d.ts.map +1 -1
  29. package/lib/typescript/src/components/chat/item/ChatAIAnswerMessageItem.d.ts.map +1 -1
  30. package/lib/typescript/src/components/chat/item/ChatAIThinkingMessageItem.d.ts.map +1 -1
  31. package/lib/typescript/src/components/chat/item/index.d.ts +2 -2
  32. package/lib/typescript/src/components/chat/item/index.d.ts.map +1 -1
  33. package/lib/typescript/src/components/portal/Popup.d.ts.map +1 -1
  34. package/lib/typescript/src/constants/events.d.ts +0 -1
  35. package/lib/typescript/src/constants/events.d.ts.map +1 -1
  36. package/lib/typescript/src/hooks/message/useMessage.d.ts.map +1 -1
  37. package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
  38. package/lib/typescript/src/hooks/message/useStreamMessage.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/components/Drawer/RenameSessionPopup.tsx +1 -0
  41. package/src/components/Drawer/SessionOptionsBottomSheet.tsx +1 -1
  42. package/src/components/chat/ChatEmpty.tsx +2 -2
  43. package/src/components/chat/ChatMessageList.tsx +21 -32
  44. package/src/components/chat/footer/index.tsx +2 -1
  45. package/src/components/chat/item/ChatAIAnswerMessageItem.tsx +12 -2
  46. package/src/components/chat/item/ChatAIThinkingMessageItem.tsx +2 -7
  47. package/src/components/chat/item/index.tsx +6 -6
  48. package/src/components/portal/Popup.tsx +4 -1
  49. package/src/constants/events.ts +0 -1
  50. package/src/hooks/message/useMessage.ts +27 -14
  51. package/src/hooks/message/useSendMessage.ts +5 -1
  52. package/src/hooks/message/useStreamMessage.ts +24 -14
@@ -199,7 +199,11 @@ class CustomRenderer extends Renderer implements RendererInterface {
199
199
  );
200
200
  default:
201
201
  return (
202
- <KLabel.Text typo="TextMdNormal" key={this.getKey()}>
202
+ <KLabel.Text
203
+ typo="TextMdNormal"
204
+ key={this.getKey()}
205
+ selectable={true}
206
+ >
203
207
  {match?.[2] || ''}
204
208
  </KLabel.Text>
205
209
  );
@@ -225,6 +229,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
225
229
  key={this.getKey()}
226
230
  typo="TextMdNormal"
227
231
  color={KColors.black}
232
+ selectable={true}
228
233
  >
229
234
  {text}
230
235
  </KLabel.Text>
@@ -237,6 +242,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
237
242
  key={this.getKey()}
238
243
  typo="TextMdNormal"
239
244
  color={KColors.black}
245
+ selectable={true}
240
246
  >
241
247
  {text}
242
248
  </KLabel.Text>
@@ -250,6 +256,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
250
256
  typo="TextMdBold"
251
257
  style={styles.mdStrong}
252
258
  color={KColors.black}
259
+ selectable={true}
253
260
  >
254
261
  {children}
255
262
  </KLabel.Text>
@@ -262,6 +269,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
262
269
  typo="TextMdNormal"
263
270
  style={styles.mdEm}
264
271
  color={KColors.black}
272
+ selectable={true}
265
273
  >
266
274
  {children}
267
275
  </KLabel.Text>
@@ -286,6 +294,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
286
294
  typo="TextMdNormal"
287
295
  style={textStyle}
288
296
  color={KColors.gray.dark}
297
+ selectable={true}
289
298
  >
290
299
  {text}
291
300
  </KLabel.Text>
@@ -500,10 +509,11 @@ const ChatAIAnswerMessageItem = ({
500
509
  ))}
501
510
 
502
511
  {/* Message Actions Bar */}
512
+
503
513
  <MessageActionsBar
504
514
  messageId={item.id}
505
515
  messageContent={item.content}
506
- isVisible={!isStreaming}
516
+ isVisible={!isStreaming || (isStreaming && !isLast)}
507
517
  productImages={productImages}
508
518
  message={item}
509
519
  />
@@ -8,14 +8,13 @@ import {
8
8
  } from '@droppii/libs';
9
9
  import FastImage from '@d11/react-native-fast-image';
10
10
  import type { IMessageItem } from '../../../types';
11
- import { StyleSheet, DeviceEventEmitter } from 'react-native';
11
+ import { StyleSheet } from 'react-native';
12
12
  import { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
13
13
  import { IconThinkingStep } from '../../../assets/svgIcon/IconThinkingStep';
14
14
  import { IconChatArrow } from '../../../assets/svgIcon/IconChatArrow';
15
15
  import useStreamMessageStore from '../../../store/streamMessage';
16
16
  import Markdown, { Renderer, RendererInterface } from 'react-native-marked';
17
17
  import icons from '../../../assets/icons';
18
- import { events } from '../../../constants/events';
19
18
  import { trans } from '../../../translation';
20
19
 
21
20
  interface ChatAIThinkingMessageItemProps {
@@ -91,10 +90,6 @@ const ChatAIThinkingMessageItem = ({
91
90
  const [display, setDisplay] = useState('');
92
91
  const indexRef = useRef(0);
93
92
 
94
- const onPressExpandThinkingStep = useCallback((expand: boolean) => {
95
- DeviceEventEmitter.emit(events.expandThinkingStep, expand);
96
- }, []);
97
-
98
93
  const renderHeader = useCallback(() => {
99
94
  return (
100
95
  <KContainer.View style={styles.header}>
@@ -158,7 +153,6 @@ const ChatAIThinkingMessageItem = ({
158
153
  containerStyle={styles.container}
159
154
  headerStyle={styles.mHeader}
160
155
  defaultValue={true}
161
- onChangeValue={onPressExpandThinkingStep}
162
156
  >
163
157
  {renderThinkingContent()}
164
158
  </KListItem.Accordion>
@@ -234,6 +228,7 @@ const styles = StyleSheet.create({
234
228
  marginHorizontal: KSpacingValue['1rem'],
235
229
  },
236
230
  loadingIcon: {
231
+ marginTop: KSpacingValue['1rem'],
237
232
  width: 42,
238
233
  height: 42,
239
234
  },
@@ -5,18 +5,18 @@ import ChatUserMessageItem from './ChatUserMessageItem';
5
5
 
6
6
  interface ChatItemProps {
7
7
  item: IMessageItem;
8
- index: number;
8
+ isLastItem: boolean;
9
9
  }
10
- const ChatItem = ({ item, index }: ChatItemProps) => {
10
+ const ChatItem = ({ item, isLastItem = false }: ChatItemProps) => {
11
11
  switch (item.type) {
12
12
  case MessageType.user_message:
13
- return <ChatUserMessageItem item={item} isLast={index === 0} />;
13
+ return <ChatUserMessageItem item={item} isLast={isLastItem} />;
14
14
  case MessageType.ai_answer:
15
- return <ChatAIAnswerMessageItem item={item} isLast={index === 0} />;
15
+ return <ChatAIAnswerMessageItem item={item} isLast={isLastItem} />;
16
16
  case MessageType.ai_thinking:
17
- return <ChatAIThinkingMessageItem item={item} isLast={index === 0} />;
17
+ return <ChatAIThinkingMessageItem item={item} isLast={isLastItem} />;
18
18
  default:
19
- return <ChatUserMessageItem item={item} isLast={index === 0} />;
19
+ return <ChatUserMessageItem item={item} isLast={isLastItem} />;
20
20
  }
21
21
  };
22
22
 
@@ -45,6 +45,7 @@ import {
45
45
  import { Z_INDEX_PRIORITY } from '../../constants';
46
46
  import { ScrollView } from 'react-native-gesture-handler';
47
47
  import { WithPopupProps } from '../../types';
48
+ import { useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller';
48
49
 
49
50
  const UNIT = KSpacingValue['1rem'];
50
51
  const STATUS_BAR_HEIGHT = KDims.os === 'ios' ? 0 : StatusBar.currentHeight || 0;
@@ -248,8 +249,10 @@ const Popup = forwardRef<WithPopupProps>((_, ref) => {
248
249
  e.stopPropagation();
249
250
  }, []);
250
251
 
252
+ const { height } = useReanimatedKeyboardAnimation();
253
+
251
254
  const rStyle = useAnimatedStyle(() => ({
252
- transform: [{ scale: scale.value }],
255
+ transform: [{ scale: scale.value }, { translateY: height.value / 2 }],
253
256
  }));
254
257
 
255
258
  if (!data) {
@@ -2,7 +2,6 @@ export const events = {
2
2
  updateOneMessage: 'update_one_message',
3
3
  updateMultipleMessage: 'update_multiple_message',
4
4
  forceUpdateMessages: 'force_update_messages',
5
- expandThinkingStep: 'expand_thinking_step',
6
5
  updateMessageError: 'update_message_error',
7
6
  };
8
7
 
@@ -28,8 +28,7 @@ export const useMessage = () => {
28
28
  if (!res) return;
29
29
  setLoadState((prev) => ({
30
30
  ...res,
31
- messages:
32
- res?.messages?.length > 0 ? res.messages.reverse() : prev.messages,
31
+ messages: res?.messages?.length > 0 ? res.messages : prev.messages,
33
32
  }));
34
33
  }, [sessionId, getSessionById]);
35
34
 
@@ -44,8 +43,12 @@ export const useMessage = () => {
44
43
  useEffect(() => {
45
44
  const subOneMessage = DeviceEventEmitter.addListener(
46
45
  events.updateOneMessage,
47
- (messageItem: IMessageItem) => {
46
+ (messageItem: IMessageItem, sID?: string) => {
48
47
  setLoadState((prev) => {
48
+ if (sID !== prev.id) {
49
+ return prev;
50
+ }
51
+
49
52
  const messageIndex = prev.messages.findIndex(
50
53
  (m) => m.id === messageItem.id
51
54
  );
@@ -65,7 +68,7 @@ export const useMessage = () => {
65
68
 
66
69
  return {
67
70
  ...prev,
68
- messages: [messageItem, ...prev.messages],
71
+ messages: [...prev.messages, messageItem],
69
72
  };
70
73
  });
71
74
  }
@@ -73,23 +76,29 @@ export const useMessage = () => {
73
76
 
74
77
  const subMultipleMessage = DeviceEventEmitter.addListener(
75
78
  events.updateMultipleMessage,
76
- (messageItems: IMessageItem[]) => {
79
+ (messageItems: IMessageItem[], sID?: string) => {
77
80
  setLoadState((prev) => {
81
+ if (sID !== prev.id) {
82
+ return prev;
83
+ }
84
+
78
85
  const existingIds = new Set(prev.messages.map((m) => m?.id));
79
- const filtered = messageItems
80
- .filter((m) => !existingIds.has(m?.id))
81
- .reverse();
86
+ const filtered = messageItems.filter((m) => !existingIds.has(m?.id));
82
87
  return {
83
88
  ...prev,
84
- messages: [...filtered, ...prev.messages],
89
+ messages: [...prev.messages, ...filtered],
85
90
  };
86
91
  });
87
92
  }
88
93
  );
89
94
  const subForceUpdateMessages = DeviceEventEmitter.addListener(
90
95
  events.forceUpdateMessages,
91
- (messages: IMessageItem[]) => {
96
+ (messages: IMessageItem[], sID?: string) => {
92
97
  setLoadState((prev) => {
98
+ if (sID !== prev.id) {
99
+ return prev;
100
+ }
101
+
93
102
  const merged = prev.messages.map((msg) => {
94
103
  const update = messages.find((u) => u.id === msg.id);
95
104
  return update ? { ...msg, ...update } : msg;
@@ -99,23 +108,27 @@ export const useMessage = () => {
99
108
  const newItems = messages.filter((u) => !existingIds.has(u.id));
100
109
  return {
101
110
  ...prev,
102
- messages: [...newItems, ...merged],
111
+ messages: [...merged, ...newItems],
103
112
  };
104
113
  });
105
114
  }
106
115
  );
107
116
  const subUpdateMessageError = DeviceEventEmitter.addListener(
108
117
  events.updateMessageError,
109
- (messageId: string, metadata: Record<string, any>) => {
118
+ (messageId: string, metadata: Record<string, any>, sID?: string) => {
110
119
  setLoadState((prev) => {
120
+ if (sID !== prev.id) {
121
+ return prev;
122
+ }
123
+
111
124
  const messageIndex = prev.messages.findIndex(
112
125
  (m) => m.id === messageId
113
126
  );
114
127
  if (messageIndex === -1) return prev;
115
- const updatedMessages = prev.messages
128
+ const updatedMessages: IMessageItem[] = prev.messages
116
129
  .slice(messageIndex)
117
130
  .map((m, i) =>
118
- i === 0
131
+ i === updatedMessages?.length - 1
119
132
  ? {
120
133
  ...m,
121
134
  metadata: {
@@ -46,7 +46,11 @@ export const useSendMessage = () => {
46
46
  manual_retry_attempts: 0,
47
47
  group_suggestion_id: null,
48
48
  };
49
- DeviceEventEmitter.emit(events.updateOneMessage, messageItem);
49
+ DeviceEventEmitter.emit(
50
+ events.updateOneMessage,
51
+ messageItem,
52
+ useSessionStore.getState().sessionId
53
+ );
50
54
 
51
55
  let latestSessionId;
52
56
  if (!useSessionStore.getState().sessionId) {
@@ -69,7 +69,8 @@ export const useStreamMessage = () => {
69
69
  () => {
70
70
  DeviceEventEmitter.emit(
71
71
  events.updateMultipleMessage,
72
- Object.values(buffers).map((m) => ({ ...m, content: '' }))
72
+ Object.values(buffers).map((m) => ({ ...m, content: '' })),
73
+ useSessionStore.getState().sessionId
73
74
  );
74
75
  setStreamMessage(buffers);
75
76
  },
@@ -83,19 +84,23 @@ export const useStreamMessage = () => {
83
84
  ) => {
84
85
  await new Promise((resolve) => setTimeout(resolve, 500));
85
86
  if (isError) {
86
- DeviceEventEmitter.emit(events.updateMessageError, [
87
+ DeviceEventEmitter.emit(
88
+ events.updateMessageError,
89
+ messageId,
87
90
  {
88
- id: messageId,
89
- metadata: {
90
- needs_retry: true,
91
- original_message_id: localMessageId || messageId,
92
- status: 'error',
93
- },
91
+ needs_retry: true,
92
+ original_message_id: localMessageId || messageId,
93
+ status: 'error',
94
94
  },
95
- ]);
95
+ useSessionStore.getState().sessionId
96
+ );
96
97
  } else {
97
98
  const arrMessages = Object.values(buffers);
98
- DeviceEventEmitter.emit(events.forceUpdateMessages, arrMessages);
99
+ DeviceEventEmitter.emit(
100
+ events.forceUpdateMessages,
101
+ arrMessages,
102
+ useSessionStore.getState().sessionId
103
+ );
99
104
  arrMessages.forEach((m: any) => {
100
105
  if (m?.suggestions?.length > 0) {
101
106
  logGA?.(GAEvents.chatDetailInConvPrmSuggReturn, {
@@ -149,6 +154,7 @@ export const useStreamMessage = () => {
149
154
  });
150
155
 
151
156
  es.addEventListener('close', async () => {
157
+ throttledFlush.cancel();
152
158
  console.log('✅ Stream closed');
153
159
  });
154
160
  },
@@ -157,10 +163,14 @@ export const useStreamMessage = () => {
157
163
 
158
164
  const retryStream = useCallback(
159
165
  (messageItem: IMessageItem) => {
160
- DeviceEventEmitter.emit(events.updateOneMessage, {
161
- ...messageItem,
162
- metadata: {},
163
- });
166
+ DeviceEventEmitter.emit(
167
+ events.updateOneMessage,
168
+ {
169
+ ...messageItem,
170
+ metadata: {},
171
+ },
172
+ sessionId
173
+ );
164
174
 
165
175
  logGA(GAEvents.chatDetailSendBtnTap, {
166
176
  chat_type: useSessionStore.getState().sessionLogType,