@messenger-box/platform-mobile 10.0.3-alpha.40 → 10.0.3-alpha.46

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 (54) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/compute.js +2 -3
  3. package/lib/index.js.map +1 -1
  4. package/lib/queries/inboxQueries.js +77 -0
  5. package/lib/queries/inboxQueries.js.map +1 -0
  6. package/lib/routes.json +2 -3
  7. package/lib/screens/inbox/DialogThreadMessages.js +3 -7
  8. package/lib/screens/inbox/DialogThreadMessages.js.map +1 -1
  9. package/lib/screens/inbox/DialogThreads.js +3 -7
  10. package/lib/screens/inbox/DialogThreads.js.map +1 -1
  11. package/lib/screens/inbox/components/DialogsListItem.js +47 -46
  12. package/lib/screens/inbox/components/DialogsListItem.js.map +1 -1
  13. package/lib/screens/inbox/components/GiftedChatInboxComponent.js +313 -0
  14. package/lib/screens/inbox/components/GiftedChatInboxComponent.js.map +1 -0
  15. package/lib/screens/inbox/components/ServiceDialogsListItem.js +72 -57
  16. package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +1 -1
  17. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +115 -14
  18. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  19. package/lib/screens/inbox/components/SubscriptionHandler.js +24 -0
  20. package/lib/screens/inbox/components/SubscriptionHandler.js.map +1 -0
  21. package/lib/screens/inbox/containers/ConversationView.js +640 -493
  22. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  23. package/lib/screens/inbox/containers/Dialogs.js +100 -181
  24. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  25. package/lib/screens/inbox/containers/ThreadConversationView.js +659 -245
  26. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  27. package/lib/screens/inbox/containers/ThreadsView.js +3 -3
  28. package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
  29. package/lib/screens/inbox/hooks/useInboxMessages.js +31 -0
  30. package/lib/screens/inbox/hooks/useInboxMessages.js.map +1 -0
  31. package/package.json +4 -4
  32. package/src/index.ts +2 -0
  33. package/src/queries/inboxQueries.ts +298 -0
  34. package/src/queries/index.d.ts +2 -0
  35. package/src/queries/index.ts +1 -0
  36. package/src/screens/inbox/DialogThreadMessages.tsx +3 -11
  37. package/src/screens/inbox/DialogThreads.tsx +3 -7
  38. package/src/screens/inbox/components/Actionsheet.tsx +30 -0
  39. package/src/screens/inbox/components/DialogsListItem.tsx +89 -148
  40. package/src/screens/inbox/components/ExpandableInput.tsx +460 -0
  41. package/src/screens/inbox/components/ExpandableInputActionSheet.tsx +518 -0
  42. package/src/screens/inbox/components/GiftedChatInboxComponent.tsx +411 -0
  43. package/src/screens/inbox/components/ServiceDialogsListItem.tsx +202 -221
  44. package/src/screens/inbox/components/SlackInput.tsx +23 -0
  45. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +216 -30
  46. package/src/screens/inbox/components/SubscriptionHandler.tsx +41 -0
  47. package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +6 -7
  48. package/src/screens/inbox/containers/ConversationView.tsx +1109 -669
  49. package/src/screens/inbox/containers/Dialogs.tsx +198 -342
  50. package/src/screens/inbox/containers/SupportServiceDialogs.tsx +2 -2
  51. package/src/screens/inbox/containers/ThreadConversationView.tsx +1141 -402
  52. package/src/screens/inbox/containers/ThreadsView.tsx +5 -5
  53. package/src/screens/inbox/hooks/useInboxMessages.ts +34 -0
  54. package/src/screens/inbox/machines/threadsMachine.ts +2 -2
@@ -56,25 +56,177 @@ export default class Bubble extends React.Component<any> {
56
56
  }
57
57
 
