react-native-chatbot-ai 0.1.0 → 0.1.2
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/assets/svgIcon/IconChatArrow.js +0 -1
- package/lib/module/assets/svgIcon/IconChatArrow.js.map +1 -1
- package/lib/module/assets/svgIcon/IconPdf.js +27 -0
- package/lib/module/assets/svgIcon/IconPdf.js.map +1 -0
- package/lib/module/assets/svgIcon/IconThinkingStep.js +0 -1
- package/lib/module/assets/svgIcon/IconThinkingStep.js.map +1 -1
- package/lib/module/components/chat/ChatEmpty.js +6 -1
- package/lib/module/components/chat/ChatEmpty.js.map +1 -1
- package/lib/module/components/chat/ChatMessageList.js +33 -6
- package/lib/module/components/chat/ChatMessageList.js.map +1 -1
- package/lib/module/components/chat/footer/index.js +328 -0
- package/lib/module/components/chat/footer/index.js.map +1 -0
- package/lib/module/components/chat/footer/item/UploadFileItem.js +163 -0
- package/lib/module/components/chat/footer/item/UploadFileItem.js.map +1 -0
- package/lib/module/components/chat/footer/item/UploadImageItem.js +94 -0
- package/lib/module/components/chat/footer/item/UploadImageItem.js.map +1 -0
- package/lib/module/components/chat/index.js +1 -1
- package/lib/module/components/chat/index.js.map +1 -1
- package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js +114 -32
- package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js.map +1 -1
- package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js +18 -7
- package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js.map +1 -1
- package/lib/module/components/chat/item/ChatUserMessageItem.js +122 -15
- package/lib/module/components/chat/item/ChatUserMessageItem.js.map +1 -1
- package/lib/module/components/portal/Toast.js +193 -0
- package/lib/module/components/portal/Toast.js.map +1 -0
- package/lib/module/components/portal/index.js +15 -0
- package/lib/module/components/portal/index.js.map +1 -0
- package/lib/module/constants/events.js +2 -1
- package/lib/module/constants/events.js.map +1 -1
- package/lib/module/constants/index.js +9 -0
- package/lib/module/constants/index.js.map +1 -0
- package/lib/module/context/ChatContext.js +8 -5
- package/lib/module/context/ChatContext.js.map +1 -1
- package/lib/module/hooks/message/useMessage.js +0 -1
- package/lib/module/hooks/message/useMessage.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +3 -3
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/upload/useFileUpload.js +94 -0
- package/lib/module/hooks/upload/useFileUpload.js.map +1 -0
- package/lib/module/hooks/upload/useImageUpload.js +92 -0
- package/lib/module/hooks/upload/useImageUpload.js.map +1 -0
- package/lib/module/hooks/useAndroidBackHandler.js +20 -0
- package/lib/module/hooks/useAndroidBackHandler.js.map +1 -0
- package/lib/module/services/endpoints.js +3 -0
- package/lib/module/services/endpoints.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/ui.js +4 -0
- package/lib/module/types/ui.js.map +1 -0
- package/lib/module/utils/common.js +31 -0
- package/lib/module/utils/common.js.map +1 -0
- package/lib/module/utils/device.js +137 -0
- package/lib/module/utils/device.js.map +1 -0
- package/lib/module/utils/ui.js +28 -0
- package/lib/module/utils/ui.js.map +1 -0
- package/lib/typescript/src/assets/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/assets/svgIcon/IconChatArrow.d.ts.map +1 -1
- package/lib/typescript/src/assets/svgIcon/IconPdf.d.ts +7 -0
- package/lib/typescript/src/assets/svgIcon/IconPdf.d.ts.map +1 -0
- package/lib/typescript/src/assets/svgIcon/IconThinkingStep.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/ChatEmpty.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/ChatMessageList.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/footer/index.d.ts +16 -0
- package/lib/typescript/src/components/chat/footer/index.d.ts.map +1 -0
- package/lib/typescript/src/components/chat/footer/item/UploadFileItem.d.ts +9 -0
- package/lib/typescript/src/components/chat/footer/item/UploadFileItem.d.ts.map +1 -0
- package/lib/typescript/src/components/chat/footer/item/UploadImageItem.d.ts +9 -0
- package/lib/typescript/src/components/chat/footer/item/UploadImageItem.d.ts.map +1 -0
- package/lib/typescript/src/components/chat/item/ChatAIAnswerMessageItem.d.ts +9 -0
- package/lib/typescript/src/components/chat/item/ChatAIAnswerMessageItem.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/item/ChatAIThinkingMessageItem.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/item/ChatUserMessageItem.d.ts.map +1 -1
- package/lib/typescript/src/components/portal/Toast.d.ts +4 -0
- package/lib/typescript/src/components/portal/Toast.d.ts.map +1 -0
- package/lib/typescript/src/components/portal/index.d.ts +3 -0
- package/lib/typescript/src/components/portal/index.d.ts.map +1 -0
- package/lib/typescript/src/constants/events.d.ts +1 -0
- package/lib/typescript/src/constants/events.d.ts.map +1 -1
- package/lib/typescript/src/constants/index.d.ts +6 -0
- package/lib/typescript/src/constants/index.d.ts.map +1 -0
- package/lib/typescript/src/context/ChatContext.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts +2 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/upload/useFileUpload.d.ts +15 -0
- package/lib/typescript/src/hooks/upload/useFileUpload.d.ts.map +1 -0
- package/lib/typescript/src/hooks/upload/useImageUpload.d.ts +15 -0
- package/lib/typescript/src/hooks/upload/useImageUpload.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useAndroidBackHandler.d.ts +4 -0
- package/lib/typescript/src/hooks/useAndroidBackHandler.d.ts.map +1 -0
- 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/types/chat.d.ts +6 -0
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/types/dto.d.ts +10 -1
- 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/ui.d.ts +7 -0
- package/lib/typescript/src/types/ui.d.ts.map +1 -0
- package/lib/typescript/src/utils/common.d.ts +10 -0
- package/lib/typescript/src/utils/common.d.ts.map +1 -0
- package/lib/typescript/src/utils/device.d.ts +11 -0
- package/lib/typescript/src/utils/device.d.ts.map +1 -0
- package/lib/typescript/src/utils/ui.d.ts +12 -0
- package/lib/typescript/src/utils/ui.d.ts.map +1 -0
- package/package.json +11 -6
- package/src/assets/icons/index.ts +1 -1
- package/src/assets/svgIcon/IconChatArrow.tsx +1 -7
- package/src/assets/svgIcon/IconPdf.tsx +26 -0
- package/src/assets/svgIcon/IconThinkingStep.tsx +1 -7
- package/src/components/chat/ChatEmpty.tsx +5 -2
- package/src/components/chat/ChatMessageList.tsx +39 -5
- package/src/components/chat/footer/index.tsx +410 -0
- package/src/components/chat/footer/item/UploadFileItem.tsx +181 -0
- package/src/components/chat/footer/item/UploadImageItem.tsx +91 -0
- package/src/components/chat/index.tsx +1 -1
- package/src/components/chat/item/ChatAIAnswerMessageItem.tsx +152 -54
- package/src/components/chat/item/ChatAIThinkingMessageItem.tsx +37 -31
- package/src/components/chat/item/ChatUserMessageItem.tsx +145 -13
- package/src/components/portal/Toast.tsx +315 -0
- package/src/components/portal/index.tsx +13 -0
- package/src/constants/events.ts +1 -0
- package/src/constants/index.ts +9 -0
- package/src/context/ChatContext.tsx +6 -2
- package/src/hooks/message/useMessage.ts +0 -1
- package/src/hooks/message/useSendMessage.ts +4 -4
- package/src/hooks/upload/useFileUpload.ts +126 -0
- package/src/hooks/upload/useImageUpload.ts +123 -0
- package/src/hooks/useAndroidBackHandler.ts +29 -0
- package/src/services/endpoints.ts +3 -0
- package/src/types/chat.ts +2 -0
- package/src/types/dto.ts +16 -1
- package/src/types/index.ts +1 -0
- package/src/types/ui.ts +12 -0
- package/src/utils/common.ts +40 -0
- package/src/utils/device.ts +170 -0
- package/src/utils/ui.tsx +32 -0
- package/lib/module/components/chat/ChatFooter.js +0 -91
- package/lib/module/components/chat/ChatFooter.js.map +0 -1
- package/lib/typescript/src/components/chat/ChatFooter.d.ts +0 -3
- package/lib/typescript/src/components/chat/ChatFooter.d.ts.map +0 -1
- package/src/components/chat/ChatFooter.tsx +0 -99
package/src/types/chat.ts
CHANGED
|
@@ -5,12 +5,14 @@ export interface ChatContextType {
|
|
|
5
5
|
apiAddress: string;
|
|
6
6
|
userId: string;
|
|
7
7
|
cartButton?: JSX.Element;
|
|
8
|
+
openImageViewer?: (images: { url: string }[], index: number) => void;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export interface ChatProviderProps {
|
|
11
12
|
apiAddress: string;
|
|
12
13
|
userId: string;
|
|
13
14
|
cartButton?: JSX.Element;
|
|
15
|
+
openImageViewer?: (images: { url: string }[], index: number) => void;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export interface SessionStore {
|
package/src/types/dto.ts
CHANGED
|
@@ -11,6 +11,21 @@ export interface SuggetionResponse {
|
|
|
11
11
|
suggestions: ISuggestionItem[];
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
export interface IAttachment {
|
|
15
|
+
type: 'image' | 'file';
|
|
16
|
+
source_type: 'url';
|
|
17
|
+
data: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
size?: number;
|
|
20
|
+
loading?: boolean;
|
|
21
|
+
mime_type:
|
|
22
|
+
| 'image/jpeg'
|
|
23
|
+
| 'image/png'
|
|
24
|
+
| 'image/webp'
|
|
25
|
+
| 'image/jpg'
|
|
26
|
+
| 'application/pdf';
|
|
27
|
+
}
|
|
28
|
+
|
|
14
29
|
export interface IMessageItem {
|
|
15
30
|
id: string;
|
|
16
31
|
content: string;
|
|
@@ -22,7 +37,7 @@ export interface IMessageItem {
|
|
|
22
37
|
metadata: Record<string, any>;
|
|
23
38
|
created_at: string;
|
|
24
39
|
modified_at: string;
|
|
25
|
-
attachments:
|
|
40
|
+
attachments: IAttachment[];
|
|
26
41
|
}
|
|
27
42
|
|
|
28
43
|
export interface SessionDetailResponse {
|
package/src/types/index.ts
CHANGED
package/src/types/ui.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import { KToastBarProps } from '@droppii/libs';
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
5
|
+
|
|
6
|
+
export interface WithToastProps {
|
|
7
|
+
open: (
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
payload: KToastBarProps & { contentContainerStyle?: StyleProp<ViewStyle> }
|
|
10
|
+
) => void;
|
|
11
|
+
dismiss: () => void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const isSameFile = (a: any, b: any) =>
|
|
2
|
+
a.filename === b.filename && a.size === b.size && a.mime === b.mime;
|
|
3
|
+
|
|
4
|
+
export const formatFileSize = (bytes: number): string => {
|
|
5
|
+
if (bytes === 0) return '0 B';
|
|
6
|
+
|
|
7
|
+
const k = 1024;
|
|
8
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
9
|
+
|
|
10
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
11
|
+
const size = parseFloat((bytes / Math.pow(k, i)).toFixed(2));
|
|
12
|
+
|
|
13
|
+
return `${size} ${sizes[i]}`;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
interface ShortenOptions {
|
|
17
|
+
maxLength?: number;
|
|
18
|
+
keepStart?: number;
|
|
19
|
+
keepEnd?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const shortenFileName = (name: string, options: ShortenOptions = {}) => {
|
|
23
|
+
const { maxLength = 30, keepStart = 8, keepEnd = 2 } = options;
|
|
24
|
+
|
|
25
|
+
if (name.length <= maxLength) return name;
|
|
26
|
+
|
|
27
|
+
const dotIndex = name.lastIndexOf('.');
|
|
28
|
+
const ext = dotIndex !== -1 ? name.slice(dotIndex) : '';
|
|
29
|
+
const base = dotIndex !== -1 ? name.slice(0, dotIndex) : name;
|
|
30
|
+
|
|
31
|
+
// Tính toán độ dài phần đầu & cuối
|
|
32
|
+
const available = maxLength - ext.length - 3; // trừ "...”
|
|
33
|
+
const startLen = keepStart ?? Math.floor(available / 2);
|
|
34
|
+
const endLen = keepEnd ?? Math.floor(available / 2);
|
|
35
|
+
|
|
36
|
+
const start = base.slice(0, startLen);
|
|
37
|
+
const end = base.slice(-endLen);
|
|
38
|
+
|
|
39
|
+
return `${start}...${end}${ext}`;
|
|
40
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { DocumentPickerOptions, pick } from '@react-native-documents/picker';
|
|
2
|
+
import UIUtils from '../utils/ui';
|
|
3
|
+
import { PermissionsAndroid, Platform } from 'react-native';
|
|
4
|
+
import {
|
|
5
|
+
Image,
|
|
6
|
+
openCamera,
|
|
7
|
+
openPicker,
|
|
8
|
+
Options,
|
|
9
|
+
PossibleArray,
|
|
10
|
+
} from 'react-native-image-crop-picker';
|
|
11
|
+
import { check, PERMISSIONS, request } from 'react-native-permissions';
|
|
12
|
+
|
|
13
|
+
type MediaType<O> = O extends { mediaType: 'photo' } ? Image : never;
|
|
14
|
+
|
|
15
|
+
const READ_MEDIA_IMAGES = 'android.permission.READ_MEDIA_IMAGES';
|
|
16
|
+
|
|
17
|
+
const pickerOptions = {
|
|
18
|
+
writeTempFile: true,
|
|
19
|
+
mediaType: 'photo',
|
|
20
|
+
compressImageQuality: 0.8,
|
|
21
|
+
width: 1280,
|
|
22
|
+
height: 1280,
|
|
23
|
+
compressImageMaxHeight: 1280,
|
|
24
|
+
compressImageMaxWidth: 1280,
|
|
25
|
+
cropping: false,
|
|
26
|
+
cropperCircleOverlay: true,
|
|
27
|
+
waitAnimationEnd: true,
|
|
28
|
+
includeExif: false,
|
|
29
|
+
forceJpg: true,
|
|
30
|
+
cropperChooseText: 'Hoàn tất',
|
|
31
|
+
cropperCancelText: 'Hủy',
|
|
32
|
+
} as Options;
|
|
33
|
+
|
|
34
|
+
const requestPermission = async (
|
|
35
|
+
perm: any,
|
|
36
|
+
requestMessage?: string,
|
|
37
|
+
disableToast = false
|
|
38
|
+
) => {
|
|
39
|
+
try {
|
|
40
|
+
//handle android function check can't return status code blocked
|
|
41
|
+
let granted =
|
|
42
|
+
Platform.OS === 'android' ? await request(perm) : await check(perm);
|
|
43
|
+
if (granted === 'unavailable') {
|
|
44
|
+
UIUtils.toast.open({
|
|
45
|
+
title: 'Tính năng hiện tại không khả dụng, vui lòng thử lại sau',
|
|
46
|
+
});
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (granted === 'granted' || granted === 'limited') {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
if (granted === 'denied' && Platform.OS === 'ios') {
|
|
53
|
+
const result = await request(perm);
|
|
54
|
+
if (result === 'granted' || result === 'limited') {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (requestMessage && granted === 'blocked') {
|
|
59
|
+
UIUtils.toast.open({
|
|
60
|
+
title: requestMessage,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return false;
|
|
65
|
+
} catch (err) {
|
|
66
|
+
if (!disableToast) {
|
|
67
|
+
UIUtils.toast.open({
|
|
68
|
+
title: 'Có lỗi xảy ra, vui lòng thử lại',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const requestReadPhotoPermission = async (disableToast = false) => {
|
|
75
|
+
const perm = Platform.select({
|
|
76
|
+
ios: PERMISSIONS.IOS.PHOTO_LIBRARY,
|
|
77
|
+
default:
|
|
78
|
+
(Platform.Version as number) >= 33
|
|
79
|
+
? READ_MEDIA_IMAGES
|
|
80
|
+
: PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
|
|
81
|
+
});
|
|
82
|
+
return requestPermission(
|
|
83
|
+
perm as any,
|
|
84
|
+
'Vui lòng cấp quyền truy cập vào "Thư viện ảnh" của bạn trước khi sử dụng tính năng này',
|
|
85
|
+
disableToast
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const requestCameraPermission = async () => {
|
|
90
|
+
const perm = Platform.select({
|
|
91
|
+
ios: PERMISSIONS.IOS.CAMERA,
|
|
92
|
+
default: PERMISSIONS.ANDROID.CAMERA,
|
|
93
|
+
});
|
|
94
|
+
return requestPermission(perm, 'Droppii cần truy cập vào "Máy ảnh" của bạn');
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const openImagePicker = (
|
|
98
|
+
options?: Options
|
|
99
|
+
): Promise<PossibleArray<Options, MediaType<Options>> | undefined> => {
|
|
100
|
+
return new Promise(async (resolve) => {
|
|
101
|
+
try {
|
|
102
|
+
const isGranted = await requestReadPhotoPermission();
|
|
103
|
+
if (!isGranted) {
|
|
104
|
+
throw new Error('No permission');
|
|
105
|
+
}
|
|
106
|
+
const value = await openPicker({
|
|
107
|
+
...pickerOptions,
|
|
108
|
+
...options,
|
|
109
|
+
});
|
|
110
|
+
resolve(value);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
resolve(undefined);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const openImageMultiplePicker = (
|
|
118
|
+
options?: Options
|
|
119
|
+
): Promise<PossibleArray<Options, MediaType<Options>[]> | undefined> => {
|
|
120
|
+
return new Promise(async (resolve) => {
|
|
121
|
+
try {
|
|
122
|
+
const isGranted = await requestReadPhotoPermission();
|
|
123
|
+
if (!isGranted) {
|
|
124
|
+
throw new Error('No permission');
|
|
125
|
+
}
|
|
126
|
+
const value = await openPicker({
|
|
127
|
+
...pickerOptions,
|
|
128
|
+
...options,
|
|
129
|
+
multiple: true,
|
|
130
|
+
});
|
|
131
|
+
resolve(value);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
resolve([]);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export const openCameraPicker = (
|
|
139
|
+
options?: Options
|
|
140
|
+
): Promise<PossibleArray<Options, MediaType<Options>> | undefined> => {
|
|
141
|
+
return new Promise(async (resolve) => {
|
|
142
|
+
try {
|
|
143
|
+
const isGranted = await requestCameraPermission();
|
|
144
|
+
if (!isGranted) {
|
|
145
|
+
throw new Error('No permission');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const value = await openCamera({
|
|
149
|
+
...pickerOptions,
|
|
150
|
+
...options,
|
|
151
|
+
});
|
|
152
|
+
resolve(value);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
resolve(undefined);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const openDocumentPicker = async (options?: DocumentPickerOptions) => {
|
|
160
|
+
try {
|
|
161
|
+
const [result] = await pick({
|
|
162
|
+
mode: 'open',
|
|
163
|
+
...options,
|
|
164
|
+
});
|
|
165
|
+
console.log(result);
|
|
166
|
+
return result;
|
|
167
|
+
} catch (err) {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
};
|
package/src/utils/ui.tsx
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import { toastRef } from '../constants';
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
import type { KToastBarProps } from '@droppii/libs';
|
|
6
|
+
|
|
7
|
+
class UIUtils {
|
|
8
|
+
toast = {
|
|
9
|
+
open: (
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
params: KToastBarProps & { contentContainerStyle?: StyleProp<ViewStyle> }
|
|
12
|
+
) => {
|
|
13
|
+
toastRef.current?.open(params);
|
|
14
|
+
},
|
|
15
|
+
dismiss: () => {
|
|
16
|
+
toastRef.current?.dismiss();
|
|
17
|
+
},
|
|
18
|
+
showError: (error: any, withToast = true) => {
|
|
19
|
+
const msg =
|
|
20
|
+
error?.message ||
|
|
21
|
+
error?.response?.message ||
|
|
22
|
+
error?.data?.message ||
|
|
23
|
+
error?.response?.data?.message ||
|
|
24
|
+
'Có lỗi xảy ra, vui lòng thử lại';
|
|
25
|
+
withToast &&
|
|
26
|
+
toastRef.current?.open({ title: msg, theme: 'danger', stretch: true });
|
|
27
|
+
return msg;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default new UIUtils();
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { KButton, KColors, KContainer, KImage, KInput, KSpacingValue } from '@droppii/libs';
|
|
4
|
-
import { useCallback, useState } from 'react';
|
|
5
|
-
import { StyleSheet } from 'react-native';
|
|
6
|
-
import debounce from 'lodash/debounce';
|
|
7
|
-
import { useSendMessage } from "../../hooks/message/useSendMessage.js";
|
|
8
|
-
import useStreamMessageStore from "../../store/streamMessage.js";
|
|
9
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
-
const ChatFooter = () => {
|
|
11
|
-
const {
|
|
12
|
-
onSendMessage,
|
|
13
|
-
stopStream
|
|
14
|
-
} = useSendMessage();
|
|
15
|
-
const [message, setMessage] = useState('');
|
|
16
|
-
const isStreaming = useStreamMessageStore(state => state.isStreaming);
|
|
17
|
-
const debouncedMessage = debounce(message => {
|
|
18
|
-
setMessage(message);
|
|
19
|
-
}, 200);
|
|
20
|
-
const onPressSend = useCallback(() => {
|
|
21
|
-
if (isStreaming) {
|
|
22
|
-
stopStream();
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
onSendMessage(message?.trim());
|
|
26
|
-
setMessage('');
|
|
27
|
-
}, [message, isStreaming, onSendMessage, stopStream]);
|
|
28
|
-
return /*#__PURE__*/_jsxs(KContainer.View, {
|
|
29
|
-
style: styles.container,
|
|
30
|
-
children: [/*#__PURE__*/_jsx(KInput.TextArea, {
|
|
31
|
-
paddingV: '0.25rem',
|
|
32
|
-
paddingH: '0.25rem',
|
|
33
|
-
placeholder: "B\u1EA1n mu\u1ED1n h\u1ECFi g\xEC h\xF4m nay?",
|
|
34
|
-
clearButtonMode: "hidden",
|
|
35
|
-
onChangeText: debouncedMessage,
|
|
36
|
-
value: message,
|
|
37
|
-
multiline: true,
|
|
38
|
-
style: styles.input,
|
|
39
|
-
blurOnSubmit: false,
|
|
40
|
-
textAlignVertical: "top"
|
|
41
|
-
}), /*#__PURE__*/_jsxs(KContainer.View, {
|
|
42
|
-
style: styles.actions,
|
|
43
|
-
children: [/*#__PURE__*/_jsx(KImage.VectorIcons, {
|
|
44
|
-
name: "image-o",
|
|
45
|
-
size: 24,
|
|
46
|
-
color: KColors.gray.dark
|
|
47
|
-
}), /*#__PURE__*/_jsx(KImage.VectorIcons, {
|
|
48
|
-
name: "paperclip-o",
|
|
49
|
-
size: 24,
|
|
50
|
-
color: KColors.gray.dark
|
|
51
|
-
}), /*#__PURE__*/_jsx(KContainer.View, {
|
|
52
|
-
flex: true
|
|
53
|
-
}), /*#__PURE__*/_jsx(KButton.Solid, {
|
|
54
|
-
kind: "primary",
|
|
55
|
-
icon: {
|
|
56
|
-
vectorName: isStreaming ? 'square-b' : 'send-b',
|
|
57
|
-
size: 20,
|
|
58
|
-
tintColor: KColors.white
|
|
59
|
-
},
|
|
60
|
-
onPress: onPressSend,
|
|
61
|
-
br: "round",
|
|
62
|
-
disabled: !isStreaming && message.trim() === ''
|
|
63
|
-
})]
|
|
64
|
-
})]
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
export default ChatFooter;
|
|
68
|
-
const styles = StyleSheet.create({
|
|
69
|
-
container: {
|
|
70
|
-
paddingHorizontal: KSpacingValue['0.75rem'],
|
|
71
|
-
paddingVertical: KSpacingValue['0.5rem'],
|
|
72
|
-
gap: KSpacingValue['0.5rem'],
|
|
73
|
-
borderWidth: 1,
|
|
74
|
-
borderColor: KColors.hexToRgba(KColors.black, 0.15),
|
|
75
|
-
borderBottomWidth: 0,
|
|
76
|
-
borderTopLeftRadius: KSpacingValue['1.25rem'],
|
|
77
|
-
borderTopRightRadius: KSpacingValue['1.25rem']
|
|
78
|
-
},
|
|
79
|
-
actions: {
|
|
80
|
-
flexDirection: 'row',
|
|
81
|
-
alignItems: 'center',
|
|
82
|
-
gap: KSpacingValue['1rem']
|
|
83
|
-
},
|
|
84
|
-
sendButton: {
|
|
85
|
-
alignSelf: 'flex-end'
|
|
86
|
-
},
|
|
87
|
-
input: {
|
|
88
|
-
maxHeight: 100
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
//# sourceMappingURL=ChatFooter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["KButton","KColors","KContainer","KImage","KInput","KSpacingValue","useCallback","useState","StyleSheet","debounce","useSendMessage","useStreamMessageStore","jsx","_jsx","jsxs","_jsxs","ChatFooter","onSendMessage","stopStream","message","setMessage","isStreaming","state","debouncedMessage","onPressSend","trim","View","style","styles","container","children","TextArea","paddingV","paddingH","placeholder","clearButtonMode","onChangeText","value","multiline","input","blurOnSubmit","textAlignVertical","actions","VectorIcons","name","size","color","gray","dark","flex","Solid","kind","icon","vectorName","tintColor","white","onPress","br","disabled","create","paddingHorizontal","paddingVertical","gap","borderWidth","borderColor","hexToRgba","black","borderBottomWidth","borderTopLeftRadius","borderTopRightRadius","flexDirection","alignItems","sendButton","alignSelf","maxHeight"],"sourceRoot":"../../../../src","sources":["components/chat/ChatFooter.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ChatFooter.d.ts","sourceRoot":"","sources":["../../../../../src/components/chat/ChatFooter.tsx"],"names":[],"mappings":"AAcA,QAAA,MAAM,UAAU,+CA0Df,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
KButton,
|
|
3
|
-
KColors,
|
|
4
|
-
KContainer,
|
|
5
|
-
KImage,
|
|
6
|
-
KInput,
|
|
7
|
-
KSpacingValue,
|
|
8
|
-
} from '@droppii/libs';
|
|
9
|
-
import { useCallback, useState } from 'react';
|
|
10
|
-
import { StyleSheet } from 'react-native';
|
|
11
|
-
import debounce from 'lodash/debounce';
|
|
12
|
-
import { useSendMessage } from '../../hooks/message/useSendMessage';
|
|
13
|
-
import useStreamMessageStore from '../../store/streamMessage';
|
|
14
|
-
|
|
15
|
-
const ChatFooter = () => {
|
|
16
|
-
const { onSendMessage, stopStream } = useSendMessage();
|
|
17
|
-
const [message, setMessage] = useState('');
|
|
18
|
-
const isStreaming = useStreamMessageStore((state) => state.isStreaming);
|
|
19
|
-
|
|
20
|
-
const debouncedMessage = debounce((message: string) => {
|
|
21
|
-
setMessage(message);
|
|
22
|
-
}, 200);
|
|
23
|
-
|
|
24
|
-
const onPressSend = useCallback(() => {
|
|
25
|
-
if (isStreaming) {
|
|
26
|
-
stopStream();
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
onSendMessage(message?.trim());
|
|
30
|
-
setMessage('');
|
|
31
|
-
}, [message, isStreaming, onSendMessage, stopStream]);
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<KContainer.View style={styles.container}>
|
|
35
|
-
<KInput.TextArea
|
|
36
|
-
paddingV={'0.25rem'}
|
|
37
|
-
paddingH={'0.25rem'}
|
|
38
|
-
placeholder="Bạn muốn hỏi gì hôm nay?"
|
|
39
|
-
clearButtonMode="hidden"
|
|
40
|
-
onChangeText={debouncedMessage}
|
|
41
|
-
value={message}
|
|
42
|
-
multiline
|
|
43
|
-
style={styles.input}
|
|
44
|
-
blurOnSubmit={false}
|
|
45
|
-
textAlignVertical="top"
|
|
46
|
-
/>
|
|
47
|
-
<KContainer.View style={styles.actions}>
|
|
48
|
-
<KImage.VectorIcons
|
|
49
|
-
name="image-o"
|
|
50
|
-
size={24}
|
|
51
|
-
color={KColors.gray.dark}
|
|
52
|
-
/>
|
|
53
|
-
<KImage.VectorIcons
|
|
54
|
-
name="paperclip-o"
|
|
55
|
-
size={24}
|
|
56
|
-
color={KColors.gray.dark}
|
|
57
|
-
/>
|
|
58
|
-
<KContainer.View flex />
|
|
59
|
-
<KButton.Solid
|
|
60
|
-
kind="primary"
|
|
61
|
-
icon={{
|
|
62
|
-
vectorName: isStreaming ? 'square-b' : 'send-b',
|
|
63
|
-
size: 20,
|
|
64
|
-
tintColor: KColors.white,
|
|
65
|
-
}}
|
|
66
|
-
onPress={onPressSend}
|
|
67
|
-
br="round"
|
|
68
|
-
disabled={!isStreaming && message.trim() === ''}
|
|
69
|
-
/>
|
|
70
|
-
</KContainer.View>
|
|
71
|
-
</KContainer.View>
|
|
72
|
-
);
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
export default ChatFooter;
|
|
76
|
-
|
|
77
|
-
const styles = StyleSheet.create({
|
|
78
|
-
container: {
|
|
79
|
-
paddingHorizontal: KSpacingValue['0.75rem'],
|
|
80
|
-
paddingVertical: KSpacingValue['0.5rem'],
|
|
81
|
-
gap: KSpacingValue['0.5rem'],
|
|
82
|
-
borderWidth: 1,
|
|
83
|
-
borderColor: KColors.hexToRgba(KColors.black, 0.15),
|
|
84
|
-
borderBottomWidth: 0,
|
|
85
|
-
borderTopLeftRadius: KSpacingValue['1.25rem'],
|
|
86
|
-
borderTopRightRadius: KSpacingValue['1.25rem'],
|
|
87
|
-
},
|
|
88
|
-
actions: {
|
|
89
|
-
flexDirection: 'row',
|
|
90
|
-
alignItems: 'center',
|
|
91
|
-
gap: KSpacingValue['1rem'],
|
|
92
|
-
},
|
|
93
|
-
sendButton: {
|
|
94
|
-
alignSelf: 'flex-end',
|
|
95
|
-
},
|
|
96
|
-
input: {
|
|
97
|
-
maxHeight: 100,
|
|
98
|
-
},
|
|
99
|
-
});
|