@droppii-org/chat-mobile 0.2.23 → 0.2.25
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/images/btn_resend.png +0 -0
- package/lib/module/assets/images/index.js +2 -1
- package/lib/module/assets/images/index.js.map +1 -1
- package/lib/module/components/AttachmentPreview/FilePreview.js +1 -1
- package/lib/module/components/AttachmentPreview/FilePreview.js.map +1 -1
- package/lib/module/components/messages/MessageStatusIndicator.js +70 -0
- package/lib/module/components/messages/MessageStatusIndicator.js.map +1 -0
- package/lib/module/components/messages/fileMessage/index.js.map +1 -1
- package/lib/module/components/messages/imageMessage/index.js +59 -50
- package/lib/module/components/messages/imageMessage/index.js.map +1 -1
- package/lib/module/components/messages/linkMessage/index.js +14 -6
- package/lib/module/components/messages/linkMessage/index.js.map +1 -1
- package/lib/module/components/messages/mergedMessage/index.js.map +1 -1
- package/lib/module/components/messages/textMessage/index.js +14 -6
- package/lib/module/components/messages/textMessage/index.js.map +1 -1
- package/lib/module/components/messages/videoMessage/index.js.map +1 -1
- package/lib/module/config/uploadLimits.js +13 -0
- package/lib/module/config/uploadLimits.js.map +1 -0
- package/lib/module/core/useChatListener.js +35 -4
- package/lib/module/core/useChatListener.js.map +1 -1
- package/lib/module/core/useUserListener.js +17 -7
- package/lib/module/core/useUserListener.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +62 -15
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/useChatCompose.js +153 -0
- package/lib/module/hooks/useChatCompose.js.map +1 -0
- package/lib/module/hooks/useChatMessages.js +39 -8
- package/lib/module/hooks/useChatMessages.js.map +1 -1
- package/lib/module/hooks/useFileAttachment.js +1 -1
- package/lib/module/hooks/useFileAttachment.js.map +1 -1
- package/lib/module/hooks/useFileDownload.js +1 -1
- package/lib/module/hooks/useFileDownload.js.map +1 -1
- package/lib/module/hooks/useImageAttachment.js +81 -152
- package/lib/module/hooks/useImageAttachment.js.map +1 -1
- package/lib/module/hooks/useSendAttachment.js +2 -2
- package/lib/module/hooks/useSendAttachment.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatComposer.js +50 -185
- package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetail.js +29 -137
- package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatListLegend.js +20 -15
- package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
- package/lib/module/screens/chat-detail/index.js +0 -1
- package/lib/module/screens/chat-detail/index.js.map +1 -1
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js +18 -13
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js.map +1 -1
- package/lib/module/services/attachmentHandlers/fileAttachmentHandler.js +2 -2
- package/lib/module/services/attachmentHandlers/fileAttachmentHandler.js.map +1 -1
- package/lib/module/services/attachmentHandlers/imageAttachmentHandler.js +3 -3
- package/lib/module/services/attachmentHandlers/imageAttachmentHandler.js.map +1 -1
- package/lib/module/services/attachmentHandlers/videoAttachmentHandler.js +2 -1
- package/lib/module/services/attachmentHandlers/videoAttachmentHandler.js.map +1 -1
- package/lib/module/services/attachmentOrchestrator.js +40 -17
- package/lib/module/services/attachmentOrchestrator.js.map +1 -1
- package/lib/module/services/message.js +13 -5
- package/lib/module/services/message.js.map +1 -1
- package/lib/module/translation/resources/i18n.js +4 -3
- package/lib/module/translation/resources/i18n.js.map +1 -1
- package/lib/module/types/chat.js.map +1 -1
- package/lib/module/types/global.d.js +2 -0
- package/lib/module/types/global.d.js.map +1 -0
- package/lib/module/types/index.d.js +3 -0
- package/lib/module/types/index.d.js.map +1 -0
- package/lib/module/utils/UIUtils.js +37 -0
- package/lib/module/utils/UIUtils.js.map +1 -0
- package/lib/module/utils/imageUtils.js +3 -3
- package/lib/module/utils/imageUtils.js.map +1 -1
- package/lib/module/utils/pLimit.js +19 -0
- package/lib/module/utils/pLimit.js.map +1 -0
- package/lib/module/utils/videoThumbnail.js +8 -3
- package/lib/module/utils/videoThumbnail.js.map +1 -1
- package/lib/module/utils/videoThumbnailUpload.js +76 -0
- package/lib/module/utils/videoThumbnailUpload.js.map +1 -0
- package/lib/typescript/src/assets/images/index.d.ts +1 -0
- package/lib/typescript/src/assets/images/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/MessageStatusIndicator.d.ts +9 -0
- package/lib/typescript/src/components/messages/MessageStatusIndicator.d.ts.map +1 -0
- package/lib/typescript/src/components/messages/fileMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/imageMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/linkMessage/index.d.ts +3 -8
- package/lib/typescript/src/components/messages/linkMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/mergedMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/textMessage/index.d.ts +2 -8
- package/lib/typescript/src/components/messages/textMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/videoMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/config/uploadLimits.d.ts +7 -0
- package/lib/typescript/src/config/uploadLimits.d.ts.map +1 -0
- package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
- package/lib/typescript/src/core/useUserListener.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts +2 -0
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useChatCompose.d.ts +27 -0
- package/lib/typescript/src/hooks/useChatCompose.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useChatMessages.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useImageAttachment.d.ts +2 -2
- package/lib/typescript/src/hooks/useImageAttachment.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useSendAttachment.d.ts +1 -1
- package/lib/typescript/src/hooks/useSendAttachment.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts +5 -2
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts +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 +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/index.d.ts +0 -2
- package/lib/typescript/src/screens/chat-detail/index.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts +3 -5
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/types.d.ts +1 -35
- package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentHandlers/fileAttachmentHandler.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentHandlers/imageAttachmentHandler.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentHandlers/videoAttachmentHandler.d.ts.map +1 -1
- package/lib/typescript/src/services/attachmentOrchestrator.d.ts +1 -1
- package/lib/typescript/src/services/attachmentOrchestrator.d.ts.map +1 -1
- package/lib/typescript/src/services/message.d.ts +7 -0
- package/lib/typescript/src/services/message.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 -0
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/utils/UIUtils.d.ts +4 -0
- package/lib/typescript/src/utils/UIUtils.d.ts.map +1 -0
- package/lib/typescript/src/utils/imageUtils.d.ts.map +1 -1
- package/lib/typescript/src/utils/pLimit.d.ts +6 -0
- package/lib/typescript/src/utils/pLimit.d.ts.map +1 -0
- package/lib/typescript/src/utils/videoThumbnail.d.ts.map +1 -1
- package/lib/typescript/src/utils/videoThumbnailUpload.d.ts +11 -0
- package/lib/typescript/src/utils/videoThumbnailUpload.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/assets/images/btn_resend.png +0 -0
- package/src/assets/images/index.ts +1 -0
- package/src/components/AttachmentPreview/FilePreview.tsx +1 -1
- package/src/components/messages/MessageStatusIndicator.tsx +82 -0
- package/src/components/messages/fileMessage/index.tsx +0 -1
- package/src/components/messages/imageMessage/index.tsx +71 -57
- package/src/components/messages/linkMessage/index.tsx +13 -19
- package/src/components/messages/mergedMessage/index.tsx +0 -1
- package/src/components/messages/textMessage/index.tsx +13 -18
- package/src/components/messages/videoMessage/index.tsx +0 -1
- package/src/config/uploadLimits.ts +11 -0
- package/src/core/useChatListener.ts +38 -4
- package/src/core/useUserListener.ts +17 -7
- package/src/hooks/message/useSendMessage.ts +103 -24
- package/src/hooks/useChatCompose.ts +195 -0
- package/src/hooks/useChatMessages.ts +54 -10
- package/src/hooks/useFileAttachment.ts +1 -1
- package/src/hooks/useFileDownload.ts +1 -1
- package/src/hooks/useImageAttachment.ts +120 -199
- package/src/hooks/useSendAttachment.ts +3 -6
- package/src/index.tsx +3 -5
- package/src/screens/chat-detail/ChatComposer.tsx +88 -240
- package/src/screens/chat-detail/ChatDetail.tsx +36 -195
- package/src/screens/chat-detail/ChatListLegend.tsx +16 -13
- package/src/screens/chat-detail/index.ts +1 -5
- package/src/screens/chat-detail/legend/LegendChatMessage.tsx +19 -12
- package/src/screens/chat-detail/types.ts +1 -38
- package/src/services/attachmentHandlers/fileAttachmentHandler.ts +3 -2
- package/src/services/attachmentHandlers/imageAttachmentHandler.ts +6 -3
- package/src/services/attachmentHandlers/videoAttachmentHandler.ts +2 -1
- package/src/services/attachmentOrchestrator.ts +49 -27
- package/src/services/message.ts +21 -4
- package/src/translation/resources/i18n.ts +6 -3
- package/src/types/chat.ts +6 -0
- package/src/types/global.d.ts +299 -0
- package/src/types/index.d.ts +1 -0
- package/src/utils/UIUtils.ts +31 -0
- package/src/utils/imageUtils.ts +3 -4
- package/src/utils/pLimit.ts +20 -0
- package/src/utils/videoThumbnail.ts +10 -3
- package/src/utils/videoThumbnailUpload.ts +103 -0
- package/lib/module/hooks/useVideoAttachment.js +0 -251
- package/lib/module/hooks/useVideoAttachment.js.map +0 -1
- package/lib/module/screens/chat-detail/hooks/useAttachmentSendHandler.js +0 -288
- package/lib/module/screens/chat-detail/hooks/useAttachmentSendHandler.js.map +0 -1
- package/lib/module/utils/giftedChatMessage.js +0 -90
- package/lib/module/utils/giftedChatMessage.js.map +0 -1
- package/lib/module/utils/ui.js +0 -17
- package/lib/module/utils/ui.js.map +0 -1
- package/lib/typescript/src/hooks/useVideoAttachment.d.ts +0 -29
- package/lib/typescript/src/hooks/useVideoAttachment.d.ts.map +0 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentSendHandler.d.ts +0 -26
- package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentSendHandler.d.ts.map +0 -1
- package/lib/typescript/src/utils/giftedChatMessage.d.ts +0 -10
- package/lib/typescript/src/utils/giftedChatMessage.d.ts.map +0 -1
- package/lib/typescript/src/utils/ui.d.ts +0 -13
- package/lib/typescript/src/utils/ui.d.ts.map +0 -1
- package/src/hooks/useVideoAttachment.ts +0 -334
- package/src/screens/chat-detail/hooks/useAttachmentSendHandler.ts +0 -386
- package/src/utils/giftedChatMessage.ts +0 -137
- package/src/utils/ui.ts +0 -19
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import OpenIMSDK, {
|
|
1
|
+
import OpenIMSDK, {
|
|
2
|
+
MessageStatus,
|
|
3
|
+
type MessageItem,
|
|
4
|
+
} from '@droppii/openim-rn-client-sdk';
|
|
5
|
+
|
|
2
6
|
import type {
|
|
3
7
|
Attachment,
|
|
4
8
|
AttachmentSendOptions,
|
|
@@ -6,6 +10,7 @@ import type {
|
|
|
6
10
|
} from '../types/attachment';
|
|
7
11
|
import { getAttachmentHandler } from '../types/attachmentHandler';
|
|
8
12
|
import { useConversationStore } from '../store';
|
|
13
|
+
import { useMessageStore } from '../store/message';
|
|
9
14
|
import {
|
|
10
15
|
getAttachmentPriorityConfig,
|
|
11
16
|
type AttachmentType,
|
|
@@ -15,8 +20,7 @@ export namespace AttachmentOrchestratorService {
|
|
|
15
20
|
export async function sendPreparedAttachments(
|
|
16
21
|
attachments: Attachment[],
|
|
17
22
|
uploadedUrls: Record<string, string>,
|
|
18
|
-
options: AttachmentSendOptions = { strategy: 'individual' }
|
|
19
|
-
onMessageSent?: (message: any) => void
|
|
23
|
+
options: AttachmentSendOptions = { strategy: 'individual' }
|
|
20
24
|
): Promise<AttachmentSendResult> {
|
|
21
25
|
const result: AttachmentSendResult = {
|
|
22
26
|
success: false,
|
|
@@ -30,7 +34,6 @@ export namespace AttachmentOrchestratorService {
|
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
// 1. Validate all attachments
|
|
33
|
-
console.log('[AttachmentOrchestrator] Validating prepared attachments...');
|
|
34
37
|
for (const att of attachments) {
|
|
35
38
|
try {
|
|
36
39
|
const handler = getAttachmentHandler(att.type);
|
|
@@ -90,8 +93,7 @@ export namespace AttachmentOrchestratorService {
|
|
|
90
93
|
try {
|
|
91
94
|
const mergedMsgId = await sendMergedMessage(
|
|
92
95
|
payloads.map((p) => p.payload),
|
|
93
|
-
options.includeCaption
|
|
94
|
-
onMessageSent
|
|
96
|
+
options.includeCaption
|
|
95
97
|
);
|
|
96
98
|
console.log('[AttachmentOrchestrator] Messages sent via merger:', {
|
|
97
99
|
messageId: mergedMsgId,
|
|
@@ -116,8 +118,7 @@ export namespace AttachmentOrchestratorService {
|
|
|
116
118
|
|
|
117
119
|
async function sendMergedMessage(
|
|
118
120
|
payloads: unknown[],
|
|
119
|
-
_caption?: string
|
|
120
|
-
onMessageSent?: (message: any) => void
|
|
121
|
+
_caption?: string
|
|
121
122
|
): Promise<string> {
|
|
122
123
|
const currentConversation = useConversationStore
|
|
123
124
|
.getState()
|
|
@@ -269,32 +270,53 @@ export namespace AttachmentOrchestratorService {
|
|
|
269
270
|
}
|
|
270
271
|
);
|
|
271
272
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
console.log(
|
|
275
|
-
'[AttachmentOrchestrator] Sending message',
|
|
276
|
-
i + 1,
|
|
277
|
-
'of',
|
|
278
|
-
allMessages.length
|
|
279
|
-
);
|
|
273
|
+
const recvID = currentConversation.userID || '';
|
|
274
|
+
const groupID = currentConversation.groupID || '';
|
|
280
275
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
276
|
+
// Push all messages as "Sending" immediately so the user sees every
|
|
277
|
+
// bubble right away, instead of waiting for each network call in turn.
|
|
278
|
+
for (const m of allMessages) {
|
|
279
|
+
useMessageStore.getState().pushNewMessage({
|
|
280
|
+
...(m as MessageItem),
|
|
281
|
+
status: MessageStatus.Sending,
|
|
285
282
|
});
|
|
283
|
+
}
|
|
286
284
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
285
|
+
const sendResults = await Promise.allSettled(
|
|
286
|
+
allMessages.map(async (m) => {
|
|
287
|
+
const message = m as MessageItem;
|
|
288
|
+
const result = await OpenIMSDK.sendMessageNotOss({
|
|
289
|
+
recvID,
|
|
290
|
+
groupID,
|
|
291
|
+
message,
|
|
292
|
+
});
|
|
292
293
|
|
|
293
|
-
|
|
294
|
-
|
|
294
|
+
if (result) {
|
|
295
|
+
useMessageStore.getState().deleteOneMessage(message.clientMsgID);
|
|
296
|
+
useMessageStore.getState().pushNewMessage(result);
|
|
297
|
+
}
|
|
298
|
+
return result?.clientMsgID || result?.serverMsgID || '';
|
|
299
|
+
})
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
let firstSendError: unknown;
|
|
303
|
+
for (let i = 0; i < sendResults.length; i++) {
|
|
304
|
+
const settled = sendResults[i]!;
|
|
305
|
+
if (settled.status === 'fulfilled') {
|
|
306
|
+
lastMsgId = settled.value || lastMsgId;
|
|
307
|
+
} else {
|
|
308
|
+
firstSendError = firstSendError ?? settled.reason;
|
|
309
|
+
useMessageStore.getState().updateOneMessage({
|
|
310
|
+
...(allMessages[i] as MessageItem),
|
|
311
|
+
status: MessageStatus.Failed,
|
|
312
|
+
});
|
|
295
313
|
}
|
|
296
314
|
}
|
|
297
315
|
|
|
316
|
+
if (!lastMsgId && firstSendError) {
|
|
317
|
+
throw firstSendError;
|
|
318
|
+
}
|
|
319
|
+
|
|
298
320
|
return lastMsgId;
|
|
299
321
|
}
|
|
300
322
|
}
|
package/src/services/message.ts
CHANGED
|
@@ -20,16 +20,15 @@ export namespace ChatMessageAPI {
|
|
|
20
20
|
count?: number;
|
|
21
21
|
startClientMsgID?: string;
|
|
22
22
|
lastMinSeq?: number;
|
|
23
|
+
applicationType?: string;
|
|
23
24
|
}
|
|
24
25
|
): Promise<HistoryMessageResult> {
|
|
25
|
-
return OpenIMSDK.
|
|
26
|
+
return OpenIMSDK.getAdvancedHistoryMessageListApp({
|
|
26
27
|
conversationID,
|
|
27
28
|
count: options?.count ?? DEFAULT_PAGE_SIZE,
|
|
28
29
|
startClientMsgID: options?.startClientMsgID ?? '',
|
|
29
30
|
viewType: ViewType.History,
|
|
30
|
-
|
|
31
|
-
// ? { lastMinSeq: options.lastMinSeq ?? 0 }
|
|
32
|
-
// : {}),
|
|
31
|
+
applicationType: options?.applicationType ?? '',
|
|
33
32
|
}) as Promise<HistoryMessageResult>;
|
|
34
33
|
}
|
|
35
34
|
|
|
@@ -50,6 +49,24 @@ export namespace ChatMessageAPI {
|
|
|
50
49
|
return sentMessage;
|
|
51
50
|
}
|
|
52
51
|
|
|
52
|
+
export async function searchLocalMessages(
|
|
53
|
+
conversationID: string,
|
|
54
|
+
options?: {
|
|
55
|
+
keywordList?: string[];
|
|
56
|
+
messageTypeList?: number[];
|
|
57
|
+
pageIndex?: number;
|
|
58
|
+
count?: number;
|
|
59
|
+
}
|
|
60
|
+
) {
|
|
61
|
+
return OpenIMSDK.searchLocalMessages({
|
|
62
|
+
conversationID,
|
|
63
|
+
keywordList: options?.keywordList ?? ['a'],
|
|
64
|
+
messageTypeList: options?.messageTypeList,
|
|
65
|
+
pageIndex: options?.pageIndex ?? 1,
|
|
66
|
+
count: options?.count ?? 20,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
53
70
|
export async function markConversationAsRead(conversationID: string) {
|
|
54
71
|
return OpenIMSDK.markConversationMessageAsRead(conversationID);
|
|
55
72
|
}
|
|
@@ -11,10 +11,13 @@ const i18nKey: Record<string, string> = {
|
|
|
11
11
|
'chat:file_download_failed': 'Tải tệp thất bại',
|
|
12
12
|
'chat:file_open_failed': 'Không thể mở tệp này',
|
|
13
13
|
'chat:image_preview': 'Xem trước ảnh',
|
|
14
|
-
'chat:image_too_large':
|
|
15
|
-
|
|
14
|
+
'chat:image_too_large':
|
|
15
|
+
'Hình ảnh tải lên không hợp lệ. Kích thước hình ảnh không được vượt quá {{maxSize}}MB',
|
|
16
|
+
'chat:video_too_large':
|
|
17
|
+
'Video tải lên không hợp lệ. Kích thước video không được vượt quá {{maxSize}}MB',
|
|
16
18
|
'chat:image_sent': 'Đã gửi ảnh',
|
|
17
|
-
'chat:image_upload_failed': '
|
|
19
|
+
'chat:image_upload_failed': 'Có lỗi xảy ra vui lòng thử lại',
|
|
20
|
+
'chat:generic_error': 'Có lỗi xảy ra vui lòng thử lại',
|
|
18
21
|
'chat:failed_to_send_message': 'Không thể gửi tin nhắn. Thử lại?',
|
|
19
22
|
'chat:filename': 'Tên tệp',
|
|
20
23
|
'chat:file_size': 'Kích thước',
|
package/src/types/chat.ts
CHANGED
|
@@ -20,6 +20,12 @@ type LogGA = (
|
|
|
20
20
|
provider?: `${keyof typeof EventProvider}`
|
|
21
21
|
) => void;
|
|
22
22
|
|
|
23
|
+
export interface ChatUIAdapter {
|
|
24
|
+
toast?: { open: (params: any) => void };
|
|
25
|
+
alert?: { open: (params: any) => void };
|
|
26
|
+
popup?: { open: (params: any) => void };
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
export interface ChatContextType {
|
|
24
30
|
logGA?: LogGA;
|
|
25
31
|
applicationType: DChatApplicationType;
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
declare module 'UIUtils' {
|
|
2
|
+
import type { ParamListBase, NavigationProp } from '@react-navigation/native';
|
|
3
|
+
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
|
|
4
|
+
import type { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
|
|
5
|
+
import type { HeaderOptions, Layout } from '@react-navigation/elements';
|
|
6
|
+
import type {
|
|
7
|
+
KAlertProps,
|
|
8
|
+
KBottomSheetProps,
|
|
9
|
+
KHeaderNavigationProps,
|
|
10
|
+
KPopupProps,
|
|
11
|
+
KToastBarProps,
|
|
12
|
+
} from '@droppii/libs';
|
|
13
|
+
import type {
|
|
14
|
+
ActionSheetIOSOptions,
|
|
15
|
+
StyleProp,
|
|
16
|
+
ViewStyle,
|
|
17
|
+
} from 'react-native';
|
|
18
|
+
|
|
19
|
+
export interface KBottomSheetPropsEnhance extends KBottomSheetProps {
|
|
20
|
+
header: KBottomSheetProps['header'] & {
|
|
21
|
+
customRenderer?: (dismiss: () => void) => JSX.Element;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface ScreenConfigProps {
|
|
26
|
+
__config: any;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface MonthPickerValue {
|
|
30
|
+
month?: number;
|
|
31
|
+
year?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface KActionSheetProps extends ActionSheetIOSOptions {
|
|
35
|
+
callback: (index: number) => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface WithActionSheetProps {
|
|
39
|
+
open: (payload: KActionSheetProps) => void;
|
|
40
|
+
dismiss: () => void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface WithAlertDialogProps {
|
|
44
|
+
open: (payload: KAlertProps) => void;
|
|
45
|
+
dismiss: () => void;
|
|
46
|
+
dismissAll: () => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface WithPopupProps {
|
|
50
|
+
open: (payload: KPopupProps) => void;
|
|
51
|
+
dismiss: () => void;
|
|
52
|
+
dismissAll: () => void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface WithBottomSheetProps {
|
|
56
|
+
open: (payload: KBottomSheetPropsEnhance) => void;
|
|
57
|
+
dismiss: () => void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface WithToastProps {
|
|
61
|
+
open: (
|
|
62
|
+
payload: KToastBarProps & { contentContainerStyle?: StyleProp<ViewStyle> }
|
|
63
|
+
) => void;
|
|
64
|
+
dismiss: () => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface WithImageViewer {
|
|
68
|
+
open: (payload: ImageViewerParams) => void;
|
|
69
|
+
dismiss: () => void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface WithModal {
|
|
73
|
+
open: (payload: JSX.Element) => void;
|
|
74
|
+
dismiss: () => void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface IButton {
|
|
78
|
+
text: string;
|
|
79
|
+
onPress?: () => void;
|
|
80
|
+
skipUI?: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface IDialogParams {
|
|
84
|
+
title: string;
|
|
85
|
+
message?: string;
|
|
86
|
+
buttons?: Array<IButton>;
|
|
87
|
+
cancelIndex?: number;
|
|
88
|
+
icon?: any;
|
|
89
|
+
renderContent?: any;
|
|
90
|
+
ignoreStack?: boolean;
|
|
91
|
+
waitForDismiss?: boolean;
|
|
92
|
+
touchOutsideToDismiss?: boolean;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type AddressLevel = 'province' | 'district' | 'ward';
|
|
96
|
+
|
|
97
|
+
export type CameraType = 'avatar' | 'identity-front' | 'identity-back';
|
|
98
|
+
|
|
99
|
+
export interface RequestCameraParams {
|
|
100
|
+
cameraType: CameraType;
|
|
101
|
+
onCaptured: (path: string) => void;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface IHeaderParams extends KHeaderNavigationProps {
|
|
105
|
+
onBack?: () => void;
|
|
106
|
+
isNested?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export type Appearance = 'dark' | 'light';
|
|
110
|
+
|
|
111
|
+
export interface IModalParams {
|
|
112
|
+
Screen: React.ComponentType<any>;
|
|
113
|
+
screenProps?: any;
|
|
114
|
+
headerProps?: HeaderOptions & {
|
|
115
|
+
title?: string;
|
|
116
|
+
modal?: boolean;
|
|
117
|
+
layout?: Layout;
|
|
118
|
+
tintColor?: string;
|
|
119
|
+
noHeader?: boolean;
|
|
120
|
+
};
|
|
121
|
+
options?: {
|
|
122
|
+
disableGesture?: boolean;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export type NavigationBase = NavigationProp<ParamListBase, string, undefined>;
|
|
127
|
+
|
|
128
|
+
export interface StackScreenProps
|
|
129
|
+
extends
|
|
130
|
+
NativeStackScreenProps<ParamListBase, string, undefined>,
|
|
131
|
+
ScreenConfigProps {}
|
|
132
|
+
|
|
133
|
+
export interface TabScreenProps
|
|
134
|
+
extends
|
|
135
|
+
BottomTabScreenProps<ParamListBase, string, undefined>,
|
|
136
|
+
ScreenConfigProps {}
|
|
137
|
+
|
|
138
|
+
export interface TextModifiers {
|
|
139
|
+
fontSize?: number;
|
|
140
|
+
color?: string;
|
|
141
|
+
textCenter?: boolean;
|
|
142
|
+
fontFamily?: string;
|
|
143
|
+
fontStyle?: 'normal' | 'italic';
|
|
144
|
+
bold?: boolean;
|
|
145
|
+
letterSpacing?: number;
|
|
146
|
+
underline?: true;
|
|
147
|
+
underlineColor?: string;
|
|
148
|
+
textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase';
|
|
149
|
+
darkModeColor?: string;
|
|
150
|
+
typo?: TypographyModifiers;
|
|
151
|
+
textAlign?: 'center' | 'left' | 'right';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface LayoutModifiers {
|
|
155
|
+
flex?: number | true;
|
|
156
|
+
flexS?: number;
|
|
157
|
+
flexG?: number;
|
|
158
|
+
flexD?: 'row' | 'column' | 'row-reverse' | 'column-reverse';
|
|
159
|
+
flexW?: 'wrap' | 'nowrap' | 'wrap-reverse';
|
|
160
|
+
alignItems?:
|
|
161
|
+
| true
|
|
162
|
+
| 'flex-start'
|
|
163
|
+
| 'flex-end'
|
|
164
|
+
| 'center'
|
|
165
|
+
| 'stretch'
|
|
166
|
+
| 'baseline';
|
|
167
|
+
alignSelf?:
|
|
168
|
+
| true
|
|
169
|
+
| 'auto'
|
|
170
|
+
| 'flex-start'
|
|
171
|
+
| 'flex-end'
|
|
172
|
+
| 'center'
|
|
173
|
+
| 'stretch'
|
|
174
|
+
| 'baseline';
|
|
175
|
+
justifyContent?:
|
|
176
|
+
| true
|
|
177
|
+
| 'flex-start'
|
|
178
|
+
| 'flex-end'
|
|
179
|
+
| 'center'
|
|
180
|
+
| 'space-between'
|
|
181
|
+
| 'space-around'
|
|
182
|
+
| 'space-evenly';
|
|
183
|
+
center?: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface SpacingModifiers {
|
|
187
|
+
padding?: number | string;
|
|
188
|
+
paddingL?: number | string;
|
|
189
|
+
paddingR?: number | string;
|
|
190
|
+
paddingT?: number | string;
|
|
191
|
+
paddingB?: number | string;
|
|
192
|
+
paddingH?: number | string;
|
|
193
|
+
paddingV?: number | string;
|
|
194
|
+
margin?: number;
|
|
195
|
+
marginL?: number | string | 'auto';
|
|
196
|
+
marginR?: number | string | 'auto';
|
|
197
|
+
marginT?: number | string | 'auto';
|
|
198
|
+
marginB?: number | string | 'auto';
|
|
199
|
+
marginH?: number | string | 'auto';
|
|
200
|
+
marginV?: number | string | 'auto';
|
|
201
|
+
width?: number | string;
|
|
202
|
+
height?: number | string;
|
|
203
|
+
minW?: number | string;
|
|
204
|
+
maxW?: number | string;
|
|
205
|
+
minH?: number | string;
|
|
206
|
+
maxH?: number | string;
|
|
207
|
+
sizeWH?: number;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export interface StylingModifiers {
|
|
211
|
+
background?: string;
|
|
212
|
+
opacity?: number;
|
|
213
|
+
br?: number;
|
|
214
|
+
brW?: number;
|
|
215
|
+
brC?: string;
|
|
216
|
+
brTL?: number;
|
|
217
|
+
brTR?: number;
|
|
218
|
+
brBL?: number;
|
|
219
|
+
brBR?: number;
|
|
220
|
+
brBW?: number;
|
|
221
|
+
brTW?: number;
|
|
222
|
+
brLW?: number;
|
|
223
|
+
brRW?: number;
|
|
224
|
+
brBC?: string;
|
|
225
|
+
brTC?: string;
|
|
226
|
+
brLC?: string;
|
|
227
|
+
brRC?: string;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface TestModifiers {
|
|
231
|
+
testID?: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export type TypographyModifiers =
|
|
235
|
+
| 'H1'
|
|
236
|
+
| 'H2'
|
|
237
|
+
| 'H3'
|
|
238
|
+
| 'H4'
|
|
239
|
+
| 'H5'
|
|
240
|
+
| 'H6'
|
|
241
|
+
| 'H7'
|
|
242
|
+
| 'B1'
|
|
243
|
+
| 'P1'
|
|
244
|
+
| 'P2'
|
|
245
|
+
| 'P3'
|
|
246
|
+
| 'S1'
|
|
247
|
+
| 'S2'
|
|
248
|
+
| 'S3'
|
|
249
|
+
| 'C1'
|
|
250
|
+
| 'C2'
|
|
251
|
+
| 'C3'
|
|
252
|
+
| 'A1'
|
|
253
|
+
| 'A2'
|
|
254
|
+
| 'A3';
|
|
255
|
+
|
|
256
|
+
export interface IProductMedia {
|
|
257
|
+
url?: string;
|
|
258
|
+
isVideo?: boolean;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export interface ImageViewerParams {
|
|
262
|
+
images: IProductMedia[];
|
|
263
|
+
initIndex?: number;
|
|
264
|
+
download?: boolean;
|
|
265
|
+
pagination?: boolean;
|
|
266
|
+
logParams?: any;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export type PickerType = 'all' | 'issue-place';
|
|
270
|
+
|
|
271
|
+
export interface DistrictEnhance {
|
|
272
|
+
wards?: Record<string, { name?: string; code?: string }>;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export interface ProvinceEnhance {
|
|
276
|
+
districts?: Record<string, DistrictEnhance>;
|
|
277
|
+
wards?: Record<string, { name?: string; code?: string }>;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface PickedAddress {
|
|
281
|
+
province: { name?: string; code?: string } | undefined;
|
|
282
|
+
district?: { name?: string; code?: string } | undefined;
|
|
283
|
+
ward: { name?: string; code?: string } | undefined;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export interface ImperativeProgress {
|
|
287
|
+
setProgress: (p: number) => void;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export interface InternalWebviewScreenProps {
|
|
291
|
+
closeVisible?: boolean;
|
|
292
|
+
closeColor?: string;
|
|
293
|
+
uri: string;
|
|
294
|
+
showAsYoutubePlayer?: boolean;
|
|
295
|
+
showNavigation?: boolean;
|
|
296
|
+
swipeToDismiss?: boolean;
|
|
297
|
+
hasEncode?: boolean;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference path="./global.d.ts" />
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Alert } from 'react-native';
|
|
2
|
+
import type { ChatUIAdapter } from '../types/chat';
|
|
3
|
+
|
|
4
|
+
const openWithAlert = (params: { title?: string; message?: string }) => {
|
|
5
|
+
const { title = 'Message', message = '' } = params || {};
|
|
6
|
+
Alert.alert(title, message);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const defaultAdapter: Required<ChatUIAdapter> = {
|
|
10
|
+
toast: { open: openWithAlert },
|
|
11
|
+
alert: { open: openWithAlert },
|
|
12
|
+
popup: { open: openWithAlert },
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let _adapter: ChatUIAdapter = {};
|
|
16
|
+
|
|
17
|
+
export const registerUIUtils = (adapter: ChatUIAdapter): void => {
|
|
18
|
+
_adapter = adapter;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const UIUtils: Required<ChatUIAdapter> = {
|
|
22
|
+
toast: {
|
|
23
|
+
open: (params) => (_adapter.toast ?? defaultAdapter.toast).open(params),
|
|
24
|
+
},
|
|
25
|
+
alert: {
|
|
26
|
+
open: (params) => (_adapter.alert ?? defaultAdapter.alert).open(params),
|
|
27
|
+
},
|
|
28
|
+
popup: {
|
|
29
|
+
open: (params) => (_adapter.popup ?? defaultAdapter.popup).open(params),
|
|
30
|
+
},
|
|
31
|
+
};
|
package/src/utils/imageUtils.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ImageFile } from '../types/imageUpload';
|
|
2
2
|
import Images from '../assets/images';
|
|
3
|
+
import { UPLOAD_LIMITS } from '../config/uploadLimits';
|
|
3
4
|
|
|
4
5
|
export const generateUUID = (): string => {
|
|
5
6
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
@@ -81,10 +82,8 @@ export const formatFileSize = (bytes: number): string => {
|
|
|
81
82
|
};
|
|
82
83
|
|
|
83
84
|
export const validateImageFile = (file: ImageFile): string | null => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (file.size > MAX_SIZE) {
|
|
87
|
-
return `Image too large. Max ${formatFileSize(MAX_SIZE)}`;
|
|
85
|
+
if (file.size > UPLOAD_LIMITS.image) {
|
|
86
|
+
return `Image too large. Max ${formatFileSize(UPLOAD_LIMITS.image)}`;
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
const validMimes = [
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run `items` through `fn` with at most `concurrency` items in-flight at once.
|
|
3
|
+
* Errors per-item are swallowed — wrap `fn` if you need to capture them.
|
|
4
|
+
*/
|
|
5
|
+
export async function pLimit<T>(
|
|
6
|
+
items: T[],
|
|
7
|
+
fn: (item: T, index: number) => Promise<void>,
|
|
8
|
+
concurrency: number
|
|
9
|
+
): Promise<void> {
|
|
10
|
+
let idx = 0;
|
|
11
|
+
const worker = async () => {
|
|
12
|
+
while (idx < items.length) {
|
|
13
|
+
const i = idx++;
|
|
14
|
+
await fn(items[i]!, i);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
await Promise.all(
|
|
18
|
+
Array.from({ length: Math.min(concurrency, items.length) }, worker)
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -28,6 +28,9 @@ interface ThumbnailResult {
|
|
|
28
28
|
* The app strips "file://" before calling, so local videos fall into the broken
|
|
29
29
|
* branch. The fix is to KEEP the file:// scheme so the working overload is used.
|
|
30
30
|
*
|
|
31
|
+
* iOS is the opposite: AVAsset / react-native-create-thumbnail requires a bare
|
|
32
|
+
* path without any scheme prefix. Strip "file://" on iOS.
|
|
33
|
+
*
|
|
31
34
|
* For Android photo-picker synthetic paths we additionally copy the file into the
|
|
32
35
|
* app cache first (a clean, app-private file the retriever can always open) and
|
|
33
36
|
* still hand it back with a file:// prefix. Returns the path to pass to
|
|
@@ -36,9 +39,13 @@ interface ThumbnailResult {
|
|
|
36
39
|
const ensureRetrievableVideoPath = async (
|
|
37
40
|
videoPath: string
|
|
38
41
|
): Promise<{ path: string; cleanupPath: string | null }> => {
|
|
39
|
-
// iOS
|
|
42
|
+
// iOS AVAsset / react-native-create-thumbnail requires a bare file path
|
|
43
|
+
// without the file:// scheme. Strip it if present.
|
|
40
44
|
if (Platform.OS !== 'android') {
|
|
41
|
-
|
|
45
|
+
const barePath = videoPath.startsWith('file://')
|
|
46
|
+
? videoPath.slice('file://'.length)
|
|
47
|
+
: videoPath;
|
|
48
|
+
return { path: barePath, cleanupPath: null };
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
// content:// is handled by a dedicated native branch — pass through unchanged.
|
|
@@ -112,7 +119,6 @@ export const VideoThumbnailUtil = {
|
|
|
112
119
|
cacheName,
|
|
113
120
|
});
|
|
114
121
|
|
|
115
|
-
console.log('✅ [VideoThumbnail] THUMBNAIL PATH:', result.path);
|
|
116
122
|
console.log('[VideoThumbnail] Thumbnail generated', {
|
|
117
123
|
path: result.path,
|
|
118
124
|
width: result.width || 0,
|
|
@@ -147,6 +153,7 @@ export const VideoThumbnailUtil = {
|
|
|
147
153
|
}
|
|
148
154
|
},
|
|
149
155
|
|
|
156
|
+
// Serial by design — reduces memory pressure when processing multiple videos.
|
|
150
157
|
batchGenerateThumbnails: async (
|
|
151
158
|
videoPaths: string[],
|
|
152
159
|
options: ThumbnailOptions = {}
|