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

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 +4 -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 +631 -488
  22. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  23. package/lib/screens/inbox/containers/Dialogs.js +96 -180
  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 +3 -3
  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 +1105 -667
  49. package/src/screens/inbox/containers/Dialogs.tsx +195 -341
  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
@@ -1,4 +1,4 @@
1
- import React__default,{useState,useRef,useMemo,useEffect,useCallback}from'react';import {Box,Button,ButtonText,HStack,Avatar,AvatarFallbackText,AvatarImage,Text,Image,Spinner,Skeleton}from'@admin-layout/gluestack-ui-mobile';import {Platform,View,TouchableHighlight}from'react-native';import {useNavigation,useIsFocused,useFocusEffect}from'@react-navigation/native';import {navigationRef}from'@common-stack/client-react';import {useSelector}from'react-redux';import {uniqBy,orderBy,startCase}from'lodash-es';import*as ImagePicker from'expo-image-picker';import {MaterialCommunityIcons,Ionicons}from'@expo/vector-icons';import {Send,MessageText,InputToolbar,GiftedChat,Actions}from'react-native-gifted-chat';import {RoomType,PreDefinedRole}from'common';import {useAddDirectChannelMutation,useSendMessagesMutation,useSendExpoNotificationOnPostMutation,useMessagesQuery,MessagesDocument,OnChatMessageAddedDocument}from'common/graphql';import {useUploadFilesNative}from'@messenger-box/platform-client';import {objectId}from'@messenger-box/core';import {userSelector}from'@adminide-stack/user-auth0-client';import {isToday,isYesterday,format}from'date-fns';import Message from'../components/SlackMessageContainer/SlackMessage.js';import ImageViewerModal from'../components/SlackMessageContainer/ImageViewerModal.js';import CachedImage from'../components/CachedImage/index.js';import {config}from'../config/config.js';import colors from'tailwindcss/colors';var __defProp = Object.defineProperty;
1
+ import React__default,{useState,useRef,useMemo,useEffect,useCallback}from'react';import {useToast,Box,Button,ButtonText,HStack,Avatar,AvatarFallbackText,AvatarImage,Text,ScrollView,Image,Spinner}from'@admin-layout/gluestack-ui-mobile';import {Platform,View,TouchableHighlight,TouchableOpacity,TextInput,KeyboardAvoidingView,Animated}from'react-native';import {useNavigation,useIsFocused,useFocusEffect}from'@react-navigation/native';import {navigationRef}from'@common-stack/client-react';import {useSelector,shallowEqual}from'react-redux';import {uniqBy,orderBy,startCase}from'lodash-es';import*as ImagePicker from'expo-image-picker';import {MaterialCommunityIcons,Ionicons,MaterialIcons}from'@expo/vector-icons';import {Send,MessageText}from'react-native-gifted-chat';import {FileRefType,RoomType,PreDefinedRole}from'common';import {useAddDirectChannel,useSendChannelMessage,useSendExpoNotification,MESSAGES_DOCUMENT,CHAT_MESSAGE_ADDED,useChannelMessagesQuery}from'../../../queries/inboxQueries.js';import {useUploadFilesNative}from'@messenger-box/platform-client';import {objectId}from'@messenger-box/core';import {userSelector}from'@adminide-stack/user-auth0-client';import {isToday,isYesterday,format}from'date-fns';import Message from'../components/SlackMessageContainer/SlackMessage.js';import ImageViewerModal from'../components/SlackMessageContainer/ImageViewerModal.js';import CachedImage from'../components/CachedImage/index.js';import {config}from'../config/config.js';import colors from'tailwindcss/colors';import {SubscriptionHandler}from'../components/SubscriptionHandler.js';import {useInboxMessages}from'../hooks/useInboxMessages.js';import'react-native-reanimated';import'expo-constants';import {GiftedChatInboxComponent}from'../components/GiftedChatInboxComponent.js';var __defProp = Object.defineProperty;
2
2
  var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -46,6 +46,56 @@ const createdAtText = (value) => {
46
46
  return "Yesterday";
47
47
  return format(new Date(value), "MMM dd, yyyy");
48
48
  };
