react-native-chatbot-ai 0.1.68 → 0.1.70

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 (33) hide show
  1. package/lib/module/components/chat/footer/AttachmentBottomSheet.js +94 -0
  2. package/lib/module/components/chat/footer/AttachmentBottomSheet.js.map +1 -0
  3. package/lib/module/components/chat/footer/SuggestionsBar.js +1 -6
  4. package/lib/module/components/chat/footer/SuggestionsBar.js.map +1 -1
  5. package/lib/module/components/chat/footer/index.js +70 -118
  6. package/lib/module/components/chat/footer/index.js.map +1 -1
  7. package/lib/module/components/product/Card.js +3 -5
  8. package/lib/module/components/product/Card.js.map +1 -1
  9. package/lib/module/components/product/CardHorizontal.js +3 -5
  10. package/lib/module/components/product/CardHorizontal.js.map +1 -1
  11. package/lib/module/constants/index.js +2 -0
  12. package/lib/module/constants/index.js.map +1 -1
  13. package/lib/module/hooks/upload/useUploadItem.js +3 -0
  14. package/lib/module/hooks/upload/useUploadItem.js.map +1 -1
  15. package/lib/module/translation/resources/i18n.js +5 -2
  16. package/lib/module/translation/resources/i18n.js.map +1 -1
  17. package/lib/typescript/src/components/chat/footer/AttachmentBottomSheet.d.ts +8 -0
  18. package/lib/typescript/src/components/chat/footer/AttachmentBottomSheet.d.ts.map +1 -0
  19. package/lib/typescript/src/components/chat/footer/SuggestionsBar.d.ts.map +1 -1
  20. package/lib/typescript/src/components/chat/footer/index.d.ts.map +1 -1
  21. package/lib/typescript/src/constants/index.d.ts +1 -0
  22. package/lib/typescript/src/constants/index.d.ts.map +1 -1
  23. package/lib/typescript/src/hooks/upload/useUploadItem.d.ts.map +1 -1
  24. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  25. package/package.json +1 -1
  26. package/src/components/chat/footer/AttachmentBottomSheet.tsx +117 -0
  27. package/src/components/chat/footer/SuggestionsBar.tsx +0 -5
  28. package/src/components/chat/footer/index.tsx +79 -130
  29. package/src/components/product/Card.tsx +3 -3
  30. package/src/components/product/CardHorizontal.tsx +3 -3
  31. package/src/constants/index.ts +3 -0
  32. package/src/hooks/upload/useUploadItem.ts +3 -0
  33. package/src/translation/resources/i18n.ts +6 -2
@@ -1,37 +1,20 @@
1
1
  import {
2
- KButton,
3
2
  KColors,
4
3
  KContainer,
5
4
  KImage,
6
5
  KInput,
7
- KLabel,
8
- KRadiusValue,
9
6
  KSpacingValue,
10
7
  KFonts,
11
8
  } from '@droppii/libs';
12
9
  import SuggestionsBar from './SuggestionsBar';
13
- import { useCallback, useState, useRef, useMemo, useEffect } from 'react';
14
- import type { ComponentType } from 'react';
15
- import {
16
- FlatList,
17
- StyleSheet,
18
- TouchableWithoutFeedback,
19
- Platform,
20
- } from 'react-native';
10
+ import { useCallback, useState, useMemo, useEffect } from 'react';
11
+ import { FlatList, StyleSheet } from 'react-native';
21
12
 
22
- // Type assertion to fix TypeScript issue with React Native components
23
- const FlatListComponent = FlatList as unknown as ComponentType<any>;
24
13
  import debounce from 'lodash/debounce';
25
14
  import { useSendMessage } from '../../../hooks/message/useSendMessage';
26
15
  import { UploadItem, useUploadItem } from '../../../hooks/upload/useUploadItem';
27
16
  import useStreamMessageStore from '../../../store/streamMessage';
28
- import {
29
- Menu,
30
- MenuTrigger,
31
- MenuOption,
32
- MenuOptions,
33
- renderers,
34
- } from 'react-native-popup-menu';
17
+
35
18
  import UploadImageItem from './item/UploadImageItem';
