react-native-chatbot-ai 0.1.69 → 0.1.71

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 (63) hide show
  1. package/lib/module/components/Drawer/SessionItem.js +13 -5
  2. package/lib/module/components/Drawer/SessionItem.js.map +1 -1
  3. package/lib/module/components/Drawer/SessionOptionsBottomSheet.js +96 -31
  4. package/lib/module/components/Drawer/SessionOptionsBottomSheet.js.map +1 -1
  5. package/lib/module/components/chat/footer/AttachmentBottomSheet.js +94 -0
  6. package/lib/module/components/chat/footer/AttachmentBottomSheet.js.map +1 -0
  7. package/lib/module/components/chat/footer/SuggestionsBar.js +1 -6
  8. package/lib/module/components/chat/footer/SuggestionsBar.js.map +1 -1
  9. package/lib/module/components/chat/footer/index.js +70 -118
  10. package/lib/module/components/chat/footer/index.js.map +1 -1
  11. package/lib/module/components/portal/BottomSheet.js +1 -1
  12. package/lib/module/components/portal/BottomSheet.js.map +1 -1
  13. package/lib/module/constants/index.js +2 -0
  14. package/lib/module/constants/index.js.map +1 -1
  15. package/lib/module/constants/query.js +1 -0
  16. package/lib/module/constants/query.js.map +1 -1
  17. package/lib/module/context/ChatContext.js +23 -6
  18. package/lib/module/context/ChatContext.js.map +1 -1
  19. package/lib/module/hooks/session/useSessionPin.js +26 -0
  20. package/lib/module/hooks/session/useSessionPin.js.map +1 -0
  21. package/lib/module/hooks/upload/useUploadItem.js +3 -0
  22. package/lib/module/hooks/upload/useUploadItem.js.map +1 -1
  23. package/lib/module/services/endpoints.js +2 -0
  24. package/lib/module/services/endpoints.js.map +1 -1
  25. package/lib/module/translation/resources/i18n.js +9 -2
  26. package/lib/module/translation/resources/i18n.js.map +1 -1
  27. package/lib/typescript/src/components/Drawer/SessionItem.d.ts.map +1 -1
  28. package/lib/typescript/src/components/Drawer/SessionOptionsBottomSheet.d.ts.map +1 -1
  29. package/lib/typescript/src/components/chat/footer/AttachmentBottomSheet.d.ts +8 -0
  30. package/lib/typescript/src/components/chat/footer/AttachmentBottomSheet.d.ts.map +1 -0
  31. package/lib/typescript/src/components/chat/footer/SuggestionsBar.d.ts.map +1 -1
  32. package/lib/typescript/src/components/chat/footer/index.d.ts.map +1 -1
  33. package/lib/typescript/src/constants/index.d.ts +1 -0
  34. package/lib/typescript/src/constants/index.d.ts.map +1 -1
  35. package/lib/typescript/src/constants/query.d.ts +1 -0
  36. package/lib/typescript/src/constants/query.d.ts.map +1 -1
  37. package/lib/typescript/src/context/ChatContext.d.ts.map +1 -1
  38. package/lib/typescript/src/hooks/session/useSessionPin.d.ts +6 -0
  39. package/lib/typescript/src/hooks/session/useSessionPin.d.ts.map +1 -0
  40. package/lib/typescript/src/hooks/upload/useUploadItem.d.ts.map +1 -1
  41. package/lib/typescript/src/services/endpoints.d.ts +2 -0
  42. package/lib/typescript/src/services/endpoints.d.ts.map +1 -1
  43. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  44. package/lib/typescript/src/types/dto.d.ts +1 -0
  45. package/lib/typescript/src/types/dto.d.ts.map +1 -1
  46. package/lib/typescript/src/types/ui.d.ts +4 -1
  47. package/lib/typescript/src/types/ui.d.ts.map +1 -1
  48. package/package.json +2 -2
  49. package/src/components/Drawer/SessionItem.tsx +11 -3
  50. package/src/components/Drawer/SessionOptionsBottomSheet.tsx +111 -32
  51. package/src/components/chat/footer/AttachmentBottomSheet.tsx +117 -0
  52. package/src/components/chat/footer/SuggestionsBar.tsx +0 -5
  53. package/src/components/chat/footer/index.tsx +79 -130
  54. package/src/components/portal/BottomSheet.tsx +1 -1
  55. package/src/constants/index.ts +3 -0
  56. package/src/constants/query.ts +1 -0
  57. package/src/context/ChatContext.tsx +17 -4
  58. package/src/hooks/session/useSessionPin.ts +31 -0
  59. package/src/hooks/upload/useUploadItem.ts +3 -0
  60. package/src/services/endpoints.ts +4 -0
  61. package/src/translation/resources/i18n.ts +10 -2
  62. package/src/types/dto.ts +1 -0
  63. package/src/types/ui.ts +7 -1