49
+ const ErrorNotification = ({
50
+ message,
51
+ onClose,
52
+ type = "error"
53
+ }) => {
54
+ const opacity = useRef(new Animated.Value(0)).current;
55
+ const bgColor = type === "error" ? "#f44336" : "#ff9800";
56
+ const title = type === "error" ? "Error" : "Warning";
57
+ useEffect(() => {
58
+ Animated.timing(opacity, {
59
+ toValue: 1,
60
+ duration: 300,
61
+ useNativeDriver: true
62
+ }).start();
63
+ const timer = setTimeout(() => {
64
+ Animated.timing(opacity, {
65
+ toValue: 0,
66
+ duration: 300,
67
+ useNativeDriver: true
68
+ }).start(() => onClose && onClose());
69
+ }, 4e3);
70
+ return () => clearTimeout(timer);
71
+ }, []);
72
+ return /* @__PURE__ */ React__default.createElement(Animated.View, { style: {
73
+ position: "absolute",
74
+ top: 10,
75
+ left: 10,
76
+ right: 10,
77
+ backgroundColor: bgColor,
78
+ padding: 15,
79
+ borderRadius: 8,
80
+ shadowColor: "#000",
81
+ shadowOffset: {
82
+ width: 0,
83
+ height: 2
84
+ },
85
+ shadowOpacity: 0.25,
86
+ shadowRadius: 3.84,
87
+ elevation: 5,
88
+ zIndex: 1e3,
89
+ opacity
90
+ } }, /* @__PURE__ */ React__default.createElement(HStack, { className: "items-center justify-between" }, /* @__PURE__ */ React__default.createElement(Text, { style: {
91
+ color: "white",
92
+ fontWeight: "bold"
93
+ } }, title), /* @__PURE__ */ React__default.createElement(TouchableOpacity, { onPress: onClose }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "close", size: 20, color: "white" }))), /* @__PURE__ */ React__default.createElement(Text, { style: {
94
+ color: "white",
95
+ marginTop: 5
96
+ } }, message));
97
+ };
98
+ Platform.OS === "ios" ? 20 : 0;
49
99
  const ConversationViewComponent = (_a) => {
50
100
  var _b = _a, {
51
101
  channelId: initialChannelId,
@@ -59,7 +109,6 @@ const ConversationViewComponent = (_a) => {
59
109
  var _a2, _b2, _c, _d;
60
110
  const [channelId, setChannelId] = useState(initialChannelId || null);
61
111
  const [messageText, setMessageText] = useState("");
62
- const [skip, setSkip] = useState(0);
63
112
  const [loading, setLoading] = useState(false);
64
113
  const [loadingOldMessages, setLoadingOldMessages] = useState(false);
65
114
  const [error, setError] = useState(null);
@@ -67,40 +116,44 @@ const ConversationViewComponent = (_a) => {
67
116
  const [images, setImages] = useState([]);
68
117
  const [isShowImageViewer, setImageViewer] = useState(false);
69
118
  const [imageObject, setImageObject] = useState({});
119
+ const [errorMessage, setErrorMessage] = useState("");
120
+ const [notificationType, setNotificationType] = useState("error");
121
+ const [isActionSheetVisible, setActionSheetVisible] = useState(false);
122
+ const [bottomMargin, setBottomMargin] = useState(0);
70
123
  const messageRootListRef = useRef(null);
124
+ const textInputRef = useRef(null);
71
125
  const isMounted = useRef(true);
72
126
  const fetchOldDebounceRef = useRef(false);
73
- const auth = useSelector(userSelector);
127
+ const auth = useSelector(userSelector, shallowEqual);
74
128
  const currentRoute = navigationRef.isReady() ? (_a2 = navigationRef) == null ? void 0 : _a2.getCurrentRoute() : null;
75
129
  const navigation = useNavigation();
76
130
  const isFocused = useIsFocused();
77
- const [addDirectChannel] = useAddDirectChannelMutation();
131
+ const [addDirectChannel] = useAddDirectChannel();
78
132
  const {
79
133
  startUpload
80
134
  } = useUploadFilesNative();
81
- const [sendMsg] = useSendMessagesMutation();
82
- const [sendExpoNotificationOnPostMutation] = useSendExpoNotificationOnPostMutation();
135
+ const [sendMsg] = useSendChannelMessage();
136
+ const [sendExpoNotification] = useSendExpoNotification();
137
+ const [skip, setSkip] = useState(0);
83
138
  const {
84
139
  data,
85
140
  loading: messageLoading,
86
141
  refetch,
87
- fetchMore: fetchMoreMessages,
88
- subscribeToMore
89
- } = useMessagesQuery({
90
- variables: {
142
+ subscribe
143
+ } = useInboxMessages({
144
+ useQueryHook: useChannelMessagesQuery,
145
+ queryVariables: {
91
146
  channelId: channelId == null ? void 0 : channelId.toString(),
92
147
  parentId: null,
93
148
  limit: MESSAGES_PER_PAGE,
94
149
  skip
95
150
  },
96
- skip: !channelId,
97
- fetchPolicy: "cache-and-network",
98
- nextFetchPolicy: "cache-first",
99
- refetchWritePolicy: "merge",
100
- notifyOnNetworkStatusChange: true,
101
- onError: (error2) => {
102
- setError(String(error2));
103
- }
151
+ subscriptionDocument: CHAT_MESSAGE_ADDED,
152
+ subscriptionVariables: {
153
+ channelId: channelId == null ? void 0 : channelId.toString()
154
+ },
155
+ updateQuery: void 0,
156
+ onError: (err) => setError(String(err))
104
157
  });
105
158
  const channelMessages = useMemo(() => {
106
159
  var _a3;
@@ -126,25 +179,18 @@ const ConversationViewComponent = (_a) => {
126
179
  if (channelId) {
127
180
  refetch();
128
181
  }
129
- return () => {
130
- };
131
- }, [channelId, isFocused, refetch]));
132
- useEffect(() => {
133
- if (selectedImage) {
134
- setLoading(false);
135
- }
136
- }, [selectedImage]);
182
+ }, [isFocused, refetch]));
137
183
  const fetchMoreMessagesImpl = useCallback(async () => {
138
184
  var _a3, _b3;
139
185
  try {
140
186
  setLoadingOldMessages(true);
141
- const response = await fetchMoreMessages({
142
- variables: {
143
- channelId: channelId == null ? void 0 : channelId.toString(),
144
- parentId: null,
145
- skip: channelMessages.length
146
- }
187
+ const response = await refetch({
188
+ channelId: channelId == null ? void 0 : channelId.toString(),
189
+ parentId: null,
190
+ limit: MESSAGES_PER_PAGE,
191
+ skip: channelMessages.length
147
192
  });
193
+ setSkip(channelMessages.length);
148
194
  setLoadingOldMessages(false);
149
195
  if (!((_b3 = (_a3 = response == null ? void 0 : response.data) == null ? void 0 : _a3.messages) == null ? void 0 : _b3.data)) {
150
196
  return {
@@ -161,9 +207,9 @@ const ConversationViewComponent = (_a) => {
161
207
  error: String(error2)
162
208
  };
163
209
  }
164
- }, [channelId, channelMessages.length, fetchMoreMessages]);
210
+ }, [channelId, channelMessages.length, refetch]);
165
211
  const sendMessageImpl = useCallback(async () => {
166
- var _a3;
212
+ var _a3, _b3, _c2, _d2, _e, _f, _g, _h;
167
213
  try {
168
214
  const currentMessageText = messageText;
169
215
  setMessageText("");
@@ -188,12 +234,13 @@ const ConversationViewComponent = (_a) => {
188
234
  author: {
189
235
  __typename: "UserAccount",
190
236
  id: auth == null ? void 0 : auth.id,
191
- picture: (auth == null ? void 0 : auth.picture) || "",
192
- givenName: (auth == null ? void 0 : auth.givenName) || "",
193
- familyName: (auth == null ? void 0 : auth.familyName) || "",
194
- email: (auth == null ? void 0 : auth.email) || "",
195
- username: (auth == null ? void 0 : auth.username) || "",
196
- alias: [],
237
+ givenName: ((_a3 = auth == null ? void 0 : auth.profile) == null ? void 0 : _a3.given_name) || "",
238
+ familyName: ((_b3 = auth == null ? void 0 : auth.profile) == null ? void 0 : _b3.family_name) || "",
239
+ email: ((_c2 = auth == null ? void 0 : auth.profile) == null ? void 0 : _c2.email) || "",
240
+ username: ((_d2 = auth == null ? void 0 : auth.profile) == null ? void 0 : _d2.nickname) || "",
241
+ fullName: ((_e = auth == null ? void 0 : auth.profile) == null ? void 0 : _e.name) || "",
242
+ picture: ((_f = auth == null ? void 0 : auth.profile) == null ? void 0 : _f.picture) || "",
243
+ alias: [(_g = auth == null ? void 0 : auth.authUserId) != null ? _g : ""],
197
244
  tokens: []
198
245
  },
199
246
  isDelivered: true,
@@ -234,45 +281,51 @@ const ConversationViewComponent = (_a) => {
234
281
  update: (cache, {
235
282
  data: data2
236
283
  }) => {
237
- if (data2 == null ? void 0 : data2.sendMessage) {
238
- try {
239
- const existingData = cache.readQuery({
240
- query: MessagesDocument,
241
- variables: {
242
- channelId: channelId == null ? void 0 : channelId.toString(),
243
- parentId: null,
244
- limit: MESSAGES_PER_PAGE,
245
- skip: 0
246
- }
247
- });
248
- if (!existingData)
249
- return;
250
- cache.writeQuery({
251
- query: MessagesDocument,
252
- variables: {
253
- channelId: channelId == null ? void 0 : channelId.toString(),
254
- parentId: null,
255
- limit: MESSAGES_PER_PAGE,
256
- skip: 0
257
- },
258
- data: {
259
- messages: __spreadProps(__spreadValues({}, existingData.messages), {
260
- data: [data2.sendMessage, ...existingData.messages.data],
261
- totalCount: (existingData.messages.totalCount || 0) + 1
262
- })
284
+ if (!(data2 == null ? void 0 : data2.sendMessage))
285
+ return;
286
+ try {
287
+ cache.writeQuery({
288
+ query: MESSAGES_DOCUMENT,
289
+ variables: {
290
+ channelId: channelId == null ? void 0 : channelId.toString(),
291
+ parentId: null,
292
+ limit: MESSAGES_PER_PAGE,
293
+ skip: 0
294
+ },
295
+ data: {
296
+ messages: {
297
+ __typename: "Messages",
298
+ messagesRefId: channelId,
299
+ data: [data2.sendMessage],
300
+ totalCount: 1
263
301
  }
264
- });
265
- } catch (error2) {
266
- console.error("Error updating cache:", error2);
302
+ }
303
+ });
304
+ } catch (error2) {
305
+ console.error("Error updating cache:", error2);
306
+ let errorMsg = "Failed to update message cache";
307
+ if (__DEV__ && error2) {
308
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Cache update failed";
267
309
  }
310
+ setNotificationType("error");
311
+ setErrorMessage(errorMsg);
268
312
  }
269
313
  }
270
314
  });
315
+ setIsUploadingImage(false);
316
+ setLoading(false);
271
317
  return {
272
- message: (_a3 = response.data) == null ? void 0 : _a3.sendMessage
318
+ message: (_h = response.data) == null ? void 0 : _h.sendMessage
273
319
  };
274
320
  } catch (error2) {
275
321
  setLoading(false);
322
+ setIsUploadingImage(false);
323
+ let errorMsg = "Failed to send message";
324
+ if (__DEV__ && error2) {
325
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Message sending failed";
326
+ }
327
+ setNotificationType("error");
328
+ setErrorMessage(errorMsg);
276
329
  setError(String(error2));
277
330
  return {
278
331
  error: String(error2)
@@ -280,32 +333,42 @@ const ConversationViewComponent = (_a) => {
280
333
  }
281
334
  }, [channelId, messageText, sendMsg, auth]);
282
335
  const onSelectImages = async () => {
283
- var _a3;
284
336
  setLoading(true);
285
337
  try {
286
338
  let imageSource = await ImagePicker.launchImageLibraryAsync({
287
339
  mediaTypes: ImagePicker.MediaTypeOptions.Images,
288
- allowsEditing: true,
340
+ allowsEditing: false,
289
341
  aspect: [4, 3],
290
342
  quality: 0.8,
291
343
  base64: true,
292
- exif: false
344
+ exif: false,
345
+ allowsMultipleSelection: true
293
346
  });
294
347
  if (!(imageSource == null ? void 0 : imageSource.canceled)) {
295
- const selectedAsset = (_a3 = imageSource == null ? void 0 : imageSource.assets) == null ? void 0 : _a3[0];
296
- if (!selectedAsset) {
348
+ const selectedAssets = (imageSource == null ? void 0 : imageSource.assets) || [];
349
+ if (selectedAssets.length === 0) {
297
350
  setLoading(false);
298
351
  return;
299
352
  }
300
- const base64Data = selectedAsset.base64;
301
- const previewImage = base64Data ? `data:image/jpeg;base64,${base64Data}` : selectedAsset.uri;
302
- const asset = __spreadProps(__spreadValues({}, selectedAsset), {
303
- url: selectedAsset.uri,
304
- fileName: selectedAsset.fileName || `image_${Date.now()}.jpg`,
305
- mimeType: "image/jpeg"
353
+ const newImages = selectedAssets.map((selectedAsset) => {
354
+ const base64Data = selectedAsset.base64;
355
+ const previewImage = base64Data ? `data:image/jpeg;base64,${base64Data}` : selectedAsset.uri;
356
+ const asset = __spreadProps(__spreadValues({}, selectedAsset), {
357
+ url: selectedAsset.uri,
358
+ fileName: selectedAsset.fileName || `image_${Date.now()}.jpg`,
359
+ mimeType: "image/jpeg"
360
+ });
361
+ return asset;
306
362
  });
307
- setSelectedImage(previewImage);
308
- setImages([asset]);
363
+ if (newImages.length > 0) {
364
+ const base64Data = newImages[0].base64;
365
+ const previewImage = base64Data ? `data:image/jpeg;base64,${base64Data}` : newImages[0].uri;
366
+ setSelectedImage(previewImage);
367
+ }
368
+ setImages((currentImages) => [...currentImages, ...newImages]);
369
+ if (!isActionSheetVisible) {
370
+ setActionSheetVisible(true);
371
+ }
309
372
  } else {
310
373
  setLoading(false);
311
374
  }
@@ -314,12 +377,72 @@ const ConversationViewComponent = (_a) => {
314
377
  }
315
378
  };
316
379
  const [uploadingMessageId, setUploadingMessageId] = useState(null);
380
+ const [pendingUploads, setPendingUploads] = useState({});
381
+ const [uploadErrors, setUploadErrors] = useState({});
382
+ const [isUploadingImage, setIsUploadingImage] = useState(false);
383
+ useEffect(() => {
384
+ if (images.length === 0) {
385
+ setIsUploadingImage(false);
386
+ }
387
+ }, [images]);
388
+ useToast();
389
+ const removeMessageFromUI = useCallback((messageId) => {
390
+ setPendingUploads((prev) => {
391
+ const newPending = __spreadValues({}, prev);
392
+ delete newPending[messageId];
393
+ return newPending;
394
+ });
395
+ setUploadErrors((prev) => {
396
+ const newErrors = __spreadValues({}, prev);
397
+ delete newErrors[messageId];
398
+ return newErrors;
399
+ });
400
+ setIsUploadingImage(false);
401
+ }, []);
317
402
  const sendMessageWithFileImpl = useCallback(async () => {
318
- var _a3, _b3, _c2, _d2, _e, _f;
403
+ var _a3, _b3, _c2, _d2, _e, _f, _g;
319
404
  try {
320
- setLoading(true);
321
405
  const postId = objectId();
322
- setUploadingMessageId(postId);
406
+ setIsUploadingImage(true);
407
+ setLoading(false);
408
+ setUploadingMessageId(null);
409
+ if (!images || images.length === 0) {
410
+ setIsUploadingImage(false);
411
+ setLoading(false);
412
+ return {
413
+ error: "No images available to upload"
414
+ };
415
+ }
416
+ const currentMessageText = messageText;
417
+ const currentImages = [...images];
418
+ const imageUris = currentImages.map((img) => img.uri || img.url);
419
+ setMessageText("");
420
+ setSelectedImage("");
421
+ setImages([]);
422
+ const clientMessage = {
423
+ _id: postId,
424
+ text: currentMessageText || " ",
425
+ createdAt: new Date(),
426
+ user: {
427
+ _id: (auth == null ? void 0 : auth.id) || "",
428
+ name: `${(auth == null ? void 0 : auth.givenName) || ""} ${(auth == null ? void 0 : auth.familyName) || ""}`,
429
+ avatar: (auth == null ? void 0 : auth.picture) || ""
430
+ },
431
+ image: imageUris[0],
432
+ images: imageUris,
433
+ sent: true,
434
+ received: true,
435
+ pending: false,
436
+ type: "TEXT",
437
+ replies: {
438
+ data: [],
439
+ totalCount: 0
440
+ },
441
+ isShowThreadMessage: false
442
+ };
443
+ setPendingUploads((prev) => __spreadProps(__spreadValues({}, prev), {
444
+ [postId]: clientMessage
445
+ }));
323
446
  const notificationData = {
324
447
  url: config.INBOX_MESSEGE_PATH,
325
448
  params: {
@@ -331,23 +454,6 @@ const ConversationViewComponent = (_a) => {
331
454
  sound: Platform.OS === "android" ? void 0 : "default"
332
455
  }
333
456
  };
334
- if (!images || images.length === 0) {
335
- setLoading(false);
336
- setUploadingMessageId(null);
337
- return {
338
- error: "No images available to upload"
339
- };
340
- }
341
- const imagesToUpload = images.map((img) => {
342
- return __spreadProps(__spreadValues({}, img), {
343
- uri: img.uri || img.url,
344
- type: "image/jpeg",
345
- name: img.fileName || `image_${Date.now()}.jpg`
346
- });
347
- });
348
- const currentMessageText = messageText;
349
- setMessageText("");
350
- const fileId = objectId();
351
457
  const optimisticMessage = {
352
458
  __typename: "Post",
353
459
  id: postId,
@@ -357,12 +463,13 @@ const ConversationViewComponent = (_a) => {
357
463
  author: {
358
464
  __typename: "UserAccount",
359
465
  id: auth == null ? void 0 : auth.id,
360
- picture: (auth == null ? void 0 : auth.picture) || "",
361
- givenName: (auth == null ? void 0 : auth.givenName) || "",
362
- familyName: (auth == null ? void 0 : auth.familyName) || "",
363
- email: (auth == null ? void 0 : auth.email) || "",
364
- username: (auth == null ? void 0 : auth.username) || "",
365
- alias: [],
466
+ givenName: ((_a3 = auth == null ? void 0 : auth.profile) == null ? void 0 : _a3.given_name) || "",
467
+ familyName: ((_b3 = auth == null ? void 0 : auth.profile) == null ? void 0 : _b3.family_name) || "",
468
+ email: ((_c2 = auth == null ? void 0 : auth.profile) == null ? void 0 : _c2.email) || "",
469
+ username: ((_d2 = auth == null ? void 0 : auth.profile) == null ? void 0 : _d2.nickname) || "",
470
+ fullName: ((_e = auth == null ? void 0 : auth.profile) == null ? void 0 : _e.name) || "",
471
+ picture: ((_f = auth == null ? void 0 : auth.profile) == null ? void 0 : _f.picture) || "",
472
+ alias: [(_g = auth == null ? void 0 : auth.authUserId) != null ? _g : ""],
366
473
  tokens: []
367
474
  },
368
475
  isDelivered: true,
@@ -381,20 +488,21 @@ const ConversationViewComponent = (_a) => {
381
488
  props: {},
382
489
  files: {
383
490
  __typename: "FilesInfo",
384
- data: [{
491
+ data: imageUris.map((uri, index) => ({
385
492
  __typename: "FileInfo",
386
- id: fileId,
387
- url: selectedImage,
388
- name: ((_a3 = imagesToUpload[0]) == null ? void 0 : _a3.name) || "image.jpg",
493
+ id: `temp-file-${index}-${postId}`,
494
+ url: uri,
495
+ name: `image-${index}.jpg`,
389
496
  extension: "jpg",
390
497
  mimeType: "image/jpeg",
391
- height: ((_b3 = imagesToUpload[0]) == null ? void 0 : _b3.height) || 0,
392
- width: ((_c2 = imagesToUpload[0]) == null ? void 0 : _c2.width) || 0,
393
- size: ((_d2 = imagesToUpload[0]) == null ? void 0 : _d2.fileSize) || 0,
394
- refType: "Post",
395
- ref: postId
396
- }],
397
- totalCount: 1
498
+ size: 0,
499
+ height: 300,
500
+ width: 300,
501
+ channel: null,
502
+ post: null,
503
+ refType: FileRefType.Post
504
+ })),
505
+ totalCount: imageUris.length
398
506
  },
399
507
  replies: {
400
508
  __typename: "Messages",
@@ -402,137 +510,149 @@ const ConversationViewComponent = (_a) => {
402
510
  totalCount: 0
403
511
  }
404
512
  };
405
- const uploadResponse = await startUpload({
406
- file: imagesToUpload,
407
- saveUploadedFile: {
408
- variables: {
409
- postId
410
- }
411
- },
412
- createUploadLink: {
413
- variables: {
414
- postId
513
+ setTimeout(async () => {
514
+ var _a4;
515
+ try {
516
+ const imagesToUpload = currentImages.map((img) => __spreadProps(__spreadValues({}, img), {
517
+ uri: img.uri || img.url,
518
+ type: img.mimeType || "image/jpeg",
519
+ name: img.fileName || `image_${Date.now()}.jpg`
520
+ }));
521
+ const uploadResponse = await startUpload({
522
+ file: imagesToUpload,
523
+ saveUploadedFile: {
524
+ variables: {
525
+ postId
526
+ }
527
+ },
528
+ createUploadLink: {
529
+ variables: {
530
+ postId
531
+ }
532
+ }
533
+ });
534
+ if (uploadResponse == null ? void 0 : uploadResponse.error) {
535
+ console.error("Upload error:", uploadResponse.error);
536
+ let errorMsg = "Failed to upload image. Please try again.";
537
+ if (__DEV__ && uploadResponse.error) {
538
+ errorMsg = typeof uploadResponse.error === "string" ? uploadResponse.error : uploadResponse.error.message || errorMsg;
539
+ }
540
+ setNotificationType("error");
541
+ setErrorMessage(errorMsg);
542
+ setUploadErrors((prev) => __spreadProps(__spreadValues({}, prev), {
543
+ [postId]: errorMsg
544
+ }));
545
+ removeMessageFromUI(postId);
546
+ setIsUploadingImage(false);
547
+ setLoading(false);
548
+ return;
415
549
  }
416
- }
417
- });
418
- if (uploadResponse == null ? void 0 : uploadResponse.error) {
419
- setLoading(false);
420
- setUploadingMessageId(null);
421
- return {
422
- error: String(uploadResponse.error)
423
- };
424
- }
425
- const uploadedFiles = uploadResponse.data;
426
- const files = (_e = uploadedFiles == null ? void 0 : uploadedFiles.map((f) => f.id)) != null ? _e : null;
427
- const realMessage = __spreadProps(__spreadValues({}, optimisticMessage), {
428
- files: {
429
- __typename: "FilesInfo",
430
- data: uploadedFiles.map((file) => ({
431
- __typename: "FileInfo",
432
- id: file.id,
433
- url: file.url,
434
- name: file.name,
435
- extension: file.extension,
436
- mimeType: file.mimeType,
437
- height: file.height,
438
- width: file.width,
439
- size: file.size,
440
- refType: file.refType,
441
- ref: postId
442
- })),
443
- totalCount: uploadedFiles.length
444
- }
445
- });
446
- const response = await sendMsg({
447
- variables: {
448
- postId,
449
- channelId,
450
- content: currentMessageText || " ",
451
- files,
452
- notificationParams: notificationData
453
- },
454
- optimisticResponse: {
455
- __typename: "Mutation",
456
- sendMessage: realMessage
457
- },
458
- update: (cache, {
459
- data: data2
460
- }) => {
461
- if (data2 == null ? void 0 : data2.sendMessage) {
462
- try {
463
- const existingData = cache.readQuery({
464
- query: MessagesDocument,
465
- variables: {
466
- channelId: channelId == null ? void 0 : channelId.toString(),
467
- parentId: null,
468
- limit: MESSAGES_PER_PAGE,
469
- skip: 0
470
- }
471
- });
472
- if (!existingData)
473
- return;
474
- const messageWithFiles = __spreadProps(__spreadValues({}, data2.sendMessage), {
475
- files: data2.sendMessage.files || {
476
- __typename: "FilesInfo",
477
- data: uploadedFiles.map((file) => ({
478
- __typename: "FileInfo",
479
- id: file.id,
480
- url: file.url,
481
- name: file.name,
482
- extension: file.extension,
483
- mimeType: file.mimeType,
484
- height: file.height,
485
- width: file.width,
486
- size: file.size,
487
- refType: file.refType,
488
- ref: postId
489
- })),
490
- totalCount: uploadedFiles.length
550
+ const uploadedFiles = uploadResponse.data;
551
+ const fileIds = (_a4 = uploadedFiles == null ? void 0 : uploadedFiles.map((f) => f.id)) != null ? _a4 : null;
552
+ if ((fileIds == null ? void 0 : fileIds.length) > 0) {
553
+ await sendMsg({
554
+ variables: {
555
+ postId,
556
+ channelId,
557
+ content: currentMessageText || " ",
558
+ files: fileIds,
559
+ notificationParams: notificationData
560
+ },
561
+ optimisticResponse: {
562
+ __typename: "Mutation",
563
+ sendMessage: optimisticMessage
564
+ },
565
+ update: (cache, {
566
+ data: data2
567
+ }) => {
568
+ var _a5, _b4;
569
+ if (!(data2 == null ? void 0 : data2.sendMessage)) {
570
+ setIsUploadingImage(false);
571
+ setLoading(false);
572
+ return;
491
573
  }
492
- });
493
- cache.writeQuery({
494
- query: MessagesDocument,
495
- variables: {
496
- channelId: channelId == null ? void 0 : channelId.toString(),
497
- parentId: null,
498
- limit: MESSAGES_PER_PAGE,
499
- skip: 0
500
- },
501
- data: {
502
- messages: __spreadProps(__spreadValues({}, existingData.messages), {
503
- data: [messageWithFiles, ...existingData.messages.data],
504
- totalCount: (existingData.messages.totalCount || 0) + 1
505
- })
574
+ try {
575
+ cache.writeQuery({
576
+ query: MESSAGES_DOCUMENT,
577
+ variables: {
578
+ channelId: channelId == null ? void 0 : channelId.toString(),
579
+ parentId: null,
580
+ limit: MESSAGES_PER_PAGE,
581
+ skip: 0
582
+ },
583
+ data: {
584
+ messages: {
585
+ __typename: "Messages",
586
+ messagesRefId: channelId,
587
+ data: [data2.sendMessage],
588
+ totalCount: 1
589
+ }
590
+ }
591
+ });
592
+ const serverMessage = data2.sendMessage;
593
+ const hasServerImage = (_b4 = (_a5 = serverMessage == null ? void 0 : serverMessage.files) == null ? void 0 : _a5.data) == null ? void 0 : _b4.some((file) => file.url);
594
+ if (hasServerImage) {
595
+ removeMessageFromUI(postId);
596
+ }
597
+ setIsUploadingImage(false);
598
+ setLoading(false);
599
+ } catch (error2) {
600
+ console.error("Cache update error:", error2);
601
+ let errorMsg = "Failed to update message.";
602
+ if (__DEV__ && error2) {
603
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Cache update failed";
604
+ }
605
+ setNotificationType("error");
606
+ setErrorMessage(errorMsg);
607
+ setIsUploadingImage(false);
608
+ setLoading(false);
506
609
  }
507
- });
508
- setSelectedImage("");
509
- setImages([]);
510
- } catch (error2) {
511
- console.error("Error updating cache:", error2);
512
- }
610
+ }
611
+ });
612
+ } else {
613
+ setIsUploadingImage(false);
614
+ setLoading(false);
513
615
  }
616
+ } catch (error2) {
617
+ console.error("Background process error:", error2);
618
+ let errorMsg = "Failed to send image. Please try again.";
619
+ if (__DEV__ && error2) {
620
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Background process failed";
621
+ }
622
+ setNotificationType("error");
623
+ setErrorMessage(errorMsg);
624
+ removeMessageFromUI(postId);
625
+ setIsUploadingImage(false);
626
+ setLoading(false);
514
627
  }
515
- });
516
- setLoading(false);
517
- setUploadingMessageId(null);
628
+ }, 0);
518
629
  return {
519
- message: (_f = response.data) == null ? void 0 : _f.sendMessage
630
+ success: true
520
631
  };
521
632
  } catch (error2) {
522
- setLoading(false);
523
- setUploadingMessageId(null);
633
+ console.error("Send message error:", error2);
634
+ let errorMsg = "Failed to process image. Please try again.";
635
+ if (__DEV__ && error2) {
636
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Image processing failed";
637
+ }
638
+ setNotificationType("error");
639
+ setErrorMessage(errorMsg);
524
640
  setError(String(error2));
641
+ setIsUploadingImage(false);
642
+ setLoading(false);
525
643
  return {
526
644
  error: String(error2)
527
645
  };
528
646
  }
529
- }, [channelId, messageText, images, selectedImage, startUpload, sendMsg, auth]);
647
+ }, [channelId, messageText, images, selectedImage, startUpload, sendMsg, auth, removeMessageFromUI]);
530
648
  const createDirectChannelImpl = useCallback(async () => {
531
649
  var _a3, _b3, _c2, _d2, _e, _f, _g, _h;
532
650
  try {
533
651
  setLoading(true);
534
652
  if (!(rest == null ? void 0 : rest.isCreateNewChannel) || ((_a3 = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _a3.type) !== ((_b3 = RoomType) == null ? void 0 : _b3.Direct) || !((_d2 = (_c2 = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _c2.userIds) == null ? void 0 : _d2.length)) {
535
653
  setLoading(false);
654
+ setNotificationType("error");
655
+ setErrorMessage(__DEV__ ? "Invalid channel data" : "Unable to create conversation");
536
656
  return {
537
657
  error: "Invalid channel data"
538
658
  };
@@ -547,6 +667,8 @@ const ConversationViewComponent = (_a) => {
547
667
  });
548
668
  if (!((_h = (_g = response == null ? void 0 : response.data) == null ? void 0 : _g.createDirectChannel) == null ? void 0 : _h.id)) {
549
669
  setLoading(false);
670
+ setNotificationType("error");
671
+ setErrorMessage(__DEV__ ? "Failed to create channel" : "Unable to create conversation");
550
672
  return {
551
673
  error: "Failed to create channel"
552
674
  };
@@ -580,7 +702,7 @@ const ConversationViewComponent = (_a) => {
580
702
  email: (auth == null ? void 0 : auth.email) || "",
581
703
  username: (auth == null ? void 0 : auth.username) || "",
582
704
  alias: [],
583
- tokens: []
705
+ tokens: (auth == null ? void 0 : auth.token) ? [...auth == null ? void 0 : auth.token] : []
584
706
  },
585
707
  isDelivered: true,
586
708
  isRead: false,
@@ -620,28 +742,34 @@ const ConversationViewComponent = (_a) => {
620
742
  update: (cache, {
621
743
  data: data2
622
744
  }) => {
623
- if (data2 == null ? void 0 : data2.sendMessage) {
624
- try {
625
- cache.writeQuery({
626
- query: MessagesDocument,
627
- variables: {
628
- channelId: newChannelId,
629
- parentId: null,
630
- limit: MESSAGES_PER_PAGE,
631
- skip: 0
632
- },
633
- data: {
634
- messages: {
635
- __typename: "Messages",
636
- messagesRefId: newChannelId,
637
- data: [data2.sendMessage],
638
- totalCount: 1
639
- }
745
+ if (!(data2 == null ? void 0 : data2.sendMessage))
746
+ return;
747
+ try {
748
+ cache.writeQuery({
749
+ query: MESSAGES_DOCUMENT,
750
+ variables: {
751
+ channelId: newChannelId,
752
+ parentId: null,
753
+ limit: MESSAGES_PER_PAGE,
754
+ skip: 0
755
+ },
756
+ data: {
757
+ messages: {
758
+ __typename: "Messages",
759
+ messagesRefId: newChannelId,
760
+ data: [data2.sendMessage],
761
+ totalCount: 1
640
762
  }
641
- });
642
- } catch (error2) {
643
- console.error("Error updating cache:", error2);
763
+ }
764
+ });
765
+ } catch (error2) {
766
+ console.error("Error updating cache:", error2);
767
+ let errorMsg = "Failed to update message cache";
768
+ if (__DEV__ && error2) {
769
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Cache update failed";
644
770
  }
771
+ setNotificationType("error");
772
+ setErrorMessage(errorMsg);
645
773
  }
646
774
  }
647
775
  });
@@ -651,6 +779,12 @@ const ConversationViewComponent = (_a) => {
651
779
  };
652
780
  } catch (error2) {
653
781
  setLoading(false);
782
+ let errorMsg = "Failed to create conversation";
783
+ if (__DEV__ && error2) {
784
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Channel creation failed";
785
+ }
786
+ setNotificationType("error");
787
+ setErrorMessage(errorMsg);
654
788
  setError(String(error2));
655
789
  return {
656
790
  error: String(error2)
@@ -677,25 +811,27 @@ const ConversationViewComponent = (_a) => {
677
811
  return contentSize.height - layoutMeasurement.height - paddingToTop <= contentOffset.y;
678
812
  };
679
813
  const messageList = useMemo(() => {
814
+ const pendingMessages = Object.values(pendingUploads);
680
815
  if (!channelMessages || channelMessages.length === 0) {
681
- return [];
816
+ return pendingMessages;
682
817
  }
683
818
  const filteredMessages = uniqBy(channelMessages, ({
684
819
  id
685
820
  }) => id);
686
- if (filteredMessages.length === 0) {
687
- return [];
688
- }
689
- return orderBy(filteredMessages, ["createdAt"], ["desc"]).map((msg) => {
821
+ const serverMessages = orderBy(filteredMessages, ["createdAt"], ["desc"]).map((msg) => {
690
822
  var _a3, _b3, _c2, _d2, _e;
691
823
  const date = new Date(msg.createdAt);
692
- let imageUrl = null;
824
+ if (pendingUploads[msg.id]) {
825
+ return null;
826
+ }
827
+ let imageUrls = [];
828
+ let primaryImageUrl = null;
693
829
  if (msg.files && typeof msg.files === "object") {
694
830
  const filesData = msg.files.data || (Array.isArray(msg.files) ? msg.files : null);
695
831
  if (filesData && filesData.length > 0) {
696
- const fileData = filesData[0];
697
- if (fileData && typeof fileData === "object" && fileData.url) {
698
- imageUrl = fileData.url;
832
+ imageUrls = filesData.filter((fileData) => fileData && typeof fileData === "object" && fileData.url).map((fileData) => fileData.url);
833
+ if (imageUrls.length > 0) {
834
+ primaryImageUrl = imageUrls[0];
699
835
  }
700
836
  }
701
837
  }
@@ -708,7 +844,8 @@ const ConversationViewComponent = (_a) => {
708
844
  name: `${((_b3 = msg.author) == null ? void 0 : _b3.givenName) || ""} ${((_c2 = msg.author) == null ? void 0 : _c2.familyName) || ""}`,
709
845
  avatar: ((_d2 = msg.author) == null ? void 0 : _d2.picture) || ""
710
846
  },
711
- image: imageUrl,
847
+ image: primaryImageUrl,
848
+ images: imageUrls,
712
849
  sent: msg == null ? void 0 : msg.isDelivered,
713
850
  received: msg == null ? void 0 : msg.isRead,
714
851
  type: msg == null ? void 0 : msg.type,
@@ -716,23 +853,74 @@ const ConversationViewComponent = (_a) => {
716
853
  replies: (_e = msg == null ? void 0 : msg.replies) != null ? _e : [],
717
854
  isShowThreadMessage
718
855
  };
719
- });
720
- }, [channelMessages, isShowThreadMessage]);
856
+ }).filter(Boolean);
857
+ return [...pendingMessages, ...serverMessages];
858
+ }, [channelMessages, pendingUploads, isShowThreadMessage]);
721
859
  const renderSend = useCallback((props) => {
722
860
  const hasContent = !!props.text || (images == null ? void 0 : images.length) > 0;
723
861
  const canSend = (channelId || (rest == null ? void 0 : rest.isCreateNewChannel)) && hasContent;
724
- return /* @__PURE__ */ React__default.createElement(Send, __spreadProps(__spreadValues({}, props), { disabled: !canSend, containerStyle: {
725
- justifyContent: "center",
726
- alignItems: "center",
727
- height: 40,
728
- width: 44,
729
- marginRight: 4,
730
- marginBottom: 0,
731
- marginLeft: 4
732
- } }), /* @__PURE__ */ React__default.createElement(View, { style: {
733
- padding: 4
734
- } }, /* @__PURE__ */ React__default.createElement(MaterialCommunityIcons, { name: "send-circle", size: 32, color: canSend ? colors.blue[500] : colors.gray[400] })));
735
- }, [channelId, images, rest == null ? void 0 : rest.isCreateNewChannel]);
862
+ const isDisabled = !canSend;
863
+ return /* @__PURE__ */ React__default.createElement(
864
+ Send,
865
+ __spreadProps(__spreadValues({}, props), {
866
+ containerStyle: {
867
+ justifyContent: "center",
868
+ alignItems: "center",
869
+ height: 40,
870
+ width: 44,
871
+ marginRight: 4,
872
+ marginBottom: 0,
873
+ marginLeft: 4
874
+ }
875
+ }),
876
+ /* @__PURE__ */ React__default.createElement(View, { style: {
877
+ padding: 4
878
+ } }, /* @__PURE__ */ React__default.createElement(MaterialCommunityIcons, { name: "send-circle", size: 32, color: isDisabled ? colors.gray[400] : colors.blue[500] }))
879
+ );
880
+ }, [channelId, images, rest == null ? void 0 : rest.isCreateNewChannel, isUploadingImage, loading, isActionSheetVisible]);
881
+ useCallback(() => {
882
+ console.log("Opening action sheet");
883
+ setActionSheetVisible(true);
884
+ }, []);
885
+ useEffect(() => {
886
+ console.log("Action sheet visibility:", isActionSheetVisible);
887
+ if (isActionSheetVisible) {
888
+ setBottomMargin(0);
889
+ }
890
+ }, [isActionSheetVisible]);
891
+ const handleRemoveImage = useCallback((index) => {
892
+ const newImages = [...images];
893
+ newImages.splice(index, 1);
894
+ setImages(newImages);
895
+ if (newImages.length === 0) {
896
+ setSelectedImage("");
897
+ if (textInputRef.current && typeof textInputRef.current.focus === "function") {
898
+ textInputRef.current.focus();
899
+ }
900
+ }
901
+ }, [images]);
902
+ const [textUpdatedInActionSheet, setTextUpdatedInActionSheet] = useState(false);
903
+ useCallback(() => {
904
+ setTextUpdatedInActionSheet(true);
905
+ setActionSheetVisible(false);
906
+ setBottomMargin(0);
907
+ }, []);
908
+ useEffect(() => {
909
+ if (!isActionSheetVisible && textUpdatedInActionSheet) {
910
+ console.log("Action sheet closed with text:", messageText);
911
+ setTextUpdatedInActionSheet(false);
912
+ const currentText = messageText;
913
+ setMessageText("");
914
+ setTimeout(() => {
915
+ setMessageText(currentText);
916
+ }, 50);
917
+ }
918
+ }, [isActionSheetVisible, textUpdatedInActionSheet]);
919
+ useEffect(() => {
920
+ if (isActionSheetVisible && Platform.OS === "ios") {
921
+ console.log("Action sheet is visible, should show the input and options");
922
+ }
923
+ }, [isActionSheetVisible]);
736
924
  const handleSend = useCallback(async (messages) => {
737
925
  var _a3, _b3, _c2;
738
926
  const newMessageText = messages && messages.length > 0 ? ((_a3 = messages[0]) == null ? void 0 : _a3.text) || " " : " ";
@@ -747,15 +935,24 @@ const ConversationViewComponent = (_a) => {
747
935
  setMessageText(newMessageText);
748
936
  if ((rest == null ? void 0 : rest.isCreateNewChannel) && !channelId) {
749
937
  if (((_b3 = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _b3.type) === ((_c2 = RoomType) == null ? void 0 : _c2.Direct)) {
750
- createDirectChannelImpl();
938
+ await createDirectChannelImpl();
751
939
  }
940
+ setIsUploadingImage(false);
941
+ setLoading(false);
752
942
  return;
753
943
  }
754
944
  if (hasImages) {
755
- sendMessageWithFileImpl();
945
+ await sendMessageWithFileImpl();
756
946
  } else {
757
- sendMessageImpl();
947
+ await sendMessageImpl();
758
948
  }
949
+ setIsUploadingImage(false);
950
+ setLoading(false);
951
+ setTimeout(() => {
952
+ if (textInputRef.current) {
953
+ textInputRef.current.focus();
954
+ }
955
+ }, 100);
759
956
  }, [channelId, images, rest == null ? void 0 : rest.isCreateNewChannel, (_d = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _d.type, createDirectChannelImpl, sendMessageWithFileImpl, sendMessageImpl]);
760
957
  const renderMessageText = useCallback((props) => {
761
958
  var _a3, _b3, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U;
@@ -763,6 +960,9 @@ const ConversationViewComponent = (_a) => {
763
960
  currentMessage
764
961
  } = props;
765
962
  const lastReply = ((_b3 = (_a3 = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _a3.data) == null ? void 0 : _b3.length) > 0 ? (_d2 = (_c2 = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _c2.data) == null ? void 0 : _d2[0] : null;
963
+ if (!(currentMessage == null ? void 0 : currentMessage.text) || currentMessage.text.trim() === "") {
964
+ return null;
965
+ }
766
966
  if (currentMessage.type === "ALERT") {
767
967
  const attachment = (_f = (_e = currentMessage == null ? void 0 : currentMessage.propsConfiguration) == null ? void 0 : _e.contents) == null ? void 0 : _f.attachment;
768
968
  let action = "";
@@ -863,112 +1063,60 @@ const ConversationViewComponent = (_a) => {
863
1063
  }, className: "font-bold color-gray-500" }, lastReply ? createdAtText(lastReply == null ? void 0 : lastReply.createdAt) : ""))));
864
1064
  }
865
1065
  }, [navigation, channelId, role]);
866
- const renderActions = (props) => {
867
- return /* @__PURE__ */ React__default.createElement(
868
- Actions,
869
- __spreadProps(__spreadValues({}, props), {
870
- options: {
871
- ["Choose from Library"]: onSelectImages,
872
- ["Cancel"]: () => {
873
- }
874
- },
875
- optionTintColor: "#000000",
876
- cancelButtonIndex: 1,
877
- icon: () => /* @__PURE__ */ React__default.createElement(Box, { style: {
878
- width: 32,
879
- height: 32,
880
- alignItems: "center",
881
- justifyContent: "center"
882
- } }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "image", size: 24, color: colors.blue[500] })),
883
- containerStyle: {
884
- alignItems: "center",
885
- justifyContent: "center",
886
- marginLeft: 8,
887
- marginBottom: 0
888
- }
889
- })
890
- );
891
- };
892
- const renderAccessory = useCallback(() => {
893
- var _a3;
894
- if (!selectedImage) {
1066
+ useCallback(() => {
1067
+ if (!images.length)
895
1068
  return null;
896
- }
897
- return /* @__PURE__ */ React__default.createElement(View, { style: {
1069
+ return /* @__PURE__ */ React__default.createElement(Box, { style: {
1070
+ position: "relative",
898
1071
  height: 70,
899
- backgroundColor: "white",
900
- borderTopWidth: 1,
901
- borderTopColor: "#e0e0e0",
902
- flexDirection: "row",
903
- alignItems: "center",
904
- margin: 0,
905
- padding: 0,
906
- paddingVertical: 0,
907
- position: "absolute",
908
- bottom: Platform.OS === "ios" ? 105 : 95,
909
- left: 0,
910
- right: 0,
911
- zIndex: 1,
912
- elevation: 3,
913
- shadowColor: "#000",
914
- shadowOffset: {
915
- width: 0,
916
- height: -1
917
- },
918
- shadowOpacity: 0.05,
919
- shadowRadius: 2
920
- } }, /* @__PURE__ */ React__default.createElement(View, { style: {
921
- flex: 1,
1072
+ backgroundColor: "transparent",
1073
+ justifyContent: "center"
1074
+ } }, /* @__PURE__ */ React__default.createElement(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: {
922
1075
  flexDirection: "row",
923
- alignItems: "center",
924
1076
  paddingLeft: 15,
925
1077
  paddingRight: 5
926
- } }, /* @__PURE__ */ React__default.createElement(View, { style: {
927
- width: 56,
928
- height: 56,
1078
+ }, contentContainerStyle: {
1079
+ alignItems: "center",
1080
+ height: "100%"
1081
+ } }, images.map((img, index) => /* @__PURE__ */ React__default.createElement(View, { key: `image-preview-${index}`, style: {
1082
+ width: 40,
1083
+ height: 40,
929
1084
  marginRight: 15,
930
1085
  borderRadius: 4,
931
1086
  backgroundColor: colors.gray[200],
932
1087
  overflow: "hidden",
933
1088
  borderWidth: 1,
934
- borderColor: "#e0e0e0"
935
- } }, /* @__PURE__ */ React__default.createElement(Image, { key: selectedImage, alt: "selected image", source: {
936
- uri: selectedImage
1089
+ borderColor: "#e0e0e0",
1090
+ position: "relative",
1091
+ zIndex: 10
1092
+ } }, /* @__PURE__ */ React__default.createElement(Image, { source: {
1093
+ uri: img.uri || img.url
937
1094
  }, style: {
938
1095
  width: "100%",
939
1096
  height: "100%"
940
- }, size: "md" }), loading && /* @__PURE__ */ React__default.createElement(View, { style: {
941
- position: "absolute",
942
- top: 0,
943
- left: 0,
944
- right: 0,
945
- bottom: 0,
946
- backgroundColor: "rgba(255, 255, 255, 0.7)",
947
- justifyContent: "center",
948
- alignItems: "center"
949
- } }, /* @__PURE__ */ React__default.createElement(Spinner, { size: "small", color: colors.blue[500] }))), /* @__PURE__ */ React__default.createElement(View, { style: {
950
- flex: 1
951
- } }, /* @__PURE__ */ React__default.createElement(Text, { style: {
952
- fontSize: 14,
953
- fontWeight: "400",
954
- color: colors.gray[800]
955
- } }, ((_a3 = images[0]) == null ? void 0 : _a3.fileName) || "image_" + new Date().getTime() + ".jpg"), /* @__PURE__ */ React__default.createElement(Text, { style: {
956
- fontSize: 12,
957
- color: colors.gray[500],
958
- marginTop: 2
959
- } }, loading ? "Preparing..." : "Ready to send")), /* @__PURE__ */ React__default.createElement(TouchableHighlight, { underlayColor: "rgba(0,0,0,0.1)", onPress: () => {
960
- setSelectedImage("");
961
- setImages([]);
1097
+ }, alt: `selected image ${index + 1}` }), /* @__PURE__ */ React__default.createElement(TouchableOpacity, { onPress: () => {
1098
+ const newImages = [...images];
1099
+ newImages.splice(index, 1);
1100
+ setImages(newImages);
1101
+ if (newImages.length === 0) {
1102
+ setSelectedImage("");
1103
+ if (textInputRef.current && typeof textInputRef.current.focus === "function") {
1104
+ textInputRef.current.focus();
1105
+ }
1106
+ }
962
1107
  }, style: {
963
- backgroundColor: colors.red[500],
964
- borderRadius: 24,
965
- width: 36,
966
- height: 36,
1108
+ position: "absolute",
1109
+ top: -1,
1110
+ right: -1,
1111
+ backgroundColor: "rgba(0,0,0,0.6)",
1112
+ borderRadius: 12,
1113
+ width: 20,
1114
+ height: 20,
967
1115
  alignItems: "center",
968
1116
  justifyContent: "center",
969
- marginRight: 10
970
- } }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "close", size: 20, color: "white" }))));
971
- }, [selectedImage, loading, images]);
1117
+ zIndex: 9999
1118
+ } }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "close", size: 16, color: "white" }))))));
1119
+ }, [images]);
972
1120
  const setImageViewerObject = (obj, v) => {
973
1121
  setImageObject(obj);
974
1122
  setImageViewer(v);
@@ -989,36 +1137,8 @@ const ConversationViewComponent = (_a) => {
989
1137
  }, alt: "image" });
990
1138
  }, [imageObject]);
991
1139
  const renderMessage = useCallback((props) => {
992
- const isUploading = props.currentMessage._id === uploadingMessageId && loading;
993
- if (isUploading && props.currentMessage.image) {
994
- return /* @__PURE__ */ React__default.createElement(View, { style: {
995
- padding: 10,
996
- marginBottom: 10,
997
- marginRight: 10,
998
- alignSelf: "flex-end",
999
- borderRadius: 15,
1000
- backgroundColor: colors.gray[100],
1001
- maxWidth: "80%"
1002
- } }, props.currentMessage.text && props.currentMessage.text.trim() !== "" && /* @__PURE__ */ React__default.createElement(Box, { style: {
1003
- height: 15,
1004
- borderRadius: 4,
1005
- backgroundColor: colors.gray[200],
1006
- overflow: "hidden",
1007
- marginBottom: 8
1008
- } }, /* @__PURE__ */ React__default.createElement(Skeleton, { variant: "rounded", style: {
1009
- flex: 1
1010
- } })), /* @__PURE__ */ React__default.createElement(Box, { style: {
1011
- height: 150,
1012
- width: 150,
1013
- borderRadius: 10,
1014
- backgroundColor: colors.gray[200],
1015
- overflow: "hidden"
1016
- } }, /* @__PURE__ */ React__default.createElement(Skeleton, { variant: "rounded", style: {
1017
- flex: 1
1018
- } })));
1019
- }
1020
1140
  return /* @__PURE__ */ React__default.createElement(Message, __spreadProps(__spreadValues({}, props), { isShowImageViewer, setImageViewer: setImageViewerObject }));
1021
- }, [isShowImageViewer, uploadingMessageId, loading]);
1141
+ }, [isShowImageViewer]);
1022
1142
  let onScroll = false;
1023
1143
  const onMomentumScrollBegin = async ({
1024
1144
  nativeEvent
@@ -1041,30 +1161,94 @@ const ConversationViewComponent = (_a) => {
1041
1161
  marginTop: 10
1042
1162
  } }, /* @__PURE__ */ React__default.createElement(Spinner, { size: "small", color: "#3b82f6" })) : null;
1043
1163
  }, [loadingOldMessages]);
1044
- const renderInputToolbar = useCallback((props) => {
1045
- return /* @__PURE__ */ React__default.createElement(InputToolbar, __spreadProps(__spreadValues({}, props), { containerStyle: {
1046
- backgroundColor: "white",
1047
- borderTopWidth: 1,
1048
- borderTopColor: colors.gray[200],
1049
- paddingHorizontal: 4,
1050
- paddingVertical: 0,
1051
- paddingTop: 2,
1052
- marginBottom: 0,
1053
- marginTop: 0
1054
- }, primaryStyle: {
1055
- alignItems: "center"
1056
- } }));
1057
- }, []);
1164
+ const [inputToolbarHeight, setInputToolbarHeight] = useState(30);
1165
+ useCallback((props) => /* @__PURE__ */ React__default.createElement(View, { style: {
1166
+ backgroundColor: "#fff",
1167
+ paddingBottom: 4,
1168
+ paddingTop: 4
1169
+ } }, /* @__PURE__ */ React__default.createElement(View, { style: {
1170
+ flexDirection: "row",
1171
+ alignItems: "center",
1172
+ minHeight: 44,
1173
+ maxHeight: 56,
1174
+ backgroundColor: "#fff",
1175
+ borderRadius: 22,
1176
+ marginHorizontal: 8,
1177
+ paddingHorizontal: 8,
1178
+ borderTopWidth: 1,
1179
+ borderTopColor: "#e0e0e0"
1180
+ } }, /* @__PURE__ */ React__default.createElement(TouchableOpacity, { onPress: onSelectImages, style: {
1181
+ width: 32,
1182
+ height: 32,
1183
+ borderRadius: 16,
1184
+ backgroundColor: "#fff",
1185
+ alignItems: "center",
1186
+ justifyContent: "center",
1187
+ marginRight: 8
1188
+ } }, /* @__PURE__ */ React__default.createElement(MaterialIcons, { name: "add", size: 24, color: "#888" })), /* @__PURE__ */ React__default.createElement(TextInput, { ref: textInputRef, style: {
1189
+ flex: 1,
1190
+ maxHeight: 44,
1191
+ backgroundColor: "transparent",
1192
+ color: "#444",
1193
+ paddingHorizontal: 8,
1194
+ paddingVertical: 0,
1195
+ alignSelf: "center",
1196
+ textAlignVertical: "center"
1197
+ }, placeholder: "Jot something down", placeholderTextColor: colors.gray[400], multiline: true, value: messageText, onChangeText: setMessageText }), /* @__PURE__ */ React__default.createElement(
1198
+ TouchableOpacity,
1199
+ {
1200
+ onPress: () => handleSend([{
1201
+ text: messageText
1202
+ }]),
1203
+ disabled: false,
1204
+ style: {
1205
+ marginLeft: 8,
1206
+ opacity: !messageText.trim() && images.length === 0 ? 0.5 : 1
1207
+ }
1208
+ },
1209
+ /* @__PURE__ */ React__default.createElement(
1210
+ MaterialCommunityIcons,
1211
+ {
1212
+ name: "send-circle",
1213
+ size: 32,
1214
+ color: !messageText.trim() && images.length === 0 ? colors.gray[400] : colors.blue[500]
1215
+ }
1216
+ )
1217
+ )), images && images.length > 0 && /* @__PURE__ */ React__default.createElement(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: {
1218
+ marginTop: 4,
1219
+ marginLeft: 8
1220
+ } }, images.map((img, index) => /* @__PURE__ */ React__default.createElement(View, { key: `image-preview-${index}`, style: {
1221
+ width: 48,
1222
+ height: 48,
1223
+ marginRight: 8,
1224
+ borderRadius: 6,
1225
+ overflow: "hidden",
1226
+ position: "relative",
1227
+ backgroundColor: colors.gray[200]
1228
+ } }, /* @__PURE__ */ React__default.createElement(Image, { source: {
1229
+ uri: img.uri || img.url
1230
+ }, style: {
1231
+ width: "100%",
1232
+ height: "100%"
1233
+ }, alt: `selected image ${index + 1}` }), /* @__PURE__ */ React__default.createElement(TouchableOpacity, { onPress: () => {
1234
+ handleRemoveImage(index);
1235
+ }, style: {
1236
+ position: "absolute",
1237
+ top: 2,
1238
+ right: 2,
1239
+ backgroundColor: "rgba(0,0,0,0.6)",
1240
+ borderRadius: 10,
1241
+ width: 20,
1242
+ height: 20,
1243
+ alignItems: "center",
1244
+ justifyContent: "center"
1245
+ } }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "close", size: 14, color: "white" })))))), [onSelectImages, messageText, images, isUploadingImage, loading, handleSend, handleRemoveImage]);
1058
1246
  const imageViewerModal = useMemo(() => /* @__PURE__ */ React__default.createElement(ImageViewerModal, { isVisible: isShowImageViewer, setVisible: setImageViewer, modalContent }), [isShowImageViewer, modalContent]);
1059
- const subscriptionHandler = useMemo(() => /* @__PURE__ */ React__default.createElement(SubscriptionHandler, { channelId: channelId == null ? void 0 : channelId.toString(), subscribeToNewMessages: () => subscribeToMore({
1060
- document: OnChatMessageAddedDocument,
1061
- variables: {
1062
- channelId: channelId == null ? void 0 : channelId.toString()
1063
- }
1064
- }) }), [channelId, subscribeToMore, auth == null ? void 0 : auth.id]);
1065
1247
  const renderChatFooter = useCallback(() => {
1066
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, imageViewerModal, subscriptionHandler);
1067
- }, [imageViewerModal, subscriptionHandler]);
1248
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, imageViewerModal, /* @__PURE__ */ React__default.createElement(SubscriptionHandler, { subscribeToMore: subscribe, document: CHAT_MESSAGE_ADDED, variables: {
1249
+ channelId: channelId == null ? void 0 : channelId.toString()
1250
+ }, updateQuery: void 0 }));
1251
+ }, [imageViewerModal, subscribe]);
1068
1252
  const listViewProps = useMemo(() => ({
1069
1253
  onEndReached,
1070
1254
  onEndReachedThreshold: 0.5,
@@ -1086,98 +1270,57 @@ const ConversationViewComponent = (_a) => {
1086
1270
  }
1087
1271
  }
1088
1272
  }, []);
1089
- return /* @__PURE__ */ React__default.createElement(View, { style: {
1273
+ return /* @__PURE__ */ React__default.createElement(KeyboardAvoidingView, { style: {
1274
+ flex: 1,
1275
+ justifyContent: "flex-end"
1276
+ }, behavior: Platform.OS === "ios" ? "padding" : "height", keyboardVerticalOffset: Platform.OS === "ios" ? 64 : 0 }, /* @__PURE__ */ React__default.createElement(View, { style: {
1090
1277
  flex: 1,
1091
1278
  backgroundColor: "white",
1092
- position: "relative"
1093
- } }, messageLoading && /* @__PURE__ */ React__default.createElement(Spinner, { color: "#3b82f6" }), selectedImage ? renderAccessory() : null, /* @__PURE__ */ React__default.createElement(
1094
- GiftedChat,
1279
+ position: "relative",
1280
+ marginBottom: images.length > 0 ? 5 : bottomMargin
1281
+ } }, errorMessage ? /* @__PURE__ */ React__default.createElement(ErrorNotification, { message: errorMessage, onClose: () => setErrorMessage(""), type: notificationType }) : null, messageLoading && /* @__PURE__ */ React__default.createElement(Spinner, { color: "#3b82f6" }), /* @__PURE__ */ React__default.createElement(
1282
+ GiftedChatInboxComponent,
1095
1283
  {
1096
1284
  ref: messageRootListRef,
1285
+ errorMessage,
1286
+ images,
1287
+ onSelectImages,
1288
+ onRemoveImage: handleRemoveImage,
1289
+ selectedImage,
1290
+ setSelectedImage,
1291
+ isUploadingImage,
1292
+ loading,
1097
1293
  wrapInSafeArea: true,
1098
1294
  renderLoading: () => /* @__PURE__ */ React__default.createElement(Spinner, { color: "#3b82f6" }),
1099
1295
  messages: messageList,
1296
+ renderAvatar: null,
1297
+ showUserAvatar: false,
1100
1298
  listViewProps: __spreadProps(__spreadValues({}, listViewProps), {
1101
1299
  contentContainerStyle: {
1102
- paddingBottom: selectedImage ? 90 : 0
1300
+ paddingBottom: inputToolbarHeight
1103
1301
  }
1104
1302
  }),
1105
1303
  onSend: handleSend,
1106
1304
  text: messageText || " ",
1107
- onInputTextChanged: (text) => setMessageText(text),
1108
- renderFooter: () => loading && !images.length ? /* @__PURE__ */ React__default.createElement(Spinner, { color: "#3b82f6" }) : null,
1305
+ onInputTextChanged: (text) => {
1306
+ setMessageText(text);
1307
+ },
1308
+ renderFooter: () => isUploadingImage ? /* @__PURE__ */ React__default.createElement(Spinner, { color: "#3b82f6" }) : null,
1109
1309
  scrollToBottom: true,
1110
1310
  user: {
1111
1311
  _id: (auth == null ? void 0 : auth.id) || ""
1112
1312
  },
1113
- isTyping: false,
1114
- alwaysShowSend: true,
1115
1313
  renderSend,
1116
1314
  renderMessageText,
1117
- renderInputToolbar,
1118
- minInputToolbarHeight: 50,
1119
- renderActions: channelId && renderActions,
1120
1315
  renderMessage,
1121
1316
  renderChatFooter,
1122
1317
  renderLoadEarlier,
1123
1318
  loadEarlier: totalCount > channelMessages.length,
1124
1319
  isLoadingEarlier: loadingOldMessages,
1125
- bottomOffset: Platform.OS === "ios" ? selectedImage ? 90 : 10 : 0,
1126
- textInputProps: {
1127
- style: {
1128
- borderWidth: 1,
1129
- borderColor: colors.gray[300],
1130
- backgroundColor: "#f8f8f8",
1131
- borderRadius: 20,
1132
- minHeight: 36,
1133
- maxHeight: 80,
1134
- color: "#000",
1135
- padding: 8,
1136
- paddingHorizontal: 15,
1137
- fontSize: 16,
1138
- flex: 1,
1139
- marginVertical: 2,
1140
- marginBottom: 0
1141
- },
1142
- multiline: true,
1143
- returnKeyType: "default",
1144
- enablesReturnKeyAutomatically: true,
1145
- placeholderTextColor: colors.gray[400]
1146
- },
1147
- minComposerHeight: 36,
1148
- maxComposerHeight: 100,
1149
- isKeyboardInternallyHandled: true,
1150
- placeholder: "Type a message...",
1151
- lightboxProps: {
1152
- underlayColor: "transparent",
1153
- springConfig: {
1154
- tension: 9e4,
1155
- friction: 9e4
1156
- },
1157
- disabled: true
1158
- },
1159
- infiniteScroll: false
1160
- }
1161
- ));
1162
- };
1163
- const SubscriptionHandler = ({
1164
- subscribeToNewMessages,
1165
- channelId
1166
- }) => {
1167
- const channelIdRef = useRef(channelId);
1168
- useEffect(() => {
1169
- if (!channelId) {
1170
- return;
1320
+ placeholder: "Jot something down",
1321
+ infiniteScroll: true
1171
1322
  }
1172
- const unsubscribe = subscribeToNewMessages();
1173
- channelIdRef.current = channelId;
1174
- return () => {
1175
- if (unsubscribe && typeof unsubscribe === "function") {
1176
- unsubscribe();
1177
- }
1178
- };
1179
- }, [channelId, subscribeToNewMessages]);
1180
- return null;
1323
+ )));
1181
1324
  };
1182
1325
  const ConversationView = React__default.memo(ConversationViewComponent, (prevProps, nextProps) => {
1183
1326
  return prevProps.channelId === nextProps.channelId && prevProps.role === nextProps.role && prevProps.isShowThreadMessage === nextProps.isShowThreadMessage;