36
19
  import UploadFileItem from './item/UploadFileItem';
37
20
  import {
@@ -44,8 +27,8 @@ import { trans } from '../../../translation';
44
27
  import { useChatContext } from '../../../context/ChatContext';
45
28
  import { GAEvents } from '../../../constants/events';
46
29
  import useSessionStore from '../../../store/session';
47
-
48
- const { Popover } = renderers;
30
+ import { openAttachmentBottomSheet } from './AttachmentBottomSheet';
31
+ import { IS_IOS } from '../../../constants';
49
32
 
50
33
  interface IChatFooterProps {
51
34
  lastMessage?: IMessageItem;
@@ -56,7 +39,6 @@ const uploadItemKeyExtractor = (item: UploadItem) => {
56
39
  };
57
40
 
58
41
  const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
59
- const menuRef = useRef(null);
60
42
  const logGA = useChatContext().logGA;
61
43
  const { onSendMessage } = useSendMessage();
62
44
  const [message, setMessage] = useState('');
@@ -94,21 +76,6 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
94
76
  );
95
77
  }, [lastMessage]);
96
78
 
97
- const menuItems = useMemo(() => {
98
- return [
99
- {
100
- icon: 'image-o',
101
- onPress: onPressImagePicker,
102
- label: trans('photo_library'),
103
- },
104
- {
105
- icon: 'camera-o',
106
- onPress: onPressCameraPicker,
107
- label: trans('camera'),
108
- },
109
- ];
110
- }, [onPressImagePicker, onPressCameraPicker]);
111
-
112
79
  const onPressSend = useCallback(() => {
113
80
  if (isDisabledSend) return;
114
81
  if (isStreaming) {
@@ -169,6 +136,14 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
169
136
  [handleRemoveUploadItem, handleUploadSuccess]
170
137
  );
171
138
 
139
+ const onPressAttachment = useCallback(() => {
140
+ openAttachmentBottomSheet({
141
+ handleCamera: onPressCameraPicker,
142
+ handleDocument: handlePressDocumentPicker,
143
+ handlePhoto: onPressImagePicker,
144
+ });
145
+ }, [handlePressDocumentPicker, onPressCameraPicker, onPressImagePicker]);
146
+
172
147
  useEffect(() => {
173
148
  return () => {
174
149
  stopStream();
@@ -176,7 +151,11 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
176
151
  }, [stopStream, sessionId]);
177
152
 
178
153
  return (
179
- <KContainer.View style={styles.container}>
154
+ <KContainer.View
155
+ background={KColors.white}
156
+ paddingT="0.5rem"
157
+ style={styles.container}
158
+ >
180
159
  <KContainer.VisibleView visible={isShowSuggestions}>
181
160
  <SuggestionsBar
182
161
  suggestions={lastMessage?.suggestions}
@@ -185,83 +164,82 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
185
164
  onSendMessage={onSendMessage}
186
165
  />
187
166
  </KContainer.VisibleView>
188
- <KContainer.View style={styles.contentContainer}>
189
- <KContainer.VisibleView visible={fileUpload.length > 0}>
190
- <FlatListComponent
167
+ <KContainer.VisibleView visible={fileUpload.length > 0}>
168
+ <KContainer.View>
169
+ <FlatList
191
170
  data={fileUpload}
192
171
  renderItem={renderUploadItem}
193
172
  horizontal
194
173
  keyExtractor={uploadItemKeyExtractor}
195
174
  contentContainerStyle={styles.listUploadItem}
196
175
  />
197
- </KContainer.VisibleView>
198
- <KContainer.View padding={4}>
176
+ </KContainer.View>
177
+ </KContainer.VisibleView>
178
+ <KContainer.View
179
+ row
180
+ alignItems
181
+ paddingB="0.5rem"
182
+ paddingH="0.5rem"
183
+ background={KColors.white}
184
+ >
185
+ <KContainer.Touchable
186
+ padding={'0.5rem'}
187
+ marginR={'0.5rem'}
188
+ justifyContent
189
+ alignItems
190
+ background={KColors.palette.gray.w25}
191
+ br={'round'}
192
+ onPress={onPressAttachment}
193
+ >
194
+ <KImage.VectorIcons
195
+ name="plus-o"
196
+ size={24}
197
+ color={KColors.gray.dark}
198
+ />
199
+ </KContainer.Touchable>
200
+ <KContainer.View
201
+ row
202
+ flex
203
+ alignItems="flex-end"
204
+ background={KColors.palette.gray.w25}
205
+ paddingV={4}
206
+ paddingR={4}
207
+ paddingL={'0.75rem'}
208
+ style={styles.inputContainer}
209
+ >
199
210
  <KInput.TextArea
211
+ flex
200
212
  paddingV={0}
201
- paddingH={Platform.OS === 'ios' ? 2 : 0}
213
+ paddingH={IS_IOS ? 2 : 0}
202
214
  placeholder={trans('input_placeholder')}
203
215
  clearButtonMode="hidden"
204
216
  onChangeText={debouncedMessage}
205
217
  value={message}
206
218
  multiline
207
219
  style={styles.input}
220
+ background="transparent"
208
221
  blurOnSubmit={false}
209
222
  textAlignVertical="top"
210
223
  />
211
- </KContainer.View>
212
- <KContainer.View style={styles.actions}>
213
- <Menu
214
- ref={menuRef}
215
- renderer={Popover}
216
- rendererProps={{
217
- placement: 'top',
218
- anchorStyle: { display: 'none' },
219
- }}
224
+
225
+ <KContainer.Touchable
226
+ padding={'0.5rem'}
227
+ marginL={'0.5rem'}
228
+ justifyContent
229
+ alignItems
230
+ background={
231
+ isStreaming ? KColors.gray.dark : KColors.primary.normal
232
+ }
233
+ br={'round'}
234
+ onPress={onPressSend}
235
+ style={{ opacity: isDisabledSend ? 0.5 : 1 }}
220
236
  >
221
- <MenuTrigger
222
- customStyles={{
223
- TriggerTouchableComponent: TouchableWithoutFeedback,
224
- }}
225
- >
226
- <KImage.VectorIcons
227
- name="image-o"
228
- size={24}
229
- color={KColors.gray.dark}
230
- />
231
- </MenuTrigger>
232
- <MenuOptions optionsContainerStyle={styles.popover}>
233
- {menuItems.map((i) => (
234
- <MenuOption
235
- key={i.icon}
236
- onSelect={i.onPress}
237
- style={styles.menuItem}
238
- >
239
- <KImage.VectorIcons name={i.icon} />
240
- <KLabel.Text typo="TextMdMedium">{i.label}</KLabel.Text>
241
- </MenuOption>
242
- ))}
243
- </MenuOptions>
244
- </Menu>
245
- <KContainer.Touchable onPress={handlePressDocumentPicker}>
246
237
  <KImage.VectorIcons
247
- name="paperclip-o"
248
- size={24}
249
- color={KColors.gray.dark}
238
+ name={isStreaming ? 'square-b' : 'send-b'}
239
+ size={18}
240
+ color={KColors.white}
250
241
  />
251
242
  </KContainer.Touchable>
252
- <KContainer.View flex />
253
- <KContainer.View style={{ opacity: isDisabledSend ? 0.5 : 1 }}>
254
- <KButton.Solid
255
- kind="primary"
256
- icon={{
257
- vectorName: isStreaming ? 'square-b' : 'send-b',
258
- size: 20,
259
- tintColor: KColors.white,
260
- }}
261
- onPress={onPressSend}
262
- br="round"
263
- />
264
- </KContainer.View>
265
243
  </KContainer.View>
266
244
  </KContainer.View>
267
245
  </KContainer.View>
@@ -272,26 +250,7 @@ export default ChatFooter;
272
250
 
273
251
  const styles = StyleSheet.create({
274
252
  container: {
275
- paddingVertical: KSpacingValue['0.5rem'],
276
- borderWidth: 1,
277
- borderColor: KColors.hexToRgba(KColors.black, 0.15),
278
- borderBottomWidth: 0,
279
- borderTopLeftRadius: KSpacingValue['1.25rem'],
280
- borderTopRightRadius: KSpacingValue['1.25rem'],
281
- backgroundColor: KColors.white,
282
-
283
- shadowColor: 'rgb(21, 23, 24)',
284
- shadowOffset: {
285
- width: 0,
286
- height: -18,
287
- },
288
- shadowOpacity: 0.04,
289
- shadowRadius: 36,
290
-
291
- elevation: 10,
292
- },
293
- contentContainer: {
294
- paddingHorizontal: KSpacingValue['0.75rem'],
253
+ gap: 8,
295
254
  },
296
255
  actions: {
297
256
  flexDirection: 'row',
@@ -302,29 +261,19 @@ const styles = StyleSheet.create({
302
261
  sendButton: {
303
262
  alignSelf: 'flex-end',
304
263
  },
264
+ inputContainer: {
265
+ borderRadius: 22,
266
+ },
305
267
  input: {
306
268
  maxHeight: 100,
307
269
  fontSize: 16,
308
270
  lineHeight: 22.4,
309
271
  fontFamily: KFonts.regular,
310
- },
311
- popover: {
312
- borderRadius: KRadiusValue['4x'],
313
- backgroundColor: KColors.white,
314
- width: 200,
315
- paddingHorizontal: KSpacingValue['0.75rem'],
316
- paddingVertical: KSpacingValue['0.5rem'],
317
- },
318
- menuItem: {
319
- padding: KSpacingValue['0.5rem'],
320
- flexDirection: 'row',
321
- alignItems: 'center',
322
- justifyContent: 'flex-start',
323
- gap: KSpacingValue['0.75rem'],
272
+ marginVertical: IS_IOS ? 0 : -8,
324
273
  },
325
274
  listUploadItem: {
326
275
  gap: KSpacingValue['0.75rem'],
276
+ paddingHorizontal: KSpacingValue['0.5rem'],
327
277
  paddingTop: 6,
328
- paddingBottom: 8,
329
278
  },
330
279
  });
@@ -290,7 +290,7 @@ const ProductCard = memo(
290
290
  logGA(GAEvents.chatDetailBuyNowBtnTap, {
291
291
  conversation_id: useSessionStore.getState().sessionId,
292
292
  product_id: item.id,
293
- position_in_list: -1, //TODO: fix
293
+ position_in_list: index,
294
294
  pdp_id: item.pdpId,
295
295
  message_chat_id: messageId,
296
296
  tab_name: getRouteKey(tabIndex),
@@ -302,7 +302,7 @@ const ProductCard = memo(
302
302
  {
303
303
  conversation_id: useSessionStore.getState().sessionId,
304
304
  product_id: item.id,
305
- position_in_list: -1, //TODO: fix
305
+ position_in_list: index,
306
306
  pdp_id: item.pdpId,
307
307
  message_chat_id: messageId,
308
308
  tab_name: getRouteKey(tabIndex),
@@ -310,7 +310,7 @@ const ProductCard = memo(
310
310
  },
311
311
  EventProvider.netcore
312
312
  );
313
- }, [onBuyNow, logGA, item, messageId, tabIndex]);
313
+ }, [onBuyNow, logGA, item, messageId, tabIndex, index]);
314
314
 
315
315
  const onJumpToMessage = useCallback(() => {
316
316
  if (!item) return;
@@ -304,7 +304,7 @@ const ProductHorizontalCard = memo(
304
304
  logGA(GAEvents.chatDetailBuyNowBtnTap, {
305
305
  conversation_id: useSessionStore.getState().sessionId,
306
306
  product_id: item.id,
307
- position_in_list: -1, //TODO: fix
307
+ position_in_list: index,
308
308
  pdp_id: item.pdpId,
309
309
  message_chat_id: messageId,
310
310
  tab_name: getRouteKey(tabIndex),
@@ -315,7 +315,7 @@ const ProductHorizontalCard = memo(
315
315
  {
316
316
  conversation_id: useSessionStore.getState().sessionId,
317
317
  product_id: item.id,
318
- position_in_list: -1, //TODO: fix
318
+ position_in_list: index,
319
319
  pdp_id: item.pdpId,
320
320
  message_chat_id: messageId,
321
321
  tab_name: getRouteKey(tabIndex),
@@ -323,7 +323,7 @@ const ProductHorizontalCard = memo(
323
323
  },
324
324
  EventProvider.netcore
325
325
  );
326
- }, [onBuyNow, logGA, item, messageId, tabIndex]);
326
+ }, [onBuyNow, logGA, item, messageId, tabIndex, index]);
327
327
 
328
328
  return (
329
329
  <KContainer.Touchable style={styles.container} onPress={onPress}>
@@ -1,5 +1,6 @@
1
1
  import { createRef } from 'react';
2
2
  import { WithBottomSheetProps, WithPopupProps, WithToastProps } from '../types';
3
+ import { Platform } from 'react-native';
3
4
  export * from './chatTab';
4
5
 
5
6
  const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER + 100;
@@ -13,3 +14,5 @@ export const Z_INDEX_PRIORITY = {
13
14
  bottomSheet: MAX_SAFE_INTEGER - 2,
14
15
  popup: MAX_SAFE_INTEGER, // Highest priority - always on top
15
16
  };
17
+
18
+ export const IS_IOS = Platform.OS === 'ios';
@@ -105,6 +105,7 @@ export const useUploadItem = ({ logGA }: Props) => {
105
105
 
106
106
  const onPressImagePicker = useCallback(async () => {
107
107
  Keyboard.dismiss();
108
+ UIUtils.bottomSheet.dismiss();
108
109
  if (imageUpload.length >= MAX_FILE_UPLOAD) {
109
110
  UIUtils.toast.open({
110
111
  title: trans('max_image_reached', { number: MAX_FILE_UPLOAD }),
@@ -130,6 +131,7 @@ export const useUploadItem = ({ logGA }: Props) => {
130
131
 
131
132
  const onPressCameraPicker = useCallback(async () => {
132
133
  Keyboard.dismiss();
134
+ UIUtils.bottomSheet.dismiss();
133
135
  if (imageUpload.length >= MAX_FILE_UPLOAD) {
134
136
  UIUtils.toast.open({
135
137
  title: trans('max_image_reached', { number: MAX_FILE_UPLOAD }),
@@ -149,6 +151,7 @@ export const useUploadItem = ({ logGA }: Props) => {
149
151
 
150
152
  const handlePressDocumentPicker = useCallback(async () => {
151
153
  Keyboard.dismiss();
154
+ UIUtils.bottomSheet.dismiss();
152
155
  if (documentUpload.length >= MAX_FILE_UPLOAD) {
153
156
  UIUtils.toast.open({
154
157
  title: trans('max_file_reached', { number: MAX_FILE_UPLOAD }),
@@ -5,8 +5,6 @@ const i18nKey: Record<string, string> = {
5
5
  chat_empty_title: 'Bạn cần hỗ trợ gì hôm nay?',
6
6
  chat_empty_description_1: 'Hãy đặt câu hỏi hoặc chia sẻ vấn đề của bạn!',
7
7
  chat_empty_description_2: 'Những gợi ý dành cho bạn:',
8
- photo_library: 'Thư viện ảnh',
9
- camera: 'Chụp ảnh',
10
8
 
11
9
  // Session options
12
10
  session_options_title: 'Tuỳ chọn phiên chat',
@@ -14,6 +12,12 @@ const i18nKey: Record<string, string> = {
14
12
  session_share: 'Chia sẻ',
15
13
  session_delete: 'Xoá',
16
14
 
15
+ // Attachment bottom sheet
16
+ attachment_options_title: 'Tuỳ chọn thêm',
17
+ attachment_photo_library: 'Thư viện ảnh',
18
+ attachment_camera: 'Chụp ảnh',
19
+ attachment_document: 'Tài liệu',
20
+
17
21
  // Rename session
18
22
  rename_session_title: 'Đổi tên phiên chat',
19
23
  rename_session_placeholder: 'Nhập tên phiên chat',