@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,4 +1,4 @@
1
- import { memo, useState, useCallback, useEffect, useMemo, useRef } from 'react';
1
+ import { memo, useCallback, useEffect, useMemo, useRef } from 'react';
2
2
  import { Platform, StyleSheet } from 'react-native';
3
3
 
4
4
  import { KeyboardAvoidingView } from 'react-native-keyboard-controller';
@@ -14,26 +14,16 @@ import { useConversation, useConversationStore } from '../../store';
14
14
  import ChatDetailHeader from './ChatDetailHeader';
15
15
  import { ChatListLegend } from './ChatListLegend';
16
16
  import { ChatComposer } from './ChatComposer';
17
- import {
18
- DEFAULT_ATTACHMENT_ACTIONS,
19
- DEFAULT_Chat_QUICK_ACTIONS,
20
- } from './constants';
21
17
  import {
22
18
  getConversationAvatarUri,
23
19
  getConversationSubtitle,
24
20
  getConversationTitle,
25
21
  shouldShowAddMember,
26
22
  } from './conversationHeader.utils';
27
- import type {
28
- ChatDetailProps,
29
- DChatQuickAction,
30
- DChatAttachmentAction,
31
- } from './types';
32
- import { useSendMessage } from '../../hooks/message/useSendMessage';
33
- import type { IUrlMetadata } from '../../types/common';
34
- import { useMessageStore } from '../../store/message';
23
+ import type { ChatDetailProps } from './types';
35
24
  import { ChatDetailProvider } from '../../context/ChatDetailContext';
36
25
  import { normalizeUrl } from '../../utils/url';
26
+ // import { ChatMessageAPI } from '../../services/message';
37
27
 