@@ -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
  });
@@ -173,7 +173,7 @@ const BottomSheet = forwardRef<WithBottomSheetProps>((_, ref) => {
173
173
  <KLabel.Text
174
174
  typo={subTitle.typo || 'TextSmNormal'}
175
175
  color={subTitle.color || KColors.gray.light}
176
- numberOfLines={2}
176
+ numberOfLines={data?.header?.subTitle?.numberOfLines || 2}
177
177
  marginT="0.25rem"
178
178
  >
179
179
  {subTitle.text}
@@ -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';
@@ -7,6 +7,7 @@ export const QUERY_KEYS = {
7
7
  UPDATE_SESSION: 'UPDATE_SESSION',
8
8
  SHARE_SESSION: 'SHARE_SESSION',
9
9
  DELETE_SESSION: 'DELETE_SESSION',
10
+ SESSION_PIN: 'SESSION_PIN',
10
11
  SEND_FEEDBACK: 'SEND_FEEDBACK',
11
12
  GET_EXTERNAL_SESSION_INFO: 'GET_EXTERNAL_SESSION_INFO',
12
13
  };
@@ -1,10 +1,13 @@
1
1
  import { createContext, useContext, useEffect, useRef, useState } from 'react';
2
+ import { StyleSheet } from 'react-native';
2
3
  import type { ChatContextType, ChatProviderProps } from '../types/chat';
3
4
  import ChatBotAI from '../components/chat';
4
5
  import Portal from '../components/portal';
5
6
  import ReanimatedDrawerExample from '../components/Drawer';
6
7
  import useSessionStore from '../store/session';
7
8
  import useStreamMessageStore from '../store/streamMessage';
9
+ import { Z_INDEX_PRIORITY } from '../constants';
10
+ import { KContainer } from '@droppii/libs';
8
11
 
9
12
  export const ChatContext = createContext<ChatContextType>({
10
13
  apiAddress: '',
@@ -26,6 +29,14 @@ export const ChatContext = createContext<ChatContextType>({
26
29
 
27
30
  export const useChatContext = () => useContext(ChatContext);
28
31
 
32
+ const styles = StyleSheet.create({
33
+ root: { flex: 1 },
34
+ portalLayer: {
35
+ ...StyleSheet.absoluteFillObject,
36
+ zIndex: Z_INDEX_PRIORITY.popup,
37
+ },
38
+ });
39
+
29
40
  export const ChatProvider = (props: ChatProviderProps) => {
30
41
  const ref = useRef<any>(null);
31
42
  const spanRef = useRef<any>(null);
@@ -100,12 +111,14 @@ export const ChatProvider = (props: ChatProviderProps) => {
100
111
  setTabIndex,
101
112
  }}
102
113
  >
103
- <ReanimatedDrawerExample ref={ref}>
104
- <>
114
+ <KContainer.View style={styles.root}>
115
+ <ReanimatedDrawerExample ref={ref}>
105
116
  <ChatBotAI />
117
+ </ReanimatedDrawerExample>
118
+ <KContainer.View style={styles.portalLayer} pointerEvents="box-none">
106
119
  <Portal />
107
- </>
108
- </ReanimatedDrawerExample>
120
+ </KContainer.View>
121
+ </KContainer.View>
109
122
  </ChatContext.Provider>
110
123
  );
111
124
  };
@@ -0,0 +1,31 @@
1
+ import { useMutation, useQueryClient } from '@tanstack/react-query';
2
+ import { QUERY_KEYS } from '../../constants/query';
3
+ import { apiInstance } from '../../services/apis';
4
+ import { ENDPOINTS } from '../../services/endpoints';
5
+ import { BaseResponse } from '../../types/common';
6
+
7
+ export const useSessionPin = () => {
8
+ const queryClient = useQueryClient();
9
+
10
+ return useMutation({
11
+ mutationKey: [QUERY_KEYS.SESSION_PIN],
12
+ mutationFn: async ({
13
+ sessionId,
14
+ pin,
15
+ }: {
16
+ sessionId: string;
17
+ pin: boolean;
18
+ }) => {
19
+ const url = pin
20
+ ? ENDPOINTS.assistantService.pinSession(sessionId)
21
+ : ENDPOINTS.assistantService.unpinSession(sessionId);
22
+ const res = await apiInstance?.put<BaseResponse<unknown>>(url);
23
+ return res?.data;
24
+ },
25
+ onSuccess: () => {
26
+ queryClient.refetchQueries({
27
+ queryKey: [QUERY_KEYS.SEARCH_SESSIONS],
28
+ });
29
+ },
30
+ });
31
+ };
@@ -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 }),
@@ -13,6 +13,10 @@ export const ENDPOINTS = {
13
13
  `/assistant-service/v1/app/chat/sessions/${sessionId}/share`,
14
14
  deleteSession: (sessionId: string) =>
15
15
  `/assistant-service/v1/app/chat/sessions/${sessionId}`,
16
+ pinSession: (sessionId: string) =>
17
+ `/assistant-service/v1/app/chat/sessions/${sessionId}/pin`,
18
+ unpinSession: (sessionId: string) =>
19
+ `/assistant-service/v1/app/chat/sessions/${sessionId}/unpin`,
16
20
  sendFeedback: (sessionId: string) =>
17
21
  `/assistant-service/v1/app/chat/sessions/${sessionId}/feedback`,
18
22
  generateAudio: (sessionId: string, messageId: string) =>
@@ -5,14 +5,22 @@ 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',
11
+ session_pin: 'Ghim',
12
+ session_unpin: 'Bỏ ghim',
13
13
  session_rename: 'Đổi tên',
14
14
  session_share: 'Chia sẻ',
15
15
  session_delete: 'Xoá',
16
+ pin_session_success: 'Đã ghim phiên chat',
17
+ unpin_session_success: 'Đã bỏ ghim phiên chat',
18
+
19
+ // Attachment bottom sheet
20
+ attachment_options_title: 'Tuỳ chọn thêm',
21
+ attachment_photo_library: 'Thư viện ảnh',
22
+ attachment_camera: 'Chụp ảnh',
23
+ attachment_document: 'Tài liệu',
16
24
 
17
25
  // Rename session
18
26
  rename_session_title: 'Đổi tên phiên chat',
package/src/types/dto.ts CHANGED
@@ -104,6 +104,7 @@ export interface SessionSearchItem {
104
104
  created_at: string;
105
105
  updated_at: string;
106
106
  metadata: Record<string, any>;
107
+ pinned_at?: string;
107
108
  }
108
109
 
109
110
  export interface SearchSessionsRequest {
package/src/types/ui.ts CHANGED
@@ -14,8 +14,14 @@ export interface WithToastProps {
14
14
  }
15
15
 
16
16
  export interface KBottomSheetPropsEnhance extends KBottomSheetProps {
17
- header: KBottomSheetProps['header'] & {
17
+ header?: NonNullable<KBottomSheetProps['header']> & {
18
18
  customRenderer?: (dismiss: () => void) => JSX.Element;
19
+
20
+ subTitle?: NonNullable<
21
+ NonNullable<KBottomSheetProps['header']>['subTitle']
22
+ > & {
23
+ numberOfLines?: number;
24
+ };
19
25
  };
20
26
  }
21
27