@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.
Files changed (194) hide show
  1. package/lib/module/assets/images/btn_resend.png +0 -0
  2. package/lib/module/assets/images/index.js +2 -1
  3. package/lib/module/assets/images/index.js.map +1 -1
  4. package/lib/module/components/AttachmentPreview/FilePreview.js +1 -1
  5. package/lib/module/components/AttachmentPreview/FilePreview.js.map +1 -1
  6. package/lib/module/components/messages/MessageStatusIndicator.js +70 -0
  7. package/lib/module/components/messages/MessageStatusIndicator.js.map +1 -0
  8. package/lib/module/components/messages/fileMessage/index.js.map +1 -1
  9. package/lib/module/components/messages/imageMessage/index.js +59 -50
  10. package/lib/module/components/messages/imageMessage/index.js.map +1 -1
  11. package/lib/module/components/messages/linkMessage/index.js +14 -6
  12. package/lib/module/components/messages/linkMessage/index.js.map +1 -1
  13. package/lib/module/components/messages/mergedMessage/index.js.map +1 -1
  14. package/lib/module/components/messages/textMessage/index.js +14 -6
  15. package/lib/module/components/messages/textMessage/index.js.map +1 -1
  16. package/lib/module/components/messages/videoMessage/index.js.map +1 -1
  17. package/lib/module/config/uploadLimits.js +13 -0
  18. package/lib/module/config/uploadLimits.js.map +1 -0
  19. package/lib/module/core/useChatListener.js +35 -4
  20. package/lib/module/core/useChatListener.js.map +1 -1
  21. package/lib/module/core/useUserListener.js +17 -7
  22. package/lib/module/core/useUserListener.js.map +1 -1
  23. package/lib/module/hooks/message/useSendMessage.js +62 -15
  24. package/lib/module/hooks/message/useSendMessage.js.map +1 -1
  25. package/lib/module/hooks/useChatCompose.js +153 -0
  26. package/lib/module/hooks/useChatCompose.js.map +1 -0
  27. package/lib/module/hooks/useChatMessages.js +39 -8
  28. package/lib/module/hooks/useChatMessages.js.map +1 -1
  29. package/lib/module/hooks/useFileAttachment.js +1 -1
  30. package/lib/module/hooks/useFileAttachment.js.map +1 -1
  31. package/lib/module/hooks/useFileDownload.js +1 -1
  32. package/lib/module/hooks/useFileDownload.js.map +1 -1
  33. package/lib/module/hooks/useImageAttachment.js +81 -152
  34. package/lib/module/hooks/useImageAttachment.js.map +1 -1
  35. package/lib/module/hooks/useSendAttachment.js +2 -2
  36. package/lib/module/hooks/useSendAttachment.js.map +1 -1
  37. package/lib/module/index.js +1 -1
  38. package/lib/module/index.js.map +1 -1
  39. package/lib/module/screens/chat-detail/ChatComposer.js +50 -185
  40. package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
  41. package/lib/module/screens/chat-detail/ChatDetail.js +29 -137
  42. package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
  43. package/lib/module/screens/chat-detail/ChatListLegend.js +20 -15
  44. package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
  45. package/lib/module/screens/chat-detail/index.js +0 -1
  46. package/lib/module/screens/chat-detail/index.js.map +1 -1
  47. package/lib/module/screens/chat-detail/legend/LegendChatMessage.js +18 -13
  48. package/lib/module/screens/chat-detail/legend/LegendChatMessage.js.map +1 -1
  49. package/lib/module/services/attachmentHandlers/fileAttachmentHandler.js +2 -2
  50. package/lib/module/services/attachmentHandlers/fileAttachmentHandler.js.map +1 -1
  51. package/lib/module/services/attachmentHandlers/imageAttachmentHandler.js +3 -3
  52. package/lib/module/services/attachmentHandlers/imageAttachmentHandler.js.map +1 -1
  53. package/lib/module/services/attachmentHandlers/videoAttachmentHandler.js +2 -1
  54. package/lib/module/services/attachmentHandlers/videoAttachmentHandler.js.map +1 -1
  55. package/lib/module/services/attachmentOrchestrator.js +40 -17
  56. package/lib/module/services/attachmentOrchestrator.js.map +1 -1
  57. package/lib/module/services/message.js +13 -5
  58. package/lib/module/services/message.js.map +1 -1
  59. package/lib/module/translation/resources/i18n.js +4 -3
  60. package/lib/module/translation/resources/i18n.js.map +1 -1
  61. package/lib/module/types/chat.js.map +1 -1
  62. package/lib/module/types/global.d.js +2 -0
  63. package/lib/module/types/global.d.js.map +1 -0
  64. package/lib/module/types/index.d.js +3 -0
  65. package/lib/module/types/index.d.js.map +1 -0
  66. package/lib/module/utils/UIUtils.js +37 -0
  67. package/lib/module/utils/UIUtils.js.map +1 -0
  68. package/lib/module/utils/imageUtils.js +3 -3
  69. package/lib/module/utils/imageUtils.js.map +1 -1
  70. package/lib/module/utils/pLimit.js +19 -0
  71. package/lib/module/utils/pLimit.js.map +1 -0
  72. package/lib/module/utils/videoThumbnail.js +8 -3
  73. package/lib/module/utils/videoThumbnail.js.map +1 -1
  74. package/lib/module/utils/videoThumbnailUpload.js +76 -0
  75. package/lib/module/utils/videoThumbnailUpload.js.map +1 -0
  76. package/lib/typescript/src/assets/images/index.d.ts +1 -0
  77. package/lib/typescript/src/assets/images/index.d.ts.map +1 -1
  78. package/lib/typescript/src/components/messages/MessageStatusIndicator.d.ts +9 -0
  79. package/lib/typescript/src/components/messages/MessageStatusIndicator.d.ts.map +1 -0
  80. package/lib/typescript/src/components/messages/fileMessage/index.d.ts.map +1 -1
  81. package/lib/typescript/src/components/messages/imageMessage/index.d.ts.map +1 -1
  82. package/lib/typescript/src/components/messages/linkMessage/index.d.ts +3 -8
  83. package/lib/typescript/src/components/messages/linkMessage/index.d.ts.map +1 -1
  84. package/lib/typescript/src/components/messages/mergedMessage/index.d.ts.map +1 -1
  85. package/lib/typescript/src/components/messages/textMessage/index.d.ts +2 -8
  86. package/lib/typescript/src/components/messages/textMessage/index.d.ts.map +1 -1
  87. package/lib/typescript/src/components/messages/videoMessage/index.d.ts.map +1 -1
  88. package/lib/typescript/src/config/uploadLimits.d.ts +7 -0
  89. package/lib/typescript/src/config/uploadLimits.d.ts.map +1 -0
  90. package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
  91. package/lib/typescript/src/core/useUserListener.d.ts.map +1 -1
  92. package/lib/typescript/src/hooks/message/useSendMessage.d.ts +2 -0
  93. package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
  94. package/lib/typescript/src/hooks/useChatCompose.d.ts +27 -0
  95. package/lib/typescript/src/hooks/useChatCompose.d.ts.map +1 -0
  96. package/lib/typescript/src/hooks/useChatMessages.d.ts.map +1 -1
  97. package/lib/typescript/src/hooks/useImageAttachment.d.ts +2 -2
  98. package/lib/typescript/src/hooks/useImageAttachment.d.ts.map +1 -1
  99. package/lib/typescript/src/hooks/useSendAttachment.d.ts +1 -1
  100. package/lib/typescript/src/hooks/useSendAttachment.d.ts.map +1 -1
  101. package/lib/typescript/src/index.d.ts +1 -2
  102. package/lib/typescript/src/index.d.ts.map +1 -1
  103. package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts +5 -2
  104. package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
  105. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts +1 -1
  106. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
  107. package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts +1 -1
  108. package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts.map +1 -1
  109. package/lib/typescript/src/screens/chat-detail/index.d.ts +0 -2
  110. package/lib/typescript/src/screens/chat-detail/index.d.ts.map +1 -1
  111. package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts +3 -5
  112. package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts.map +1 -1
  113. package/lib/typescript/src/screens/chat-detail/types.d.ts +1 -35
  114. package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
  115. package/lib/typescript/src/services/attachmentHandlers/fileAttachmentHandler.d.ts.map +1 -1
  116. package/lib/typescript/src/services/attachmentHandlers/imageAttachmentHandler.d.ts.map +1 -1
  117. package/lib/typescript/src/services/attachmentHandlers/videoAttachmentHandler.d.ts.map +1 -1
  118. package/lib/typescript/src/services/attachmentOrchestrator.d.ts +1 -1
  119. package/lib/typescript/src/services/attachmentOrchestrator.d.ts.map +1 -1
  120. package/lib/typescript/src/services/message.d.ts +7 -0
  121. package/lib/typescript/src/services/message.d.ts.map +1 -1
  122. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  123. package/lib/typescript/src/types/chat.d.ts +11 -0
  124. package/lib/typescript/src/types/chat.d.ts.map +1 -1
  125. package/lib/typescript/src/utils/UIUtils.d.ts +4 -0
  126. package/lib/typescript/src/utils/UIUtils.d.ts.map +1 -0
  127. package/lib/typescript/src/utils/imageUtils.d.ts.map +1 -1
  128. package/lib/typescript/src/utils/pLimit.d.ts +6 -0
  129. package/lib/typescript/src/utils/pLimit.d.ts.map +1 -0
  130. package/lib/typescript/src/utils/videoThumbnail.d.ts.map +1 -1
  131. package/lib/typescript/src/utils/videoThumbnailUpload.d.ts +11 -0
  132. package/lib/typescript/src/utils/videoThumbnailUpload.d.ts.map +1 -0
  133. package/package.json +2 -2
  134. package/src/assets/images/btn_resend.png +0 -0
  135. package/src/assets/images/index.ts +1 -0
  136. package/src/components/AttachmentPreview/FilePreview.tsx +1 -1
  137. package/src/components/messages/MessageStatusIndicator.tsx +82 -0
  138. package/src/components/messages/fileMessage/index.tsx +0 -1
  139. package/src/components/messages/imageMessage/index.tsx +71 -57
  140. package/src/components/messages/linkMessage/index.tsx +13 -19
  141. package/src/components/messages/mergedMessage/index.tsx +0 -1
  142. package/src/components/messages/textMessage/index.tsx +13 -18
  143. package/src/components/messages/videoMessage/index.tsx +0 -1
  144. package/src/config/uploadLimits.ts +11 -0
  145. package/src/core/useChatListener.ts +38 -4
  146. package/src/core/useUserListener.ts +17 -7
  147. package/src/hooks/message/useSendMessage.ts +103 -24
  148. package/src/hooks/useChatCompose.ts +195 -0
  149. package/src/hooks/useChatMessages.ts +54 -10
  150. package/src/hooks/useFileAttachment.ts +1 -1
  151. package/src/hooks/useFileDownload.ts +1 -1
  152. package/src/hooks/useImageAttachment.ts +120 -199
  153. package/src/hooks/useSendAttachment.ts +3 -6
  154. package/src/index.tsx +3 -5
  155. package/src/screens/chat-detail/ChatComposer.tsx +88 -240
  156. package/src/screens/chat-detail/ChatDetail.tsx +36 -195
  157. package/src/screens/chat-detail/ChatListLegend.tsx +16 -13
  158. package/src/screens/chat-detail/index.ts +1 -5
  159. package/src/screens/chat-detail/legend/LegendChatMessage.tsx +19 -12
  160. package/src/screens/chat-detail/types.ts +1 -38
  161. package/src/services/attachmentHandlers/fileAttachmentHandler.ts +3 -2
  162. package/src/services/attachmentHandlers/imageAttachmentHandler.ts +6 -3
  163. package/src/services/attachmentHandlers/videoAttachmentHandler.ts +2 -1
  164. package/src/services/attachmentOrchestrator.ts +49 -27
  165. package/src/services/message.ts +21 -4
  166. package/src/translation/resources/i18n.ts +6 -3
  167. package/src/types/chat.ts +6 -0
  168. package/src/types/global.d.ts +299 -0
  169. package/src/types/index.d.ts +1 -0
  170. package/src/utils/UIUtils.ts +31 -0
  171. package/src/utils/imageUtils.ts +3 -4
  172. package/src/utils/pLimit.ts +20 -0
  173. package/src/utils/videoThumbnail.ts +10 -3
  174. package/src/utils/videoThumbnailUpload.ts +103 -0
  175. package/lib/module/hooks/useVideoAttachment.js +0 -251
  176. package/lib/module/hooks/useVideoAttachment.js.map +0 -1
  177. package/lib/module/screens/chat-detail/hooks/useAttachmentSendHandler.js +0 -288
  178. package/lib/module/screens/chat-detail/hooks/useAttachmentSendHandler.js.map +0 -1
  179. package/lib/module/utils/giftedChatMessage.js +0 -90
  180. package/lib/module/utils/giftedChatMessage.js.map +0 -1
  181. package/lib/module/utils/ui.js +0 -17
  182. package/lib/module/utils/ui.js.map +0 -1
  183. package/lib/typescript/src/hooks/useVideoAttachment.d.ts +0 -29
  184. package/lib/typescript/src/hooks/useVideoAttachment.d.ts.map +0 -1
  185. package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentSendHandler.d.ts +0 -26
  186. package/lib/typescript/src/screens/chat-detail/hooks/useAttachmentSendHandler.d.ts.map +0 -1
  187. package/lib/typescript/src/utils/giftedChatMessage.d.ts +0 -10
  188. package/lib/typescript/src/utils/giftedChatMessage.d.ts.map +0 -1
  189. package/lib/typescript/src/utils/ui.d.ts +0 -13
  190. package/lib/typescript/src/utils/ui.d.ts.map +0 -1
  191. package/src/hooks/useVideoAttachment.ts +0 -334
  192. package/src/screens/chat-detail/hooks/useAttachmentSendHandler.ts +0 -386
  193. package/src/utils/giftedChatMessage.ts +0 -137
  194. package/src/utils/ui.ts +0 -19