58
58
  renderMessageImage() {
59
- if (this.props.currentMessage.image) {
60
- const { containerStyle, wrapperStyle, ...messageImageProps } = this.props;
59
+ const { currentMessage, containerStyle, wrapperStyle, ...messageImageProps } = this.props;
60
+
61
+ // Check if we have multiple images
62
+ if (currentMessage.images && Array.isArray(currentMessage.images) && currentMessage.images.length > 0) {
63
+ // Filter out any invalid or empty image URLs first
64
+ const validImages = currentMessage.images.filter((url) => url && typeof url === 'string');
65
+
66
+ // If no valid images after filtering, don't render anything
67
+ if (validImages.length === 0) {
68
+ return null;
69
+ }
70
+
71
+ // Render multiple images in a scrollable horizontal row
72
+ return (
73
+ <View style={{ marginVertical: 0 }}>
74
+ <View
75
+ style={{
76
+ flexDirection: 'row',
77
+ flexWrap: 'wrap',
78
+ gap: 8,
79
+ }}
80
+ >
81
+ {validImages.map((imageUrl, index) => {
82
+ // Check if this is a local image
83
+ const isLocalImage =
84
+ imageUrl.startsWith('file:') ||
85
+ imageUrl.startsWith('data:') ||
86
+ imageUrl.startsWith('content:') ||
87
+ (!imageUrl.startsWith('http://') && !imageUrl.startsWith('https://'));
88
+
89
+ const imageSize =
90
+ validImages.length === 1
91
+ ? { width: windowWidth * 0.6, height: windowWidth * 0.4 }
92
+ : { width: windowWidth * 0.3, height: windowWidth * 0.3 };
93
+
94
+ // Show upload indicator if this message is uploading
95
+ const isUploading = currentMessage.isUploading;
96
+
97
+ return (
98
+ <TouchableHighlight
99
+ key={`image-${index}-${currentMessage._id}`}
100
+ underlayColor={'transparent'}
101
+ onPress={() => {
102
+ // Don't allow viewing while uploading
103
+ if (isUploading) return;
104
+
105
+ // Create a message-like object with this image for the viewer
106
+ const imageObject = {
107
+ _id: `${currentMessage._id}-img-${index}`,
108
+ image: imageUrl,
109
+ };
110
+ this.props.setImageViewer(imageObject, true);
111
+ }}
112
+ >
113
+ <View
114
+ style={{
115
+ ...imageSize,
116
+ maxHeight: 200,
117
+ borderRadius: 8,
118
+ overflow: 'hidden',
119
+ borderWidth: 1,
120
+ borderColor: '#e0e0e0',
121
+ backgroundColor: '#f7f7f7',
122
+ }}
123
+ >
124
+ {isLocalImage ? (
125
+ // For local images, use direct Image component with no loading state
126
+ <View style={{ width: '100%', height: '100%' }}>
127
+ <MessageImage
128
+ {...messageImageProps}
129
+ currentMessage={{ ...currentMessage, image: imageUrl }}
130
+ imageStyle={{
131
+ width: '100%',
132
+ height: '100%',
133
+ borderRadius: 8,
134
+ }}
135
+ />
136
+
137
+ {/* Show upload indicator if needed */}
138
+ {isUploading && (
139
+ <View
140
+ style={{
141
+ position: 'absolute',
142
+ top: 0,
143
+ left: 0,
144
+ right: 0,
145
+ bottom: 0,
146
+ backgroundColor: 'rgba(0,0,0,0.2)',
147
+ justifyContent: 'center',
148
+ alignItems: 'center',
149
+ }}
150
+ >
151
+ <Text style={{ color: 'white', fontWeight: 'bold' }}>
152
+ Uploading...
153
+ </Text>
154
+ </View>
155
+ )}
156
+ </View>
157
+ ) : (
158
+ // For remote images, use CachedImage with loading placeholder
159
+ <CachedImage
160
+ style={[styles.slackImage, { width: '100%', height: '100%' }]}
161
+ cacheKey={`${currentMessage._id}-img-${index}-slack-bubble-imageKey`}
162
+ source={{
163
+ uri: imageUrl,
164
+ expiresIn: 86400,
165
+ }}
166
+ resizeMode={'cover'}
167
+ alt={'image'}
168
+ placeholderContent={
169
+ <View
170
+ style={[
171
+ styles.slackImage,
172
+ {
173
+ width: '100%',
174
+ height: '100%',
175
+ backgroundColor: '#e1e1e1',
176
+ justifyContent: 'center',
177
+ alignItems: 'center',
178
+ borderRadius: 8,
179
+ },
180
+ ]}
181
+ >
182
+ <Text>{isUploading ? 'Uploading...' : 'Loading...'}</Text>
183
+ </View>
184
+ }
185
+ />
186
+ )}
187
+ </View>
188
+ </TouchableHighlight>
189
+ );
190
+ })}
191
+ </View>
192
+ </View>
193
+ );
194
+ }
195
+
196
+ // Fall back to single image rendering if no images array
197
+ if (currentMessage.image) {
61
198
  if (this.props.renderMessageImage) {
62
199
  return this.props.renderMessageImage(messageImageProps);
63
200
  }
64
- const { image, _id } = messageImageProps?.currentMessage;
201
+ const { image, _id } = currentMessage;
65
202
 
66
203
  // Add validation for image URL
67
204
  if (!image || typeof image !== 'string') {
68
205
  return null;
69
206
  }
70
207
 
208
+ // Check if this is a local image (from device camera/library)
209
+ const isLocalImage =
210
+ image.startsWith('file:') ||
211
+ image.startsWith('data:') ||
212
+ image.startsWith('content:') ||
213
+ // Check if the image is a pendingUpload by checking if it doesn't start with http/https
214
+ (!image.startsWith('http://') && !image.startsWith('https://'));
215
+
216
+ // Check uploading state
217
+ const isUploading = currentMessage.isUploading;
218
+
71
219
  // Class components can't use hooks like useMemo
72
220
  // Directly render the CachedImage instead
73
221
  return (
74
222
  <TouchableHighlight
75
223
  underlayColor={'transparent'}
76
- style={{ width: '100%', marginVertical: 5 }}
77
- onPress={() => this.props.setImageViewer(messageImageProps?.currentMessage, true)}
224
+ style={{ width: '100%', marginVertical: 0 }}
225
+ onPress={() => {
226
+ // Don't allow viewing while uploading
227
+ if (isUploading) return;
228
+ this.props.setImageViewer(currentMessage, true);
229
+ }}
78
230
  >
79
231
  <View
80
232
  style={{
@@ -88,37 +240,71 @@ export default class Bubble extends React.Component<any> {
88
240
  backgroundColor: '#f7f7f7',
89
241
  }}
90
242
  >
91
- <CachedImage
92
- style={[styles.slackImage, { width: '100%', height: '100%' }]}
93
- cacheKey={`${_id}-slack-bubble-imageKey`}
94
- source={{
95
- uri: image,
96
- expiresIn: 86400,
97
- }}
98
- resizeMode={'cover'}
99
- alt={'image'}
100
- placeholderContent={
101
- <View
102
- style={[
103
- styles.slackImage,
104
- {
105
- width: '100%',
106
- height: '100%',
107
- backgroundColor: '#e1e1e1',
243
+ {isLocalImage ? (
244
+ // For local images, use direct Image component with no loading state
245
+ <View style={{ width: '100%', height: '100%', position: 'relative' }}>
246
+ <MessageImage
247
+ {...messageImageProps}
248
+ imageStyle={{
249
+ width: '100%',
250
+ height: '100%',
251
+ borderRadius: 8,
252
+ }}
253
+ />
254
+
255
+ {/* Show upload indicator if needed */}
256
+ {isUploading && (
257
+ <View
258
+ style={{
259
+ position: 'absolute',
260
+ top: 0,
261
+ left: 0,
262
+ right: 0,
263
+ bottom: 0,
264
+ backgroundColor: 'rgba(0,0,0,0.2)',
108
265
  justifyContent: 'center',
109
266
  alignItems: 'center',
110
- borderRadius: 8,
111
- },
112
- ]}
113
- >
114
- <Text>Loading...</Text>
115
- </View>
116
- }
117
- />
267
+ }}
268
+ >
269
+ <Text style={{ color: 'white', fontWeight: 'bold' }}>Uploading...</Text>
270
+ </View>
271
+ )}
272
+ </View>
273
+ ) : (
274
+ // For remote images, use CachedImage with loading placeholder
275
+ <CachedImage
276
+ style={[styles.slackImage, { width: '100%', height: '100%' }]}
277
+ cacheKey={`${_id}-slack-bubble-imageKey`}
278
+ source={{
279
+ uri: image,
280
+ expiresIn: 86400,
281
+ }}
282
+ resizeMode={'cover'}
283
+ alt={'image'}
284
+ placeholderContent={
285
+ <View
286
+ style={[
287
+ styles.slackImage,
288
+ {
289
+ width: '100%',
290
+ height: '100%',
291
+ backgroundColor: '#e1e1e1',
292
+ justifyContent: 'center',
293
+ alignItems: 'center',
294
+ borderRadius: 8,
295
+ },
296
+ ]}
297
+ >
298
+ <Text>{isUploading ? 'Uploading...' : 'Loading...'}</Text>
299
+ </View>
300
+ }
301
+ />
302
+ )}
118
303
  </View>
119
304
  </TouchableHighlight>
120
305
  );
121
306
  }
307
+
122
308
  return null;
123
309
  }
124
310
 
@@ -0,0 +1,41 @@
1
+ import { useEffect } from 'react';
2
+
3
+ /**
4
+ * Shared SubscriptionHandler for Apollo subscribeToMore
5
+ *
6
+ * @param subscribeToMore - Apollo subscribeToMore function
7
+ * @param document - GraphQL subscription document
8
+ * @param variables - Variables for the subscription
9
+ * @param updateQuery - Apollo updateQuery function
10
+ * @param onError - Optional error handler
11
+ * @param enabled - If false, disables the subscription
12
+ */
13
+ export function SubscriptionHandler({
14
+ subscribeToMore,
15
+ document,
16
+ variables,
17
+ updateQuery,
18
+ onError,
19
+ enabled = true,
20
+ }: {
21
+ subscribeToMore: Function;
22
+ document: any;
23
+ variables: Record<string, any>;
24
+ updateQuery: (prev: any, { subscriptionData }: any) => any;
25
+ onError?: (error: any) => void;
26
+ enabled?: boolean;
27
+ }) {
28
+ useEffect(() => {
29
+ if (!enabled) return;
30
+ const unsubscribe = subscribeToMore({
31
+ document,
32
+ variables,
33
+ updateQuery,
34
+ onError,
35
+ });
36
+ return () => {
37
+ if (unsubscribe && typeof unsubscribe === 'function') unsubscribe();
38
+ };
39
+ }, [subscribeToMore, document, JSON.stringify(variables), updateQuery, onError, enabled]);
40
+ return null;
41
+ }
@@ -16,14 +16,13 @@ import { format, isToday, isYesterday } from 'date-fns';
16
16
  import { useFocusEffect } from '@react-navigation/native';
17
17
  import { IChannel, IUserAccount } from 'common';
18
18
  import {
19
+ THREAD_CREATED_UPDATED,
20
+ CHAT_MESSAGE_ADDED,
19
21
  useThreadMessagesQuery,
22
+ useThreadCreatedUpdatedSubscription,
23
+ useThreadChatMessageAddedSubscription,
20
24
  useMessagesQuery,
21
- useUserAccountQuery,
22
- useOnThreadCreatedUpdatedSubscription,
23
- useOnThreadChatMessageAddedSubscription,
24
- OnThreadCreatedUpdatedDocument as THREAD_CHAT_ADDED,
25
- OnThreadChatMessageAddedDocument as CHAT_MESSAGE_ADDED,
26
- } from 'common/graphql';
25
+ } from '../../../queries/inboxQueries';
27
26
  import { startCase } from 'lodash-es';
28
27
  import colors from 'tailwindcss/colors';
29
28
 
@@ -204,7 +203,7 @@ export const SupportServiceDialogsListItemComponent: React.FC<IDialogListItemPro
204
203
  lastMessage={lastMessage}
205
204
  subscribeToNewMessages={() =>
206
205
  subscribeToMore({
207
- document: THREAD_CHAT_ADDED,
206
+ document: THREAD_CREATED_UPDATED,
208
207
  variables: {
209
208
  channelId: channel?.id?.toString(),
210
209
  postParentId: postParentId ? servicePostParentId : null,