38
28
  const ChatDetail = memo(
39
29
  ({
@@ -50,58 +40,27 @@ const ChatDetail = memo(
50
40
  onPressAddMember,
51
41
  onPressMenu,
52
42
  onPressAvatar,
53
- showQuickActions = true,
54
- quickActions,
55
- inputPlaceholder,
56
- onChangeInput,
57
- onPressAttach,
58
- onPressEmoji,
59
- attachmentActions,
60
- onQuickActionPress,
61
- onAttachmentAction,
62
- renderQuickAction,
63
- renderQuickActions,
64
- renderAttachmentAction,
65
- attachmentColumns,
66
43
  onPressUrl,
67
44
  customMessageItemFactory,
68
45
  }: ChatDetailProps) => {
69
46
  const navigation = useNavigation();
70
- const [internalInput, setInternalInput] = useState<string>('');
71
47
  const mediaViewerRef = useRef<MediaViewerModalHandle>(null);
72
48
  const conversation = useConversation(conversationId);
73
- // const user = conversation?.peer;
74
49
 
75
- // Default handlers when props not provided
76
50
  const handleBackDefault = useCallback(() => {
77
51
  navigation.goBack();
78
52
  }, [navigation]);
79
53
 
80
- const quickActionsDefault = useMemo<DChatQuickAction[]>(
81
- () =>
82
- DEFAULT_Chat_QUICK_ACTIONS.map((action) => ({
83
- ...action,
84
- onPress: () => {
85
- console.log('[quick-action]', action.id);
86
- },
87
- })),
88
- []
89
- );
90
-
91
- const attachmentActionsDefault = useMemo<DChatAttachmentAction[]>(
92
- () =>
93
- DEFAULT_ATTACHMENT_ACTIONS.map((action) => ({
94
- ...action,
95
- onPress: () => {
96
- console.log('[attachment-action]', action.id);
97
- },
98
- })),
54
+ const handleMediaPress = useCallback(
55
+ (
56
+ items: Parameters<MediaViewerModalHandle['show']>[0],
57
+ index?: number
58
+ ) => {
59
+ mediaViewerRef.current?.show(items, index);
60
+ },
99
61
  []
100
62
  );
101
63
 
102
- const { sendMessage } = useSendMessage();
103
- const { pushNewMessage } = useMessageStore();
104
-
105
64
  const {
106
65
  messages,
107
66
  currentUserId,
@@ -109,30 +68,23 @@ const ChatDetail = memo(
109
68
  isLoading,
110
69
  isLoadingEarlier,
111
70
  hasMoreEarlier,
112
- } = useChatMessages({
113
- conversationId,
114
- enabled,
115
- });
116
-
117
- // Callback for attachment messages - add them to the message list
118
- const handleAttachmentMessageSent = useCallback(
119
- (message: any) => {
120
- if (__DEV__)
121
- console.log('[ChatDetail] Attachment message received:', {
122
- clientMsgID: message?.clientMsgID,
123
- contentType: message?.contentType,
124
- });
125
- if (message) {
126
- pushNewMessage(message);
127
- }
128
- },
129
- [pushNewMessage]
130
- );
71
+ } = useChatMessages({ conversationId, enabled });
131
72
 
132
73
  useEffect(() => {
133
74
  useConversationStore.getState().setCurrentConversation(conversationId);
134
75
  }, [conversationId]);
135
76
 
77
+ // useEffect(() => {
78
+ // if (!conversationId) return;
79
+ // ChatMessageAPI.searchLocalMessages(conversationId, { count: 20 })
80
+ // .then((result) => {
81
+ // console.log('[TEST searchLocalMessages] success:', result);
82
+ // })
83
+ // .catch((err) => {
84
+ // console.log('[TEST searchLocalMessages] error:', err);
85
+ // });
86
+ // }, [conversationId]);
87
+
136
88
  const resolvedTitle = title ?? getConversationTitle(conversation);
137
89
  const resolvedAvatarUri =
138
90
  avatarUri ?? getConversationAvatarUri(conversation);
@@ -140,84 +92,18 @@ const ChatDetail = memo(
140
92
  const resolvedShowAddMember =
141
93
  showAddMember ?? shouldShowAddMember(conversation);
142
94
  const resolvedSubtitle = useMemo(() => {
143
- if (subtitle !== undefined) {
144
- return subtitle;
145
- }
146
-
147
- if (getSubtitle && conversation) {
148
- return getSubtitle(conversation);
149
- }
150
-
95
+ if (subtitle !== undefined) return subtitle;
96
+ if (getSubtitle && conversation) return getSubtitle(conversation);
151
97
  return getConversationSubtitle(conversation);
152
98
  }, [conversation, getSubtitle, subtitle]);
153
99
 
154
- const currentInput = internalInput;
155
-
156
- const handleChangeText = useCallback(
157
- (text?: string) => {
158
- const newText = text ?? '';
159
- if (onChangeInput) {
160
- onChangeInput(newText);
161
- } else {
162
- setInternalInput(newText);
163
- }
164
- },
165
- [onChangeInput]
166
- );
167
-
168
- const handleSend = useCallback(
169
- async (urlMetadata?: any) => {
170
- // Support captured text passed from attachment handler
171
- const capturedText = (urlMetadata as any)?._capturedText;
172
- const cleanMetadata = capturedText
173
- ? (({ _capturedText, ...rest }) => rest)(urlMetadata)
174
- : (urlMetadata as IUrlMetadata);
175
-
176
- const text = (capturedText || currentInput).trim();
177
-
178
- // Validate: must have text OR preview metadata (text is optional if preview exists)
179
- // If metadata exists, trust it (useLinkPreview is responsible for validity)
180
- if (!text && !cleanMetadata) {
181
- if (__DEV__)
182
- console.warn('[ChatDetail] No text or preview link to send');
183
- return;
184
- }
185
-
186
- // Log if metadata seems incomplete
187
- if (cleanMetadata && !cleanMetadata.url) {
188
- if (__DEV__)
189
- console.warn(
190
- '[ChatDetail] Preview metadata missing URL - check useLinkPreview'
191
- );
192
- }
193
-
194
- try {
195
- await sendMessage({
196
- files: [],
197
- plainText: text,
198
- urlMetadata: cleanMetadata || undefined,
199
- });
100
+ const insets = useSafeAreaInsets();
200
101
 
201
- // Clear input after successful send
202
- if (onChangeInput) {
203
- onChangeInput('');
204
- } else {
205
- setInternalInput('');
206
- }
207
- } catch (error) {
208
- if (__DEV__)
209
- console.error('[ChatDetail] Failed to send message:', {
210
- error,
211
- text: text.substring(0, 50),
212
- hasPreview: !!cleanMetadata,
213
- });
214
- }
215
- },
216
- [currentInput, onChangeInput, sendMessage]
102
+ const keyboardVerticalOffset = useMemo(
103
+ () => Platform.select({ android: insets.bottom, default: 0 }),
104
+ [insets.bottom]
217
105
  );
218
106
 
219
- const insets = useSafeAreaInsets();
220
-
221
107
  const handlePressUrl = useCallback(
222
108
  (url: string) => {
223
109
  onPressUrl?.(normalizeUrl(url));
@@ -236,25 +122,16 @@ const ChatDetail = memo(
236
122
  avatarFullName={resolvedAvatarFullName}
237
123
  showAddMember={resolvedShowAddMember}
238
124
  onBack={onBack ?? handleBackDefault}
239
- onPressSearch={
240
- onPressSearch ?? (() => console.log('[onPressSearch]'))
241
- }
242
- onPressAddMember={
243
- onPressAddMember ?? (() => console.log('[onPressAddMember]'))
244
- }
245
- onPressMenu={onPressMenu ?? (() => console.log('[onPressMenu]'))}
246
- onPressAvatar={
247
- onPressAvatar ?? (() => console.log('[onPressAvatar]'))
248
- }
125
+ onPressSearch={onPressSearch}
126
+ onPressAddMember={onPressAddMember}
127
+ onPressMenu={onPressMenu}
128
+ onPressAvatar={onPressAvatar}
249
129
  />
250
130
 
251
131
  <KeyboardAvoidingView
252
132
  style={styles.keyboardAvoiding}
253
133
  behavior="padding"
254
- keyboardVerticalOffset={Platform.select({
255
- android: insets.bottom,
256
- default: 0,
257
- })}
134
+ keyboardVerticalOffset={keyboardVerticalOffset}
258
135
  >
259
136
  <ChatListLegend
260
137
  messages={messages}
@@ -264,45 +141,11 @@ const ChatDetail = memo(
264
141
  isLoading={isLoading}
265
142
  isLoadingEarlier={isLoadingEarlier}
266
143
  hasMoreEarlier={hasMoreEarlier}
267
- onMediaPress={(items, index) => {
268
- mediaViewerRef.current?.show(items, index);
269
- }}
144
+ onMediaPress={handleMediaPress}
270
145
  onPressUrl={handlePressUrl}
271
146
  />
272
147
 
273
- <ChatComposer
274
- value={currentInput}
275
- placeholder={inputPlaceholder}
276
- onChangeText={handleChangeText}
277
- onSend={handleSend}
278
- onMessageSent={handleAttachmentMessageSent}
279
- onPressAttach={
280
- onPressAttach ?? (() => console.log('[onPressAttach]'))
281
- }
282
- onPressEmoji={
283
- onPressEmoji ?? (() => console.log('[onPressEmoji]'))
284
- }
285
- showQuickActions={showQuickActions}
286
- quickActions={quickActions ?? quickActionsDefault}
287
- attachmentActions={attachmentActions ?? attachmentActionsDefault}
288
- onQuickActionPress={
289
- onQuickActionPress ??
290
- ((action: DChatQuickAction) => {
291
- console.log('[onQuickActionPress]', action.id, action.meta);
292
- })
293
- }
294
- onAttachmentAction={
295
- onAttachmentAction ??
296
- ((action: DChatAttachmentAction) => {
297
- console.log('[onAttachmentAction]', action.id, action.meta);
298
- })
299
- }
300
- renderQuickAction={renderQuickAction}
301
- renderQuickActions={renderQuickActions}
302
- renderAttachmentAction={renderAttachmentAction}
303
- attachmentColumns={attachmentColumns}
304
- isEmptyMessage={messages?.length === 0}
305
- />
148
+ <ChatComposer isEmptyMessage={messages?.length === 0} />
306
149
  </KeyboardAvoidingView>
307
150
 
308
151
  <MediaViewerModal ref={mediaViewerRef} />
@@ -315,9 +158,7 @@ const ChatDetail = memo(
315
158
  ChatDetail.displayName = 'ChatDetail';
316
159
 
317
160
  const styles = StyleSheet.create({
318
- keyboardAvoiding: {
319
- flex: 1,
320
- },
161
+ keyboardAvoiding: { flex: 1 },
321
162
  });
322
163
 
323
164
  export default ChatDetail;
@@ -1,5 +1,5 @@
1
1
  import { memo, useCallback, useMemo, useEffect, useRef, useState } from 'react';
2
- import { ActivityIndicator, StyleSheet } from 'react-native';
2
+ import { StyleSheet } from 'react-native';
3
3
  import Animated, {
4
4
  useSharedValue,
5
5
  useAnimatedStyle,
@@ -18,6 +18,7 @@ import { getFlowInputButtonsNode } from '../../utils/flows';
18
18
  import { InputButtonFlow } from '../../components/flows/inputButtons';
19
19
  import { useResetFlow, useRunFlow } from '../../hooks/flows/useFlow';
20
20
  import type { IRunConversationFlowPayload } from '../../types/flows';
21
+ import { useSendMessage } from '../../hooks/message/useSendMessage';
21
22
 
22
23
  export const ChatListLegend = memo(
23
24
  ({
@@ -25,7 +26,6 @@ export const ChatListLegend = memo(
25
26
  currentUserId = '',
26
27
  customMessageItemFactory,
27
28
  onLoadEarlier,
28
- isLoading,
29
29
  isLoadingEarlier,
30
30
  hasMoreEarlier,
31
31
  onLoadNewer,
@@ -41,6 +41,7 @@ export const ChatListLegend = memo(
41
41
  );
42
42
 
43
43
  const { isBotConversation, conversationFlow } = useChatDetailContext();
44
+ const { retryMessage } = useSendMessage();
44
45
 
45
46
  const lastMessageId = useMemo(() => {
46
47
  const last = messages[messages.length - 1];
@@ -143,6 +144,7 @@ export const ChatListLegend = memo(
143
144
  createdAtTime={createdAt}
144
145
  onMediaPress={onMediaPress}
145
146
  onPressUrl={onPressUrl}
147
+ onRetry={retryMessage}
146
148
  customMessageItemFactory={customMessageItemFactory}
147
149
  />
148
150
  {!!flowInputButtonsNode && (
@@ -179,6 +181,7 @@ export const ChatListLegend = memo(
179
181
  onRunFlow,
180
182
  conversationFlow?.flowCurrentStep,
181
183
  handleItemLayout,
184
+ retryMessage,
182
185
  ]
183
186
  );
184
187
 
@@ -327,16 +330,16 @@ export const ChatListLegend = memo(
327
330
  };
328
331
  }, []);
329
332
 
330
- if (isLoading) {
331
- return (
332
- <KContainer.View flex center background={KColors.white}>
333
- <ActivityIndicator
334
- color={KColors.palette.primary.w400}
335
- size="small"
336
- />
337
- </KContainer.View>
338
- );
339
- }
333
+ // if (isLoading) {
334
+ // return (
335
+ // <KContainer.View flex center background={KColors.white}>
336
+ // <ActivityIndicator
337
+ // color={KColors.palette.primary.w400}
338
+ // size="small"
339
+ // />
340
+ // </KContainer.View>
341
+ // );
342
+ // }
340
343
 
341
344
  return (
342
345
  <KContainer.View flex background={KColors.white} style={styles.container}>
@@ -346,7 +349,7 @@ export const ChatListLegend = memo(
346
349
  renderItem={renderItem}
347
350
  estimatedItemSize={avgItemHeightRef.current}
348
351
  keyExtractor={(item) => String(item.clientMsgID || item.serverMsgID)}
349
- recycleItems={false}
352
+ recycleItems={true}
350
353
  extraData={`${conversationFlow?.flowCurrentStep?.id ?? ''}-${lastMessageId ?? ''}`}
351
354
  alignItemsAtEnd
352
355
  maintainVisibleContentPosition={maintainVisiblePositionConfig}
@@ -27,12 +27,8 @@ export type {
27
27
  ChatQuickActionsRenderParams,
28
28
  ChatAttachmentPanelProps,
29
29
  } from './types';
30
- export type { DGiftedChatMessage } from '../../utils/giftedChatMessage';
30
+
31
31
  export {
32
32
  DChatMessageType,
33
33
  CUSTOM_MESSAGE_DATA_TYPE,
34
34
  } from '../../types/message';
35
- export {
36
- mapOpenIMMessageToGiftedChat,
37
- mapOpenIMMessagesToGiftedChat,
38
- } from '../../utils/giftedChatMessage';
@@ -1,6 +1,8 @@
1
1
  import { memo } from 'react';
2
2
  import type { ComponentType, ReactNode } from 'react';
3
+ import { KContainer } from '@droppii/libs';
3
4
  import { MessageType } from '@droppii/openim-rn-client-sdk';
5
+ import type { MessageItem } from '@droppii/openim-rn-client-sdk';
4
6
  import type { DMessageItem } from '../../../types/chat';
5
7
  import type { MediaItem } from '../../../hooks/useMediaViewer';
6
8
  import { TextMessage } from '../../../components/messages/textMessage';
@@ -9,6 +11,7 @@ import { VideoMessage } from '../../../components/messages/videoMessage';
9
11
  import { FileMessage } from '../../../components/messages/fileMessage';
10
12
  import { LinkMessage } from '../../../components/messages/linkMessage';
11
13
  import { MergedMessage } from '../../../components/messages/mergedMessage';
14
+ import { MessageStatusIndicator } from '../../../components/messages/MessageStatusIndicator';
12
15
  import type { BaseLegendMessageProps } from '../../../components/messages/types';
13
16
 
14
17
  type MessageProps = BaseLegendMessageProps & {
@@ -21,6 +24,7 @@ interface LegendChatMessageProps {
21
24
  createdAtTime: number;
22
25
  onMediaPress?: (items: MediaItem[], index?: number) => void;
23
26
  onPressUrl?: (url: string) => void;
27
+ onRetry?: (message: MessageItem) => void;
24
28
  customMessageItemFactory?: (m: DMessageItem) => ReactNode;
25
29
  }
26
30
 
@@ -46,10 +50,6 @@ const MEDIA_TYPES: number[] = [
46
50
  MERGED_MESSAGE_TYPE,
47
51
  ];
48
52
 
49
- /**
50
- * Dispatcher component - renders the appropriate message component
51
- * based on message type. Extensible for new message types.
52
- */
53
53
  export const LegendChatMessage = memo(
54
54
  ({
55
55
  message,
@@ -57,9 +57,9 @@ export const LegendChatMessage = memo(
57
57
  createdAtTime,
58
58
  onMediaPress,
59
59
  onPressUrl,
60
+ onRetry,
60
61
  customMessageItemFactory,
61
62
  }: LegendChatMessageProps) => {
62
- console.log('customMessageItemFactory', customMessageItemFactory);
63
63
  const customNode = customMessageItemFactory?.(message);
64
64
  if (customNode) {
65
65
  return customNode;
@@ -74,13 +74,20 @@ export const LegendChatMessage = memo(
74
74
  onPressUrl && message?.contentType === MessageType.UrlTextMessage;
75
75
 
76
76
  return (
77
- <MessageComponent
78
- message={message}
79
- isOutgoing={isOutgoing}
80
- createdAtTime={createdAtTime}
81
- onMediaPress={hasMediaPress ? onMediaPress : undefined}
82
- onPressUrl={hasUrlPress ? onPressUrl : undefined}
83
- />
77
+ <KContainer.View row alignItems>
78
+ <MessageStatusIndicator
79
+ message={message}
80
+ isOutgoing={isOutgoing}
81
+ onRetry={onRetry}
82
+ />
83
+ <MessageComponent
84
+ message={message}
85
+ isOutgoing={isOutgoing}
86
+ createdAtTime={createdAtTime}
87
+ onMediaPress={hasMediaPress ? onMediaPress : undefined}
88
+ onPressUrl={hasUrlPress ? onPressUrl : undefined}
89
+ />
90
+ </KContainer.View>
84
91
  );
85
92
  }
86
93
  );
@@ -1,8 +1,6 @@
1
1
  import type { ReactNode } from 'react';
2
-
3
2
  import type { MediaItem } from '../../hooks/useMediaViewer';
4
3
  import type { DMessageItem } from '../../types/chat';
5
- import type { IUrlMetadata } from '../../types/common';
6
4
  import type { ConversationItem } from '@droppii/openim-rn-client-sdk';
7
5
 
8
6
  export type DChatActionIconProvider = 'MaterialCommunityIcons' | 'DroppiiNew';
@@ -58,23 +56,7 @@ export interface ChatAttachmentPanelProps {
58
56
  }
59
57
 
60
58
  export interface ChatComposerProps {
61
- value?: string;
62
- placeholder?: string;
63
- onChangeText?: (text?: string) => void;
64
- onSend?: (urlMetadata?: IUrlMetadata) => void;
65
- onPressAttach?: () => void;
66
- onPressEmoji?: () => void;
67
- onMessageSent?: (message: DMessageItem) => void;
68
- showQuickActions?: boolean;
69
- quickActions?: DChatQuickAction[];
70
- attachmentActions?: DChatAttachmentAction[];
71
- onQuickActionPress?: (action: DChatQuickAction) => void;
72
- onAttachmentAction?: (action: DChatAttachmentAction) => void;
73
- renderQuickAction?: ChatQuickActionsProps['renderAction'];
74
- renderQuickActions?: ChatQuickActionsProps['renderQuickActions'];
75
- renderAttachmentAction?: ChatAttachmentPanelProps['renderAction'];
76
- attachmentColumns?: number;
77
- isEmptyMessage: boolean;
59
+ isEmptyMessage?: boolean;
78
60
  }
79
61
 
80
62
  export interface ChatListProps {
@@ -110,25 +92,6 @@ export interface ChatDetailProps extends Omit<
110
92
  avatarFullName?: string;
111
93
  showAddMember?: boolean;
112
94
  getSubtitle?: (conversation: ConversationItem) => string | undefined;
113
- renderChat?: (item: DMessageItem) => ReactNode;
114
- showQuickActions?: boolean;
115
- showAttachmentActions?: boolean;
116
- quickActions?: DChatQuickAction[];
117
- getQuickActions?: (
118
- conversation: ConversationItem
119
- ) => DChatQuickAction[] | undefined;
120
- attachmentActions?: DChatAttachmentAction[];
121
- inputPlaceholder?: string;
122
- onChangeInput?: (text: string) => void;
123
- onSend?: () => void;
124
- onPressAttach?: () => void;
125
- onPressEmoji?: () => void;
126
- onQuickActionPress?: (action: DChatQuickAction) => void;
127
- onAttachmentAction?: (action: DChatAttachmentAction) => void;
128
- renderQuickAction?: ChatQuickActionsProps['renderAction'];
129
- renderQuickActions?: ChatQuickActionsProps['renderQuickActions'];
130
- renderAttachmentAction?: ChatAttachmentPanelProps['renderAction'];
131
- attachmentColumns?: number;
132
95
  onPressUrl?: (url: string) => void;
133
96
  customMessageItemFactory?: (item: DMessageItem) => ReactNode;
134
97
  }
@@ -9,8 +9,9 @@ interface FileElem {
9
9
  sourceUrl: string;
10
10
  }
11
11
 
12
- const MB = 1024 * 1024;
13
- export const MAX_FILE_SIZE = 50 * MB;
12
+ import { UPLOAD_LIMITS } from '../../config/uploadLimits';
13
+
14
+ export const MAX_FILE_SIZE = UPLOAD_LIMITS.file;
14
15
 
15
16
  export class FileAttachmentHandler implements IAttachmentHandler {
16
17
  validate(
@@ -1,12 +1,15 @@
1
1
  import type { ImageAttachment } from '../../types/attachment';
2
2
  import type { IAttachmentHandler } from '../../types/attachmentHandler';
3
3
  import { generateUUID } from '../../utils/imageUtils';
4
+ import { UPLOAD_LIMITS } from '../../config/uploadLimits';
4
5
 
5
6
  export const ImageAttachmentHandler: IAttachmentHandler = {
6
7
  validate(attachment: ImageAttachment) {
7
- const MAX_SIZE = 5 * 1024 * 1024;
8
- if (attachment.sourceFile.size > MAX_SIZE) {
9
- return { valid: false, reason: 'Image exceeds 5MB limit' };
8
+ if (attachment.sourceFile.size > UPLOAD_LIMITS.image) {
9
+ return {
10
+ valid: false,
11
+ reason: `Image exceeds ${UPLOAD_LIMITS.image / 1024 / 1024}MB limit`,
12
+ };
10
13
  }
11
14
 
12
15
  const validMimes = [
@@ -1,5 +1,6 @@
1
1
  import type { Attachment, VideoAttachment } from '../../types/attachment';
2
2
  import type { IAttachmentHandler } from '../../types/attachmentHandler';
3
+ import { UPLOAD_LIMITS } from '../../config/uploadLimits';
3
4
 
4
5
  interface VideoPicInfo {
5
6
  videoUUID: string;
@@ -18,7 +19,7 @@ interface VideoPicInfo {
18
19
  }
19
20
 
20
21
  export class VideoAttachmentHandler implements IAttachmentHandler {
21
- private static readonly MAX_VIDEO_SIZE = 200 * 1024 * 1024; // 200MB
22
+ private static readonly MAX_VIDEO_SIZE = UPLOAD_LIMITS.video;
22
23
  private static readonly SUPPORTED_TYPES = ['video/mp4', 'video/quicktime'];
23
24
 
24
25
  validate(