@@ -1,386 +0,0 @@
1
- import { useCallback } from 'react';
2
- import RNFS from 'react-native-fs';
3
- import { isVideoFromPicker } from '../../../utils/imageUtils';
4
- import VideoThumbnailUtil from '../../../utils/videoThumbnail';
5
- import { ImageUploadAPI } from '../../../services/imageUpload';
6
- import UIUtils from '../../../utils/ui';
7
- import type { DMessageItem } from '../../../types/chat';
8
- import type { FileWithUploadStatus } from '../../../hooks/useFileAttachment';
9
-
10
- interface AttachmentItem {
11
- image: any;
12
- uploadedUrl?: string;
13
- uploadProgress?: number;
14
- error?: any;
15
- isUploading?: boolean;
16
- }
17
-
18
- interface UseAttachmentSendHandlerProps {
19
- selectedImages: AttachmentItem[];
20
- selectedFiles: FileWithUploadStatus[];
21
- sendAttachments: (
22
- items: any[],
23
- _: any,
24
- onMessageSent?: (message: DMessageItem) => void
25
- ) => Promise<boolean>;
26
- clearAllImages: () => void;
27
- clearAllFiles?: () => void;
28
- onSend?: () => void;
29
- onMessageSent?: (message: DMessageItem) => void;
30
- textMessage?: string;
31
- urlMetadata?: any;
32
- onSendText?: (text: string, urlMetadata?: any) => void;
33
- }
34
-
35
- export const useAttachmentSendHandler = ({
36
- selectedImages,
37
- selectedFiles,
38
- sendAttachments,
39
- clearAllImages,
40
- clearAllFiles,
41
- onSend,
42
- onMessageSent,
43
- textMessage,
44
- urlMetadata,
45
- onSendText,
46
- }: UseAttachmentSendHandlerProps) => {
47
- const handleSend = useCallback(async () => {
48
- console.log('[ChatComposer] handleSend called', {
49
- selectedImagesCount: selectedImages.length,
50
- selectedImagesData: selectedImages.map((img: any) => ({
51
- filename: img.image.filename,
52
- isUploading: img.isUploading,
53
- uploadedUrl: img.uploadedUrl ? 'SET' : 'MISSING',
54
- uploadProgress: img.uploadProgress,
55
- })),
56
- });
57
-
58
- // Separate images and videos from selectedImages
59
- const actualImages = selectedImages.filter(
60
- (img: any) => !isVideoFromPicker(img.image)
61
- );
62
- const videosFromGallery = selectedImages.filter((img: any) =>
63
- isVideoFromPicker(img.image)
64
- );
65
-
66
- console.log('🎬 [ChatComposer] Separation result:', {
67
- actualImagesCount: actualImages.length,
68
- videosFromGalleryCount: videosFromGallery.length,
69
- videosFromGalleryList: videosFromGallery.map((v: any) => ({
70
- filename: v.image.filename,
71
- uploadedUrl: v.uploadedUrl,
72
- })),
73
- });
74
-
75
- const uploadedImages = actualImages.filter((img: any) => img.uploadedUrl);
76
- const uploadedVideosFromGallery = videosFromGallery.filter(
77
- (vid: any) => vid.uploadedUrl
78
- );
79
-
80
- // Auto-generate thumbnails for gallery videos
81
- // Use unique ID per video to avoid race conditions and path mismatches
82
- const galleryVideoThumbnails: Record<
83
- string,
84
- { url: string; size: number }
85
- > = {};
86
- const failedVideos: string[] = []; // Track failed videos
87
-
88
- if (uploadedVideosFromGallery.length > 0) {
89
- console.log(
90
- '[ChatComposer] Auto-generating thumbnails for gallery videos...'
91
- );
92
-
93
- for (let idx = 0; idx < uploadedVideosFromGallery.length; idx++) {
94
- const vidItem = uploadedVideosFromGallery[idx]!;
95
- const videoId = vidItem.uploadedUrl || `video-${idx}`; // Use unique ID instead of path
96
- let cachedVideoPath: string | null = null;
97
-
98
- try {
99
- const originalVideoPath = vidItem.image.path;
100
- let videoDuration = (vidItem.image as any).duration || 0;
101
- const videoMime = (vidItem.image as any).mime;
102
- const filename = vidItem.image.filename || 'video.mp4';
103
-
104
- console.log('[ChatComposer] Generating thumbnail for video:', {
105
- index: idx,
106
- filename,
107
- originalVideoPath,
108
- videoDuration,
109
- videoMime,
110
- uploadedUrl: vidItem.uploadedUrl,
111
- });
112
-
113
- // ✅ FIX: Validate duration is reasonable
114
- if (videoDuration <= 0 || videoDuration > 3600000) {
115
- // Duration should be between 0 and 1 hour (3600000ms)
116
- console.warn(
117
- '[ChatComposer] Invalid duration, using default:',
118
- videoDuration
119
- );
120
- videoDuration = 5000; // Default 5 seconds
121
- }
122
-
123
- // Copy video to persistent location
124
- const ext = filename.split('.').pop() || 'mp4';
125
- // ✅ FIX: Use unique ID to avoid race condition
126
- const cachedFileName = `thumb-cache-${idx}-${Date.now()}-${Math.random()
127
- .toString(36)
128
- .slice(2)}.${ext}`;
129
- cachedVideoPath = `${RNFS.DocumentDirectoryPath}/${cachedFileName}`;
130
-
131
- console.log('[ChatComposer] Copying video to cache:', {
132
- from: originalVideoPath,
133
- to: cachedVideoPath,
134
- });
135
-
136
- await RNFS.copyFile(originalVideoPath, cachedVideoPath);
137
- console.log('[ChatComposer] Video cached successfully');
138
-
139
- // ✅ FIX: Choose frame at 30-40% for better representation
140
- // (not exactly middle, to avoid black frames/transitions)
141
- const timeMs = Math.min(
142
- Math.max(1000, Math.floor(videoDuration * 0.35)),
143
- videoDuration - 1000
144
- );
145
-
146
- console.log('[ChatComposer] Thumbnail settings for video:', {
147
- index: idx,
148
- videoDuration,
149
- timeMs,
150
- quality: 80,
151
- videoPath: cachedVideoPath,
152
- });
153
-
154
- // Generate thumbnail from cached copy
155
- const thumbnail = await VideoThumbnailUtil.generateThumbnail(
156
- cachedVideoPath,
157
- {
158
- time: timeMs,
159
- quality: 80,
160
- cacheId: `thumb-${idx}-${Date.now()}`,
161
- }
162
- );
163
-
164
- if (!thumbnail) {
165
- throw new Error('Failed to generate thumbnail');
166
- }
167
-
168
- console.log('[ChatComposer] Thumbnail generated for video:', {
169
- index: idx,
170
- path: thumbnail.path,
171
- width: thumbnail.width,
172
- height: thumbnail.height,
173
- });
174
-
175
- // Upload thumbnail
176
- const baseName =
177
- vidItem.image.filename?.split('.')[0] || `video-${idx}`;
178
- const uploadedThumbnail = await ImageUploadAPI.uploadImageFile(
179
- {
180
- path: thumbnail.path,
181
- filename: `thumb-${baseName}.jpg`,
182
- size: 0,
183
- width: thumbnail.width || 320,
184
- height: thumbnail.height || 180,
185
- mime: 'image/jpeg',
186
- },
187
- (progress) => {
188
- console.log('[ChatComposer] Thumbnail upload progress:', {
189
- videoIndex: idx,
190
- percentage: progress,
191
- });
192
- }
193
- );
194
-
195
- if (!uploadedThumbnail?.url) {
196
- throw new Error('No thumbnail URL returned');
197
- }
198
-
199
- // ✅ FIX: Store with unique ID instead of path
200
- galleryVideoThumbnails[videoId] = {
201
- url: uploadedThumbnail.url,
202
- size: uploadedThumbnail.size || 0,
203
- };
204
-
205
- console.log('[ChatComposer] Thumbnail ready for video:', {
206
- videoIndex: idx,
207
- videoId,
208
- url: uploadedThumbnail.url,
209
- size: uploadedThumbnail.size,
210
- });
211
- console.log(
212
- `✅ [ChatComposer] Video #${idx} THUMBNAIL URL: ${uploadedThumbnail.url}`
213
- );
214
- } catch (error) {
215
- // ✅ FIX: Skip failed video instead of aborting all
216
- const errorMsg =
217
- error instanceof Error ? error.message : String(error);
218
- console.error(
219
- '[ChatComposer] Thumbnail generation error for video:',
220
- idx,
221
- errorMsg
222
- );
223
- failedVideos.push(vidItem.image.filename);
224
-
225
- // Mark this video as failed (no thumbnail)
226
- galleryVideoThumbnails[videoId] = { url: '', size: 0 };
227
- } finally {
228
- // Cleanup cached video file
229
- if (cachedVideoPath) {
230
- try {
231
- await RNFS.unlink(cachedVideoPath);
232
- console.log('[ChatComposer] Cleaned up cached video:', {
233
- videoIndex: idx,
234
- path: cachedVideoPath,
235
- });
236
- } catch (err) {
237
- console.warn('[ChatComposer] Failed to clean cached video:', err);
238
- }
239
- }
240
- }
241
- }
242
-
243
- // Show error about failed videos if any
244
- if (failedVideos.length > 0) {
245
- UIUtils.toast.open({
246
- title: 'Thumbnail Generation Failed',
247
- message: `Failed for: ${failedVideos.join(', ')}. Videos will be sent without thumbnails.`,
248
- theme: 'warning',
249
- });
250
- console.warn(
251
- '[ChatComposer] Failed to generate thumbnails for:',
252
- failedVideos
253
- );
254
- }
255
- }
256
-
257
- const allUploadedVideos = [...uploadedVideosFromGallery];
258
-
259
- console.log('[ChatComposer] handleSend summary:', {
260
- actualImages: actualImages.length,
261
- uploadedImages: uploadedImages.length,
262
- videosFromGallery: videosFromGallery.length,
263
- uploadedVideosFromGallery: uploadedVideosFromGallery.length,
264
- allUploadedVideos: allUploadedVideos.length,
265
- });
266
-
267
- // Log thumbnail URLs
268
- if (uploadedVideosFromGallery.length > 0) {
269
- uploadedVideosFromGallery.forEach((vid: any, vidIdx: number) => {
270
- // ✅ Use same key as storage: uploadedUrl or video-${idx}
271
- const videoId = vid.uploadedUrl || `video-${vidIdx}`;
272
- const thumbnail = galleryVideoThumbnails[videoId];
273
- console.log(`✅ [ChatComposer] Gallery Video Thumbnail:`, {
274
- filename: vid.image.filename,
275
- videoId,
276
- thumbnailUrl: thumbnail?.url || 'NOT FOUND',
277
- videoUrl: vid.uploadedUrl,
278
- });
279
- });
280
- }
281
-
282
- // Send images and videos if any
283
- if (uploadedImages.length > 0 || allUploadedVideos.length > 0) {
284
- const attachmentItems = [
285
- ...uploadedImages.map((img: any) => ({
286
- ...img,
287
- type: 'image' as const,
288
- })),
289
- // Videos from gallery picker with auto-generated thumbnails
290
- ...uploadedVideosFromGallery.map((vid: any, vidIdx: number) => {
291
- // ✅ Use same key as storage: uploadedUrl or video-${idx}
292
- const videoId = vid.uploadedUrl || `video-${vidIdx}`;
293
- const thumbnail = galleryVideoThumbnails[videoId];
294
- return {
295
- type: 'video' as const,
296
- video: vid.image,
297
- uploadProgress: vid.uploadProgress,
298
- error: vid.error,
299
- isUploading: vid.isUploading,
300
- uploadedUrl: vid.uploadedUrl,
301
- thumbnailUrl: thumbnail?.url,
302
- thumbnailSize: thumbnail?.size,
303
- };
304
- }),
305
- ];
306
-
307
- console.log('[ChatComposer] Sending attachments...', {
308
- imagesCount: uploadedImages.length,
309
- videosCount: uploadedVideosFromGallery.length,
310
- hasTextMessage: !!textMessage,
311
- });
312
-
313
- const success = await sendAttachments(
314
- attachmentItems,
315
- undefined,
316
- onMessageSent
317
- );
318
-
319
- console.log('[ChatComposer] Attachments send result:', { success });
320
-
321
- if (success) {
322
- clearAllImages();
323
- console.log('[ChatComposer] Images cleared after successful send');
324
- }
325
- }
326
-
327
- // Send each file as its own individual message
328
- const uploadedFiles = selectedFiles.filter(
329
- (f) => f.uploadedUrl && !f.error
330
- );
331
- if (uploadedFiles.length > 0) {
332
- console.log('[ChatComposer] Sending files individually:', {
333
- count: uploadedFiles.length,
334
- });
335
- for (const file of uploadedFiles) {
336
- await sendAttachments(
337
- [
338
- {
339
- type: 'file' as const,
340
- file: { path: file.uri, filename: file.name, size: file.size },
341
- uploadProgress: 100,
342
- error: null,
343
- isUploading: false,
344
- uploadedUrl: file.uploadedUrl,
345
- },
346
- ],
347
- undefined,
348
- onMessageSent
349
- );
350
- }
351
- clearAllFiles?.();
352
- }
353
-
354
- // Send text last
355
- if (textMessage && onSendText) {
356
- console.log('[ChatComposer] Sending text message after attachments', {
357
- hasPreview: !!urlMetadata,
358
- previewUrl: urlMetadata?.url,
359
- });
360
- onSendText(textMessage, urlMetadata);
361
- return;
362
- }
363
-
364
- const hasAnySent =
365
- uploadedImages.length > 0 ||
366
- allUploadedVideos.length > 0 ||
367
- uploadedFiles.length > 0;
368
- if (!hasAnySent) {
369
- onSend?.();
370
- }
371
- return;
372
- }, [
373
- selectedImages,
374
- selectedFiles,
375
- sendAttachments,
376
- clearAllImages,
377
- clearAllFiles,
378
- onSend,
379
- onMessageSent,
380
- textMessage,
381
- urlMetadata,
382
- onSendText,
383
- ]);
384
-
385
- return { handleSend };
386
- };
@@ -1,137 +0,0 @@
1
- import { MessageStatus, MessageType } from '@droppii/openim-rn-client-sdk';
2
- import type { IMessage } from 'react-native-gifted-chat';
3
- import type { DChatMessageType } from '../types/message';
4
- import type { DMessageItem } from '../types/chat';
5
- import { resolveChatMessageType } from './resolveMessageType';
6
-
7
- export type DGiftedChatMessage = IMessage & {
8
- openIMMessage: DMessageItem;
9
- messageType: DChatMessageType;
10
- };
11
-
12
- const SYSTEM_MESSAGE_TYPES = new Set<MessageType>([
13
- MessageType.FriendAdded,
14
- MessageType.OANotification,
15
- MessageType.GroupCreated,
16
- MessageType.GroupInfoUpdated,
17
- MessageType.MemberQuit,
18
- MessageType.GroupOwnerTransferred,
19
- MessageType.MemberKicked,
20
- MessageType.MemberInvited,
21
- MessageType.MemberEnter,
22
- MessageType.GroupDismissed,
23
- MessageType.GroupMemberMuted,
24
- MessageType.GroupMemberCancelMuted,
25
- MessageType.GroupMuted,
26
- MessageType.GroupCancelMuted,
27
- MessageType.GroupAnnouncementUpdated,
28
- MessageType.GroupNameUpdated,
29
- MessageType.RevokeMessage,
30
- ]);
31
-
32
- const getMessageText = (message: DMessageItem): string => {
33
- switch (message.contentType) {
34
- case MessageType.TextMessage:
35
- return message.textElem?.content ?? message.content;
36
- case MessageType.AtTextMessage:
37
- return message.atTextElem?.text ?? message.content;
38
- case MessageType.QuoteMessage:
39
- return message.quoteElem?.text ?? message.content;
40
- case MessageType.PictureMessage:
41
- return '';
42
- case MessageType.VoiceMessage:
43
- return message.soundElem?.sourceUrl ? '' : '[Tin nhắn thoại]';
44
- case MessageType.VideoMessage:
45
- return message.videoElem?.videoUrl ? '' : '[Video]';
46
- case MessageType.FileMessage:
47
- return message.fileElem?.fileName ?? message.content;
48
- case MessageType.CardMessage:
49
- return message.cardElem?.nickname ?? message.content;
50
- case MessageType.LocationMessage:
51
- return message.locationElem?.description ?? message.content;
52
- case MessageType.CustomMessage:
53
- return message.customElem?.description ?? message.content;
54
- case MessageType.FaceMessage:
55
- return '[Sticker]';
56
- default:
57
- if (message.notificationElem?.detail) {
58
- return message.notificationElem.detail;
59
- }
60
- return message.content || '';
61
- }
62
- };
63
-
64
- const mapMessageStatus = (
65
- message: DMessageItem
66
- ): Pick<IMessage, 'pending' | 'sent' | 'received'> => {
67
- switch (message.status) {
68
- case MessageStatus.Sending:
69
- return { pending: true };
70
- case MessageStatus.Succeed:
71
- return { sent: true, received: message.isRead };
72
- case MessageStatus.Failed:
73
- return { pending: true };
74
- default:
75
- return {};
76
- }
77
- };
78
-
79
- export const mapOpenIMMessageToGiftedChat = (
80
- message: DMessageItem
81
- ): DGiftedChatMessage => {
82
- const gifted: DGiftedChatMessage = {
83
- _id: message.clientMsgID || message.serverMsgID,
84
- text: getMessageText(message),
85
- createdAt: new Date(message.sendTime || message.createTime),
86
- user: {
87
- _id: String(message.sendID),
88
- name: message.senderNickname,
89
- avatar: message.senderFaceUrl || undefined,
90
- },
91
- openIMMessage: message,
92
- messageType: resolveChatMessageType(message),
93
- ...mapMessageStatus(message),
94
- };
95
-
96
- if (SYSTEM_MESSAGE_TYPES.has(message.contentType)) {
97
- gifted.system = true;
98
- }
99
-
100
- if (message.contentType === MessageType.PictureMessage) {
101
- const imageUrl =
102
- message.pictureElem?.snapshotPicture?.url ||
103
- message.pictureElem?.bigPicture?.url ||
104
- message.pictureElem?.sourcePicture?.url;
105
-
106
- if (imageUrl) {
107
- gifted.image = imageUrl;
108
- }
109
- }
110
-
111
- if (
112
- message.contentType === MessageType.VideoMessage &&
113
- message.videoElem?.videoUrl
114
- ) {
115
- gifted.video = message.videoElem.videoUrl;
116
- }
117
-
118
- if (
119
- message.contentType === MessageType.VoiceMessage &&
120
- message.soundElem?.sourceUrl
121
- ) {
122
- gifted.audio = message.soundElem.sourceUrl;
123
- }
124
-
125
- return gifted;
126
- };
127
-
128
- export const mapOpenIMMessagesToGiftedChat = (
129
- messages: DMessageItem[]
130
- ): DGiftedChatMessage[] => {
131
- return messages
132
- .map(mapOpenIMMessageToGiftedChat)
133
- .sort(
134
- (a, b) =>
135
- new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
136
- );
137
- };
package/src/utils/ui.ts DELETED
@@ -1,19 +0,0 @@
1
- import { Alert } from 'react-native';
2
-
3
- interface ToastConfig {
4
- title?: string;
5
- message?: string;
6
- theme?: 'success' | 'danger' | 'warning' | 'info';
7
- }
8
-
9
- const UIUtils = {
10
- toast: {
11
- open: (config: ToastConfig) => {
12
- const { title = 'Message', message = '' } = config;
13
- Alert.alert(title, message);
14
- },
15
- },
16
- };
17
-
18
- export default UIUtils;
19
- export { UIUtils };