@messenger-box/platform-mobile 10.0.3-alpha.5 → 10.0.3-alpha.54

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 (98) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/lib/compute.js +2 -3
  3. package/lib/compute.js.map +1 -1
  4. package/lib/index.js.map +1 -1
  5. package/lib/queries/inboxQueries.js +65 -0
  6. package/lib/queries/inboxQueries.js.map +1 -0
  7. package/lib/routes.json +2 -3
  8. package/lib/screens/inbox/DialogMessages.js +1 -1
  9. package/lib/screens/inbox/DialogMessages.js.map +1 -1
  10. package/lib/screens/inbox/DialogThreadMessages.js +4 -8
  11. package/lib/screens/inbox/DialogThreadMessages.js.map +1 -1
  12. package/lib/screens/inbox/DialogThreads.js +57 -12
  13. package/lib/screens/inbox/DialogThreads.js.map +1 -1
  14. package/lib/screens/inbox/Inbox.js +1 -1
  15. package/lib/screens/inbox/Inbox.js.map +1 -1
  16. package/lib/screens/inbox/components/CachedImage/consts.js +1 -1
  17. package/lib/screens/inbox/components/CachedImage/consts.js.map +1 -1
  18. package/lib/screens/inbox/components/CachedImage/index.js +168 -46
  19. package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
  20. package/lib/screens/inbox/components/DialogItem.js +169 -0
  21. package/lib/screens/inbox/components/DialogItem.js.map +1 -0
  22. package/lib/screens/inbox/components/GiftedChatInboxComponent.js +313 -0
  23. package/lib/screens/inbox/components/GiftedChatInboxComponent.js.map +1 -0
  24. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +147 -31
  25. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  26. package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js +6 -1
  27. package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js.map +1 -1
  28. package/lib/screens/inbox/components/SubscriptionHandler.js +24 -0
  29. package/lib/screens/inbox/components/SubscriptionHandler.js.map +1 -0
  30. package/lib/screens/inbox/components/ThreadsViewItem.js +66 -55
  31. package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
  32. package/lib/screens/inbox/config/config.js +2 -2
  33. package/lib/screens/inbox/config/config.js.map +1 -1
  34. package/lib/screens/inbox/containers/ConversationView.js +1111 -434
  35. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  36. package/lib/screens/inbox/containers/Dialogs.js +193 -80
  37. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  38. package/lib/screens/inbox/containers/ThreadConversationView.js +725 -216
  39. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  40. package/lib/screens/inbox/containers/ThreadsView.js +83 -50
  41. package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
  42. package/lib/screens/inbox/hooks/useInboxMessages.js +31 -0
  43. package/lib/screens/inbox/hooks/useInboxMessages.js.map +1 -0
  44. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js +108 -0
  45. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js.map +1 -0
  46. package/lib/screens/inbox/workflow/dialog-threads-xstate.js +151 -0
  47. package/lib/screens/inbox/workflow/dialog-threads-xstate.js.map +1 -0
  48. package/package.json +4 -4
  49. package/src/compute.ts +5 -6
  50. package/src/index.ts +2 -0
  51. package/src/navigation/InboxNavigation.tsx +3 -3
  52. package/src/queries/inboxQueries.ts +299 -0
  53. package/src/queries/index.d.ts +2 -0
  54. package/src/queries/index.ts +1 -0
  55. package/src/screens/inbox/DialogMessages.tsx +1 -1
  56. package/src/screens/inbox/DialogThreadMessages.tsx +7 -14
  57. package/src/screens/inbox/DialogThreads.tsx +55 -61
  58. package/src/screens/inbox/Inbox.tsx +1 -1
  59. package/src/screens/inbox/components/Actionsheet.tsx +30 -0
  60. package/src/screens/inbox/components/CachedImage/consts.ts +4 -3
  61. package/src/screens/inbox/components/CachedImage/index.tsx +232 -61
  62. package/src/screens/inbox/components/DialogItem.tsx +306 -0
  63. package/src/screens/inbox/components/DialogsHeader.tsx +6 -13
  64. package/src/screens/inbox/components/DialogsListItem.tsx +262 -198
  65. package/src/screens/inbox/components/ExpandableInput.tsx +460 -0
  66. package/src/screens/inbox/components/ExpandableInputActionSheet.tsx +518 -0
  67. package/src/screens/inbox/components/GiftedChatInboxComponent.tsx +411 -0
  68. package/src/screens/inbox/components/ServiceDialogsListItem.tsx +337 -194
  69. package/src/screens/inbox/components/SlackInput.tsx +23 -0
  70. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +233 -23
  71. package/src/screens/inbox/components/SlackMessageContainer/SlackMessage.tsx +1 -1
  72. package/src/screens/inbox/components/SmartLoader.tsx +61 -0
  73. package/src/screens/inbox/components/SubscriptionHandler.tsx +41 -0
  74. package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +53 -55
  75. package/src/screens/inbox/components/ThreadsViewItem.tsx +178 -285
  76. package/src/screens/inbox/components/workflow/dialogs-list-item-xstate.ts +145 -0
  77. package/src/screens/inbox/components/workflow/service-dialogs-list-item-xstate.ts +159 -0
  78. package/src/screens/inbox/config/config.ts +2 -2
  79. package/src/screens/inbox/containers/ConversationView.tsx +1843 -702
  80. package/src/screens/inbox/containers/ConversationView.tsx.bk +1467 -0
  81. package/src/screens/inbox/containers/Dialogs.tsx +402 -204
  82. package/src/screens/inbox/containers/SupportServiceDialogs.tsx +4 -4
  83. package/src/screens/inbox/containers/ThreadConversationView.tsx +1350 -319
  84. package/src/screens/inbox/containers/ThreadsView.tsx +105 -193
  85. package/src/screens/inbox/containers/workflow/apollo/handleResult.ts +20 -0
  86. package/src/screens/inbox/containers/workflow/conversation-xstate.ts +313 -0
  87. package/src/screens/inbox/containers/workflow/dialogs-xstate.ts +196 -0
  88. package/src/screens/inbox/containers/workflow/thread-conversation-xstate.ts +401 -0
  89. package/src/screens/inbox/hooks/useInboxMessages.ts +34 -0
  90. package/src/screens/inbox/hooks/useSafeDialogThreadsMachine.ts +136 -0
  91. package/src/screens/inbox/index.ts +37 -0
  92. package/src/screens/inbox/machines/threadsMachine.ts +147 -0
  93. package/src/screens/inbox/workflow/dialog-threads-xstate.ts +163 -0
  94. package/tsconfig.json +11 -54
  95. package/lib/screens/inbox/components/DialogsListItem.js +0 -171
  96. package/lib/screens/inbox/components/DialogsListItem.js.map +0 -1
  97. package/lib/screens/inbox/components/ServiceDialogsListItem.js +0 -171
  98. package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import React__default,{useState,useRef,useEffect,useCallback,useMemo}from'react';import {Spinner,Box,HStack,Image,Button,ButtonText,Avatar,AvatarFallbackText,AvatarImage,Text}from'@admin-layout/gluestack-ui-mobile';import {Platform,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 {encode}from'base-64';import {Ionicons,MaterialCommunityIcons}from'@expo/vector-icons';import {GiftedChat,Actions,MessageText,Send}from'react-native-gifted-chat';import {RoomType,PreDefinedRole}from'common';import {useAddDirectChannelMutation,useSendMessagesMutation,useSendExpoNotificationOnPostMutation,useMessagesQuery,OnChatMessageAddedDocument}from'common/lib/generated/generated.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';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 {useRoute,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,9 +46,59 @@ 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
- channelId: ChannelId,
101
+ channelId: initialChannelId,
52
102
  role,
53
103
  isShowThreadMessage
54
104
  } = _b, rest = __objRest(_b, [
@@ -56,371 +106,887 @@ const ConversationViewComponent = (_a) => {
56
106
  "role",
57
107
  "isShowThreadMessage"
58
108
  ]);
59
- var _a2;
60
- const [channelToTop, setChannelToTop] = useState(0);
61
- const [channelMessages, setChannelMessages] = useState([]);
62
- const auth = useSelector(userSelector);
63
- const [totalCount, setTotalCount] = useState(0);
64
- const [selectedImage, setImage] = useState("");
65
- const currentRoute = navigationRef.isReady() ? (_a2 = navigationRef) == null ? void 0 : _a2.getCurrentRoute() : null;
66
- const [channelId, setChannelId] = useState((rest == null ? void 0 : rest.isCreateNewChannel) ? null : ChannelId);
109
+ var _a2, _b2, _c, _d;
110
+ const {
111
+ params
112
+ } = useRoute();
113
+ const [channelId, setChannelId] = useState(initialChannelId || null);
114
+ const [messageText, setMessageText] = useState("");
115
+ const [loading, setLoading] = useState(false);
67
116
  const [loadingOldMessages, setLoadingOldMessages] = useState(false);
68
- const navigation = useNavigation();
69
- const [files, setFiles] = useState([]);
117
+ const [error, setError] = useState(null);
118
+ const [selectedImage, setSelectedImage] = useState("");
70
119
  const [images, setImages] = useState([]);
71
- const [msg, setMsg] = useState("");
72
- const [loading, setLoading] = useState(false);
73
- const [loadEarlierMsg, setLoadEarlierMsg] = useState(false);
74
- const [imageLoading, setImageLoading] = useState(false);
75
- const [expoTokens, setExpoTokens] = useState([]);
76
120
  const [isShowImageViewer, setImageViewer] = useState(false);
77
121
  const [imageObject, setImageObject] = useState({});
78
- const [skip, setSkip] = useState(0);
122
+ const [errorMessage, setErrorMessage] = useState("");
123
+ const [notificationType, setNotificationType] = useState("error");
124
+ const [isActionSheetVisible, setActionSheetVisible] = useState(false);
125
+ const [bottomMargin, setBottomMargin] = useState(0);
79
126
  const messageRootListRef = useRef(null);
127
+ const textInputRef = useRef(null);
128
+ const isMounted = useRef(true);
129
+ const fetchOldDebounceRef = useRef(false);
130
+ const auth = useSelector(userSelector, shallowEqual);
131
+ const currentRoute = navigationRef.isReady() ? (_a2 = navigationRef) == null ? void 0 : _a2.getCurrentRoute() : null;
132
+ const navigation = useNavigation();
80
133
  const isFocused = useIsFocused();
81
- const [addDirectChannel, {
82
- loading: addDirectChannaleLoading
83
- }] = useAddDirectChannelMutation();
134
+ const [addDirectChannel] = useAddDirectChannel();
84
135
  const {
85
136
  startUpload
86
137
  } = useUploadFilesNative();
87
- const [sendMsg] = useSendMessagesMutation();
88
- const [sendExpoNotificationOnPostMutation] = useSendExpoNotificationOnPostMutation();
138
+ const [sendMsg] = useSendChannelMessage();
139
+ const [sendExpoNotification] = useSendExpoNotification();
140
+ const [skip, setSkip] = useState(0);
89
141
  const {
90
142
  data,
91
143
  loading: messageLoading,
92
144
  refetch,
93
- fetchMore: fetchMoreMessages,
94
- subscribeToMore
95
- } = useMessagesQuery({
96
- variables: {
145
+ subscribe
146
+ } = useInboxMessages({
147
+ useQueryHook: useChannelMessagesQuery,
148
+ queryVariables: {
97
149
  channelId: channelId == null ? void 0 : channelId.toString(),
98
150
  parentId: null,
99
151
  limit: MESSAGES_PER_PAGE,
100
- skip
152
+ skip,
153
+ orgName: params == null ? void 0 : params.orgName
154
+ },
155
+ subscriptionDocument: CHAT_MESSAGE_ADDED,
156
+ subscriptionVariables: {
157
+ channelId: channelId == null ? void 0 : channelId.toString()
101
158
  },
102
- skip: !channelId,
103
- fetchPolicy: "cache-and-network",
104
- nextFetchPolicy: "cache-first",
105
- refetchWritePolicy: "merge"
159
+ updateQuery: void 0,
160
+ onError: (err) => setError(String(err))
106
161
  });
107
- React__default.useEffect(() => {
162
+ const channelMessages = useMemo(() => {
163
+ var _a3;
164
+ return ((_a3 = data == null ? void 0 : data.messages) == null ? void 0 : _a3.data) || [];
165
+ }, [(_b2 = data == null ? void 0 : data.messages) == null ? void 0 : _b2.data]);
166
+ const totalCount = useMemo(() => {
167
+ var _a3;
168
+ return ((_a3 = data == null ? void 0 : data.messages) == null ? void 0 : _a3.totalCount) || 0;
169
+ }, [(_c = data == null ? void 0 : data.messages) == null ? void 0 : _c.totalCount]);
170
+ useEffect(() => {
108
171
  return () => {
109
- setChannelMessages([]);
172
+ isMounted.current = false;
110
173
  };
111
174
  }, []);
175
+ useEffect(() => {
176
+ var _a3;
177
+ const currentChannelId = initialChannelId || ((_a3 = currentRoute == null ? void 0 : currentRoute.params) == null ? void 0 : _a3.channelId);
178
+ if (currentChannelId) {
179
+ setChannelId(currentChannelId);
180
+ }
181
+ }, [initialChannelId, currentRoute]);
112
182
  useFocusEffect(React__default.useCallback(() => {
113
- setSkip(0);
114
183
  if (channelId) {
115
- refetch({
184
+ refetch();
185
+ }
186
+ }, [isFocused, refetch]));
187
+ const fetchMoreMessagesImpl = useCallback(async () => {
188
+ var _a3, _b3;
189
+ try {
190
+ setLoadingOldMessages(true);
191
+ const response = await refetch({
116
192
  channelId: channelId == null ? void 0 : channelId.toString(),
117
193
  parentId: null,
118
194
  limit: MESSAGES_PER_PAGE,
119
- skip: 0
120
- }).then(({
121
- data: data2
122
- }) => {
123
- if (!(data2 == null ? void 0 : data2.messages)) {
124
- return;
125
- }
126
- const {
127
- data: messages,
128
- totalCount: totalCount2
129
- } = data2.messages;
130
- setTotalCount(totalCount2);
131
- setChannelMessages(messages);
195
+ skip: channelMessages.length
132
196
  });
133
- }
134
- return () => {
135
- setChannelId(null);
136
- setTotalCount(0);
137
- setSkip(0);
138
- };
139
- }, [channelId, isFocused]));
140
- React__default.useEffect(() => {
141
- var _a3;
142
- const currentChannelId = ChannelId || ((_a3 = currentRoute == null ? void 0 : currentRoute.params) == null ? void 0 : _a3.channelId);
143
- setChannelId(currentChannelId);
144
- }, [ChannelId, currentRoute]);
145
- React__default.useEffect(() => {
146
- if (selectedImage)
147
- setImageLoading(false);
148
- }, [selectedImage]);
149
- useEffect(() => {
150
- var _a3;
151
- if ((_a3 = data == null ? void 0 : data.messages) == null ? void 0 : _a3.data) {
152
- const {
153
- data: messages,
154
- totalCount: messeageTotalCount
155
- } = data.messages;
156
- console.log("messeageTotalCount", messeageTotalCount, " totalCount=", totalCount);
157
- if (messages && messages.length > 0 && messeageTotalCount > totalCount || messages && messages.length > 0 && (loadingOldMessages || channelMessages.length === 0)) {
158
- setChannelMessages((oldMessages) => uniqBy([...messages, ...oldMessages], ({
159
- id
160
- }) => id));
161
- setTotalCount(messeageTotalCount);
197
+ setSkip(channelMessages.length);
198
+ setLoadingOldMessages(false);
199
+ if (!((_b3 = (_a3 = response == null ? void 0 : response.data) == null ? void 0 : _a3.messages) == null ? void 0 : _b3.data)) {
200
+ return {
201
+ error: "No messages returned"
202
+ };
162
203
  }
163
- if (loadingOldMessages && channelMessages)
164
- setLoadingOldMessages(false);
204
+ return {
205
+ messages: response.data.messages.data
206
+ };
207
+ } catch (error2) {
208
+ setLoadingOldMessages(false);
209
+ setError(String(error2));
210
+ return {
211
+ error: String(error2)
212
+ };
165
213
  }
166
- }, [data, loadingOldMessages, channelMessages, totalCount]);
167
- const onFetchOld = useCallback(async () => {
168
- if (totalCount > channelMessages.length && !loadingOldMessages) {
169
- setLoadEarlierMsg(true);
170
- try {
171
- const response = await fetchMoreMessages({
172
- variables: {
173
- channelId: channelId == null ? void 0 : channelId.toString(),
174
- parentId: null,
175
- skip: channelMessages.length
214
+ }, [channelId, channelMessages.length, refetch]);
215
+ const sendMessageImpl = useCallback(async () => {
216
+ var _a3, _b3, _c2, _d2, _e, _f, _g, _h;
217
+ try {
218
+ const currentMessageText = messageText;
219
+ setMessageText("");
220
+ const notificationData = {
221
+ url: config.INBOX_MESSEGE_PATH,
222
+ params: {
223
+ channelId,
224
+ hideTabBar: true
225
+ },
226
+ screen: "DialogMessages",
227
+ other: {
228
+ sound: Platform.OS === "android" ? void 0 : "default"
229
+ }
230
+ };
231
+ const messageId = objectId();
232
+ const optimisticMessage = {
233
+ __typename: "Post",
234
+ id: messageId,
235
+ message: currentMessageText,
236
+ createdAt: new Date().toISOString(),
237
+ updatedAt: new Date().toISOString(),
238
+ author: {
239
+ __typename: "UserAccount",
240
+ id: auth == null ? void 0 : auth.id,
241
+ givenName: ((_a3 = auth == null ? void 0 : auth.profile) == null ? void 0 : _a3.given_name) || "",
242
+ familyName: ((_b3 = auth == null ? void 0 : auth.profile) == null ? void 0 : _b3.family_name) || "",
243
+ email: ((_c2 = auth == null ? void 0 : auth.profile) == null ? void 0 : _c2.email) || "",
244
+ username: ((_d2 = auth == null ? void 0 : auth.profile) == null ? void 0 : _d2.nickname) || "",
245
+ fullName: ((_e = auth == null ? void 0 : auth.profile) == null ? void 0 : _e.name) || "",
246
+ picture: ((_f = auth == null ? void 0 : auth.profile) == null ? void 0 : _f.picture) || "",
247
+ alias: [(_g = auth == null ? void 0 : auth.authUserId) != null ? _g : ""],
248
+ tokens: []
249
+ },
250
+ isDelivered: true,
251
+ isRead: false,
252
+ type: "TEXT",
253
+ parentId: null,
254
+ fromServer: false,
255
+ channel: {
256
+ __typename: "Channel",
257
+ id: channelId
258
+ },
259
+ propsConfiguration: {
260
+ __typename: "MachineConfiguration",
261
+ id: null,
262
+ resource: "",
263
+ contents: null,
264
+ keys: null,
265
+ target: null,
266
+ overrides: null
267
+ },
268
+ props: {},
269
+ files: {
270
+ __typename: "FilesInfo",
271
+ data: [],
272
+ totalCount: 0
273
+ },
274
+ replies: {
275
+ __typename: "Messages",
276
+ data: [],
277
+ totalCount: 0
278
+ }
279
+ };
280
+ const response = await sendMsg({
281
+ variables: {
282
+ channelId,
283
+ content: currentMessageText,
284
+ notificationParams: notificationData
285
+ },
286
+ optimisticResponse: {
287
+ __typename: "Mutation",
288
+ sendMessage: optimisticMessage
289
+ },
290
+ update: (cache, {
291
+ data: data2
292
+ }) => {
293
+ if (!(data2 == null ? void 0 : data2.sendMessage))
294
+ return;
295
+ try {
296
+ cache.writeQuery({
297
+ query: MESSAGES_DOCUMENT,
298
+ variables: {
299
+ channelId: channelId == null ? void 0 : channelId.toString(),
300
+ parentId: null,
301
+ limit: MESSAGES_PER_PAGE,
302
+ skip: 0
303
+ },
304
+ data: {
305
+ messages: {
306
+ __typename: "Messages",
307
+ messagesRefId: channelId,
308
+ data: [data2.sendMessage],
309
+ totalCount: 1
310
+ }
311
+ }
312
+ });
313
+ } catch (error2) {
314
+ console.error("Error updating cache:", error2);
315
+ let errorMsg = "Failed to update message cache";
316
+ if (__DEV__ && error2) {
317
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Cache update failed";
318
+ }
319
+ setNotificationType("error");
320
+ setErrorMessage(errorMsg);
176
321
  }
322
+ }
323
+ });
324
+ setIsUploadingImage(false);
325
+ setLoading(false);
326
+ return {
327
+ message: (_h = response.data) == null ? void 0 : _h.sendMessage
328
+ };
329
+ } catch (error2) {
330
+ setLoading(false);
331
+ setIsUploadingImage(false);
332
+ let errorMsg = "Failed to send message";
333
+ if (__DEV__ && error2) {
334
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Message sending failed";
335
+ }
336
+ setNotificationType("error");
337
+ setErrorMessage(errorMsg);
338
+ setError(String(error2));
339
+ return {
340
+ error: String(error2)
341
+ };
342
+ }
343
+ }, [channelId, messageText, sendMsg, auth]);
344
+ const onSelectImages = async () => {
345
+ setLoading(true);
346
+ try {
347
+ let imageSource = await ImagePicker.launchImageLibraryAsync({
348
+ mediaTypes: ImagePicker.MediaTypeOptions.Images,
349
+ allowsEditing: false,
350
+ aspect: [4, 3],
351
+ quality: 0.8,
352
+ base64: true,
353
+ exif: false,
354
+ allowsMultipleSelection: true
355
+ });
356
+ if (!(imageSource == null ? void 0 : imageSource.canceled)) {
357
+ const selectedAssets = (imageSource == null ? void 0 : imageSource.assets) || [];
358
+ if (selectedAssets.length === 0) {
359
+ setLoading(false);
360
+ return;
361
+ }
362
+ const newImages = selectedAssets.map((selectedAsset) => {
363
+ const base64Data = selectedAsset.base64;
364
+ const previewImage = base64Data ? `data:image/jpeg;base64,${base64Data}` : selectedAsset.uri;
365
+ const asset = __spreadProps(__spreadValues({}, selectedAsset), {
366
+ url: selectedAsset.uri,
367
+ fileName: selectedAsset.fileName || `image_${Date.now()}.jpg`,
368
+ mimeType: "image/jpeg"
369
+ });
370
+ return asset;
177
371
  });
178
- if (response == null ? void 0 : response.data) {
179
- setSkip(channelMessages.length);
180
- setLoadEarlierMsg(false);
181
- setLoadingOldMessages(true);
372
+ if (newImages.length > 0) {
373
+ const base64Data = newImages[0].base64;
374
+ const previewImage = base64Data ? `data:image/jpeg;base64,${base64Data}` : newImages[0].uri;
375
+ setSelectedImage(previewImage);
376
+ }
377
+ setImages((currentImages) => [...currentImages, ...newImages]);
378
+ if (!isActionSheetVisible) {
379
+ setActionSheetVisible(true);
182
380
  }
183
- } catch (error) {
184
- setLoadEarlierMsg(false);
381
+ } else {
382
+ setLoading(false);
185
383
  }
384
+ } catch (error2) {
385
+ setLoading(false);
186
386
  }
187
- }, [totalCount, channelMessages]);
188
- const isCloseToTop = ({
189
- layoutMeasurement,
190
- contentOffset,
191
- contentSize
192
- }) => {
193
- const paddingToTop = 60;
194
- return contentSize.height - layoutMeasurement.height - paddingToTop <= contentOffset.y;
195
387
  };
196
- const dataURLtoFile = (dataurl, filename) => {
197
- var arr = dataurl.split(","), mime = arr[0].match(/:(.*?);/)[1], bstr = encode(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
198
- while (n--) {
199
- u8arr[n] = bstr.charCodeAt(n);
388
+ const [uploadingMessageId, setUploadingMessageId] = useState(null);
389
+ const [pendingUploads, setPendingUploads] = useState({});
390
+ const [uploadErrors, setUploadErrors] = useState({});
391
+ const [isUploadingImage, setIsUploadingImage] = useState(false);
392
+ useEffect(() => {
393
+ if (images.length === 0) {
394
+ setIsUploadingImage(false);
200
395
  }
201
- return new File([u8arr], filename, {
202
- type: mime
396
+ }, [images]);
397
+ useToast();
398
+ const removeMessageFromUI = useCallback((messageId) => {
399
+ setPendingUploads((prev) => {
400
+ const newPending = __spreadValues({}, prev);
401
+ delete newPending[messageId];
402
+ return newPending;
203
403
  });
204
- };
205
- const onSelectImages = async () => {
206
- var _a3;
207
- setImageLoading(true);
208
- let imageSource = await ImagePicker.launchImageLibraryAsync({
209
- mediaTypes: ImagePicker.MediaTypeOptions.Images,
210
- allowsEditing: true,
211
- aspect: [4, 3],
212
- quality: 1,
213
- base64: true
404
+ setUploadErrors((prev) => {
405
+ const newErrors = __spreadValues({}, prev);
406
+ delete newErrors[messageId];
407
+ return newErrors;
214
408
  });
215
- if (!imageSource.canceled) {
216
- const image = "data:image/jpeg;base64," + ((_a3 = imageSource == null ? void 0 : imageSource.assets[0]) == null ? void 0 : _a3.base64);
217
- setImage(image);
218
- const file = dataURLtoFile(image, "inputImage.jpg");
219
- setFiles((files2) => files2.concat(file));
220
- setImages((images2) => images2.concat(imageSource == null ? void 0 : imageSource.assets[0]));
221
- }
222
- if (imageSource.canceled)
409
+ setIsUploadingImage(false);
410
+ }, []);
411
+ const sendMessageWithFileImpl = useCallback(async () => {
412
+ var _a3, _b3, _c2, _d2, _e, _f, _g;
413
+ try {
414
+ const postId = objectId();
415
+ setIsUploadingImage(true);
223
416
  setLoading(false);
224
- };
225
- const createDirectChannel = useCallback((msg2) => {
226
- var _a3, _b2, _c, _d, _e, _f, _g, _h;
227
- if ((rest == null ? void 0 : rest.isCreateNewChannel) && ((_a3 = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _a3.type) === ((_b2 = RoomType) == null ? void 0 : _b2.Direct) && ((_d = (_c = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _c.userIds) == null ? void 0 : _d.length) > 0) {
228
- (_h = (_g = addDirectChannel({
229
- variables: {
230
- receiver: [...(_f = (_e = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _e.userIds) != null ? _f : []],
231
- displayName: "DIRECT CHANNEL"
417
+ setUploadingMessageId(null);
418
+ if (!images || images.length === 0) {
419
+ setIsUploadingImage(false);
420
+ setLoading(false);
421
+ return {
422
+ error: "No images available to upload"
423
+ };
424
+ }
425
+ const currentMessageText = messageText;
426
+ const currentImages = [...images];
427
+ const imageUris = currentImages.map((img) => img.uri || img.url);
428
+ setMessageText("");
429
+ setSelectedImage("");
430
+ setImages([]);
431
+ const clientMessage = {
432
+ _id: postId,
433
+ text: currentMessageText || " ",
434
+ createdAt: new Date(),
435
+ user: {
436
+ _id: (auth == null ? void 0 : auth.id) || "",
437
+ name: `${(auth == null ? void 0 : auth.givenName) || ""} ${(auth == null ? void 0 : auth.familyName) || ""}`,
438
+ avatar: (auth == null ? void 0 : auth.picture) || ""
439
+ },
440
+ image: imageUris[0],
441
+ images: imageUris,
442
+ sent: true,
443
+ received: true,
444
+ pending: false,
445
+ type: "TEXT",
446
+ replies: {
447
+ data: [],
448
+ totalCount: 0
449
+ },
450
+ isShowThreadMessage: false
451
+ };
452
+ setPendingUploads((prev) => __spreadProps(__spreadValues({}, prev), {
453
+ [postId]: clientMessage
454
+ }));
455
+ const notificationData = {
456
+ url: config.INBOX_MESSEGE_PATH,
457
+ params: {
458
+ channelId,
459
+ hideTabBar: true
460
+ },
461
+ screen: "DialogMessages",
462
+ other: {
463
+ sound: Platform.OS === "android" ? void 0 : "default"
232
464
  }
233
- })) == null ? void 0 : _g.then(async (res) => {
234
- var _a4, _b3, _c2, _d2, _e2, _f2, _g2, _h2;
235
- if ((_b3 = (_a4 = res == null ? void 0 : res.data) == null ? void 0 : _a4.createDirectChannel) == null ? void 0 : _b3.id) {
236
- setChannelId((_d2 = (_c2 = res == null ? void 0 : res.data) == null ? void 0 : _c2.createDirectChannel) == null ? void 0 : _d2.id);
237
- const notificationData = {
238
- url: config.INBOX_MESSEGE_PATH,
239
- params: {
240
- channelId: (_f2 = (_e2 = res == null ? void 0 : res.data) == null ? void 0 : _e2.createDirectChannel) == null ? void 0 : _f2.id,
241
- hideTabBar: true
242
- },
243
- screen: "DialogMessages",
244
- other: {
245
- sound: Platform.OS === "android" ? void 0 : "default"
246
- }
247
- };
248
- setLoading(true);
249
- await sendMsg({
250
- variables: {
251
- channelId: (_h2 = (_g2 = res == null ? void 0 : res.data) == null ? void 0 : _g2.createDirectChannel) == null ? void 0 : _h2.id,
252
- content: msg2,
253
- notificationParams: notificationData
465
+ };
466
+ const optimisticMessage = {
467
+ __typename: "Post",
468
+ id: postId,
469
+ message: currentMessageText || " ",
470
+ createdAt: new Date().toISOString(),
471
+ updatedAt: new Date().toISOString(),
472
+ author: {
473
+ __typename: "UserAccount",
474
+ id: auth == null ? void 0 : auth.id,
475
+ givenName: ((_a3 = auth == null ? void 0 : auth.profile) == null ? void 0 : _a3.given_name) || "",
476
+ familyName: ((_b3 = auth == null ? void 0 : auth.profile) == null ? void 0 : _b3.family_name) || "",
477
+ email: ((_c2 = auth == null ? void 0 : auth.profile) == null ? void 0 : _c2.email) || "",
478
+ username: ((_d2 = auth == null ? void 0 : auth.profile) == null ? void 0 : _d2.nickname) || "",
479
+ fullName: ((_e = auth == null ? void 0 : auth.profile) == null ? void 0 : _e.name) || "",
480
+ picture: ((_f = auth == null ? void 0 : auth.profile) == null ? void 0 : _f.picture) || "",
481
+ alias: [(_g = auth == null ? void 0 : auth.authUserId) != null ? _g : ""],
482
+ tokens: []
483
+ },
484
+ isDelivered: true,
485
+ isRead: false,
486
+ type: "TEXT",
487
+ parentId: null,
488
+ fromServer: false,
489
+ channel: {
490
+ __typename: "Channel",
491
+ id: channelId
492
+ },
493
+ propsConfiguration: {
494
+ __typename: "MachineConfiguration",
495
+ id: null,
496
+ resource: "",
497
+ contents: null,
498
+ keys: null,
499
+ target: null,
500
+ overrides: null
501
+ },
502
+ props: {},
503
+ files: {
504
+ __typename: "FilesInfo",
505
+ data: imageUris.map((uri, index) => ({
506
+ __typename: "FileInfo",
507
+ id: `temp-file-${index}-${postId}`,
508
+ url: uri,
509
+ name: `image-${index}.jpg`,
510
+ extension: "jpg",
511
+ mimeType: "image/jpeg",
512
+ size: 0,
513
+ height: 300,
514
+ width: 300,
515
+ channel: null,
516
+ post: null,
517
+ refType: FileRefType.Post
518
+ })),
519
+ totalCount: imageUris.length
520
+ },
521
+ replies: {
522
+ __typename: "Messages",
523
+ data: [],
524
+ totalCount: 0
525
+ }
526
+ };
527
+ setTimeout(async () => {
528
+ var _a4;
529
+ try {
530
+ const imagesToUpload = currentImages.map((img) => __spreadProps(__spreadValues({}, img), {
531
+ uri: img.uri || img.url,
532
+ type: img.mimeType || "image/jpeg",
533
+ name: img.fileName || `image_${Date.now()}.jpg`
534
+ }));
535
+ const uploadResponse = await startUpload({
536
+ file: imagesToUpload,
537
+ saveUploadedFile: {
538
+ variables: {
539
+ postId
540
+ }
254
541
  },
255
- update: (cache, {
256
- data: data2,
257
- errors
258
- }) => {
259
- if (!data2 || errors) {
260
- setLoading(false);
261
- return;
542
+ createUploadLink: {
543
+ variables: {
544
+ postId
262
545
  }
263
- setChannelToTop(channelToTop + 1);
264
- setLoading(false);
265
- setMsg("");
266
546
  }
267
547
  });
548
+ if (uploadResponse == null ? void 0 : uploadResponse.error) {
549
+ console.error("Upload error:", uploadResponse.error);
550
+ let errorMsg = "Failed to upload image. Please try again.";
551
+ if (__DEV__ && uploadResponse.error) {
552
+ errorMsg = typeof uploadResponse.error === "string" ? uploadResponse.error : uploadResponse.error.message || errorMsg;
553
+ }
554
+ setNotificationType("error");
555
+ setErrorMessage(errorMsg);
556
+ setUploadErrors((prev) => __spreadProps(__spreadValues({}, prev), {
557
+ [postId]: errorMsg
558
+ }));
559
+ removeMessageFromUI(postId);
560
+ setIsUploadingImage(false);
561
+ setLoading(false);
562
+ return;
563
+ }
564
+ const uploadedFiles = uploadResponse.data;
565
+ const fileIds = (_a4 = uploadedFiles == null ? void 0 : uploadedFiles.map((f) => f.id)) != null ? _a4 : null;
566
+ if ((fileIds == null ? void 0 : fileIds.length) > 0) {
567
+ await sendMsg({
568
+ variables: {
569
+ postId,
570
+ channelId,
571
+ content: currentMessageText || " ",
572
+ files: fileIds,
573
+ notificationParams: notificationData
574
+ },
575
+ optimisticResponse: {
576
+ __typename: "Mutation",
577
+ sendMessage: optimisticMessage
578
+ },
579
+ update: (cache, {
580
+ data: data2
581
+ }) => {
582
+ var _a5, _b4;
583
+ if (!(data2 == null ? void 0 : data2.sendMessage)) {
584
+ setIsUploadingImage(false);
585
+ setLoading(false);
586
+ return;
587
+ }
588
+ try {
589
+ cache.writeQuery({
590
+ query: MESSAGES_DOCUMENT,
591
+ variables: {
592
+ channelId: channelId == null ? void 0 : channelId.toString(),
593
+ parentId: null,
594
+ limit: MESSAGES_PER_PAGE,
595
+ skip: 0
596
+ },
597
+ data: {
598
+ messages: {
599
+ __typename: "Messages",
600
+ messagesRefId: channelId,
601
+ data: [data2.sendMessage],
602
+ totalCount: 1
603
+ }
604
+ }
605
+ });
606
+ const serverMessage = data2.sendMessage;
607
+ const hasServerImage = (_b4 = (_a5 = serverMessage == null ? void 0 : serverMessage.files) == null ? void 0 : _a5.data) == null ? void 0 : _b4.some((file) => file.url);
608
+ if (hasServerImage) {
609
+ removeMessageFromUI(postId);
610
+ }
611
+ setIsUploadingImage(false);
612
+ setLoading(false);
613
+ } catch (error2) {
614
+ console.error("Cache update error:", error2);
615
+ let errorMsg = "Failed to update message.";
616
+ if (__DEV__ && error2) {
617
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Cache update failed";
618
+ }
619
+ setNotificationType("error");
620
+ setErrorMessage(errorMsg);
621
+ setIsUploadingImage(false);
622
+ setLoading(false);
623
+ }
624
+ }
625
+ });
626
+ } else {
627
+ setIsUploadingImage(false);
628
+ setLoading(false);
629
+ }
630
+ } catch (error2) {
631
+ console.error("Background process error:", error2);
632
+ let errorMsg = "Failed to send image. Please try again.";
633
+ if (__DEV__ && error2) {
634
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Background process failed";
635
+ }
636
+ setNotificationType("error");
637
+ setErrorMessage(errorMsg);
638
+ removeMessageFromUI(postId);
639
+ setIsUploadingImage(false);
640
+ setLoading(false);
268
641
  }
269
- })) == null ? void 0 : _h.catch((e) => console.log("error", JSON.stringify(e)));
270
- }
271
- }, [rest]);
272
- const handleSend = useCallback(async (message) => {
273
- var _a3;
274
- if (!channelId)
275
- return;
276
- if (!message && message != " " && images.length == 0)
277
- return;
278
- const notificationData = {
279
- url: config.INBOX_MESSEGE_PATH,
280
- params: {
281
- channelId,
282
- hideTabBar: true
283
- },
284
- screen: "DialogMessages",
285
- other: {
286
- sound: Platform.OS === "android" ? void 0 : "default"
642
+ }, 0);
643
+ return {
644
+ success: true
645
+ };
646
+ } catch (error2) {
647
+ console.error("Send message error:", error2);
648
+ let errorMsg = "Failed to process image. Please try again.";
649
+ if (__DEV__ && error2) {
650
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Image processing failed";
287
651
  }
288
- };
289
- if (images && images.length > 0) {
290
- const postId = objectId();
652
+ setNotificationType("error");
653
+ setErrorMessage(errorMsg);
654
+ setError(String(error2));
655
+ setIsUploadingImage(false);
656
+ setLoading(false);
657
+ return {
658
+ error: String(error2)
659
+ };
660
+ }
661
+ }, [channelId, messageText, images, selectedImage, startUpload, sendMsg, auth, removeMessageFromUI]);
662
+ const createDirectChannelImpl = useCallback(async () => {
663
+ var _a3, _b3, _c2, _d2, _e, _f, _g, _h;
664
+ try {
291
665
  setLoading(true);
292
- const uploadResponse = await startUpload({
293
- file: images,
294
- saveUploadedFile: {
295
- variables: {
296
- postId
297
- }
298
- },
299
- createUploadLink: {
300
- variables: {
301
- postId
302
- }
666
+ 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)) {
667
+ setLoading(false);
668
+ setNotificationType("error");
669
+ setErrorMessage(__DEV__ ? "Invalid channel data" : "Unable to create conversation");
670
+ return {
671
+ error: "Invalid channel data"
672
+ };
673
+ }
674
+ const currentMessageText = messageText;
675
+ setMessageText("");
676
+ const response = await addDirectChannel({
677
+ variables: {
678
+ receiver: [...(_f = (_e = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _e.userIds) != null ? _f : []],
679
+ displayName: "DIRECT CHANNEL"
303
680
  }
304
681
  });
305
- if (uploadResponse == null ? void 0 : uploadResponse.error)
682
+ if (!((_h = (_g = response == null ? void 0 : response.data) == null ? void 0 : _g.createDirectChannel) == null ? void 0 : _h.id)) {
306
683
  setLoading(false);
307
- const uploadedFiles = uploadResponse.data;
308
- if (uploadResponse.data) {
309
- setImage("");
310
- setFiles([]);
311
- setImages([]);
312
- const files2 = (_a3 = uploadedFiles == null ? void 0 : uploadedFiles.map((f) => f.id)) != null ? _a3 : null;
313
- await sendMsg({
314
- variables: {
315
- postId,
316
- channelId,
317
- content: message,
318
- files: files2,
319
- notificationParams: notificationData
320
- },
321
- update: (cache, {
322
- data: data2,
323
- errors
324
- }) => {
325
- if (!data2 || errors) {
326
- setLoading(false);
327
- return;
328
- }
329
- const newMessage = data2 == null ? void 0 : data2.sendMessage;
330
- setChannelMessages((oldMessages) => uniqBy([...oldMessages, newMessage], ({
331
- id
332
- }) => id));
333
- setTotalCount((t) => t + 1);
334
- setChannelToTop(channelToTop + 1);
335
- setLoading(false);
336
- setMsg("");
337
- }
338
- });
684
+ setNotificationType("error");
685
+ setErrorMessage(__DEV__ ? "Failed to create channel" : "Unable to create conversation");
686
+ return {
687
+ error: "Failed to create channel"
688
+ };
339
689
  }
340
- } else {
341
- setLoading(true);
690
+ const newChannelId = response.data.createDirectChannel.id;
691
+ setChannelId(newChannelId);
692
+ const notificationData = {
693
+ url: config.INBOX_MESSEGE_PATH,
694
+ params: {
695
+ channelId: newChannelId,
696
+ hideTabBar: true
697
+ },
698
+ screen: "DialogMessages",
699
+ other: {
700
+ sound: Platform.OS === "android" ? void 0 : "default"
701
+ }
702
+ };
703
+ const messageId = objectId();
704
+ const optimisticMessage = {
705
+ __typename: "Post",
706
+ id: messageId,
707
+ message: currentMessageText,
708
+ createdAt: new Date().toISOString(),
709
+ updatedAt: new Date().toISOString(),
710
+ author: {
711
+ __typename: "UserAccount",
712
+ id: auth == null ? void 0 : auth.id,
713
+ picture: (auth == null ? void 0 : auth.picture) || "",
714
+ givenName: (auth == null ? void 0 : auth.givenName) || "",
715
+ familyName: (auth == null ? void 0 : auth.familyName) || "",
716
+ email: (auth == null ? void 0 : auth.email) || "",
717
+ username: (auth == null ? void 0 : auth.username) || "",
718
+ alias: [],
719
+ tokens: (auth == null ? void 0 : auth.token) ? [...auth == null ? void 0 : auth.token] : []
720
+ },
721
+ isDelivered: true,
722
+ isRead: false,
723
+ type: "TEXT",
724
+ parentId: null,
725
+ fromServer: false,
726
+ channel: {
727
+ __typename: "Channel",
728
+ id: newChannelId
729
+ },
730
+ propsConfiguration: {
731
+ __typename: "MachineConfiguration",
732
+ id: null,
733
+ resource: "",
734
+ contents: null,
735
+ keys: null,
736
+ target: null,
737
+ overrides: null
738
+ },
739
+ props: {},
740
+ files: {
741
+ __typename: "FilesInfo",
742
+ data: [],
743
+ totalCount: 0
744
+ },
745
+ replies: {
746
+ __typename: "Messages",
747
+ data: [],
748
+ totalCount: 0
749
+ }
750
+ };
342
751
  await sendMsg({
343
752
  variables: {
344
- channelId,
345
- content: message,
753
+ channelId: newChannelId,
754
+ content: currentMessageText,
346
755
  notificationParams: notificationData
347
756
  },
757
+ optimisticResponse: {
758
+ __typename: "Mutation",
759
+ sendMessage: optimisticMessage
760
+ },
348
761
  update: (cache, {
349
- data: data2,
350
- errors
762
+ data: data2
351
763
  }) => {
352
- if (!data2 || errors) {
353
- setLoading(false);
764
+ if (!(data2 == null ? void 0 : data2.sendMessage))
354
765
  return;
766
+ try {
767
+ cache.writeQuery({
768
+ query: MESSAGES_DOCUMENT,
769
+ variables: {
770
+ channelId: newChannelId,
771
+ parentId: null,
772
+ limit: MESSAGES_PER_PAGE,
773
+ skip: 0
774
+ },
775
+ data: {
776
+ messages: {
777
+ __typename: "Messages",
778
+ messagesRefId: newChannelId,
779
+ data: [data2.sendMessage],
780
+ totalCount: 1
781
+ }
782
+ }
783
+ });
784
+ } catch (error2) {
785
+ console.error("Error updating cache:", error2);
786
+ let errorMsg = "Failed to update message cache";
787
+ if (__DEV__ && error2) {
788
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Cache update failed";
789
+ }
790
+ setNotificationType("error");
791
+ setErrorMessage(errorMsg);
355
792
  }
356
- const newMessage = data2 == null ? void 0 : data2.sendMessage;
357
- setChannelMessages((oldMessages) => uniqBy([...oldMessages, newMessage], ({
358
- id
359
- }) => id));
360
- setTotalCount((t) => t + 1);
361
- setChannelToTop(channelToTop + 1);
362
- setLoading(false);
363
- setMsg("");
364
793
  }
365
794
  });
795
+ setLoading(false);
796
+ return {
797
+ channelId: newChannelId
798
+ };
799
+ } catch (error2) {
800
+ setLoading(false);
801
+ let errorMsg = "Failed to create conversation";
802
+ if (__DEV__ && error2) {
803
+ errorMsg = error2.message ? error2.message.replace("[ApolloError: ", "").replace("]", "") : "Channel creation failed";
804
+ }
805
+ setNotificationType("error");
806
+ setErrorMessage(errorMsg);
807
+ setError(String(error2));
808
+ return {
809
+ error: String(error2)
810
+ };
366
811
  }
367
- }, [setChannelMessages, channelId, images, channelToTop, expoTokens]);
812
+ }, [rest, messageText, addDirectChannel, sendMsg, auth]);
813
+ const onFetchOld = useCallback(() => {
814
+ if (fetchOldDebounceRef.current)
815
+ return;
816
+ if (totalCount > channelMessages.length && !loadingOldMessages) {
817
+ fetchOldDebounceRef.current = true;
818
+ fetchMoreMessagesImpl();
819
+ setTimeout(() => {
820
+ fetchOldDebounceRef.current = false;
821
+ }, 1e3);
822
+ }
823
+ }, [totalCount, channelMessages.length, loadingOldMessages, fetchMoreMessagesImpl]);
824
+ const isCloseToTop = ({
825
+ layoutMeasurement,
826
+ contentOffset,
827
+ contentSize
828
+ }) => {
829
+ const paddingToTop = 60;
830
+ return contentSize.height - layoutMeasurement.height - paddingToTop <= contentOffset.y;
831
+ };
368
832
  const messageList = useMemo(() => {
369
- let res = [];
370
- const filteredMessages = channelMessages && (channelMessages == null ? void 0 : channelMessages.length) > 0 ? uniqBy([...channelMessages], ({
833
+ const pendingMessages = Object.values(pendingUploads);
834
+ if (!channelMessages || channelMessages.length === 0) {
835
+ return pendingMessages;
836
+ }
837
+ const filteredMessages = uniqBy(channelMessages, ({
371
838
  id
372
- }) => id) : [];
373
- if (channelId && (filteredMessages == null ? void 0 : filteredMessages.length) > 0) {
374
- orderBy(channelMessages, ["createdAt"], ["desc"]).map((msg2) => {
375
- var _a3, _b2, _c, _d;
376
- let message = {
377
- _id: "",
378
- text: "",
379
- createdAt: 0,
380
- user: {
381
- _id: "",
382
- name: "",
383
- avatar: ""
384
- },
385
- type: ""
386
- };
387
- const date = new Date(msg2.createdAt);
388
- message._id = msg2.id;
389
- message.text = msg2.message;
390
- message.createdAt = date;
391
- message.user = {
392
- _id: msg2.author.id,
393
- name: msg2.author.givenName + " " + msg2.author.familyName,
394
- avatar: (_a3 = msg2.author) == null ? void 0 : _a3.picture
395
- }, message.image = (_c = (_b2 = msg2.files) == null ? void 0 : _b2.data[0]) == null ? void 0 : _c.url, message.sent = msg2 == null ? void 0 : msg2.isDelivered, message.received = msg2 == null ? void 0 : msg2.isRead;
396
- message.type = msg2 == null ? void 0 : msg2.type;
397
- message.propsConfiguration = msg2 == null ? void 0 : msg2.propsConfiguration;
398
- message.replies = (_d = msg2 == null ? void 0 : msg2.replies) != null ? _d : [];
399
- message.isShowThreadMessage = isShowThreadMessage;
400
- res.push(message);
401
- });
839
+ }) => id);
840
+ const serverMessages = orderBy(filteredMessages, ["createdAt"], ["desc"]).map((msg) => {
841
+ var _a3, _b3, _c2, _d2, _e;
842
+ const date = new Date(msg.createdAt);
843
+ if (pendingUploads[msg.id]) {
844
+ return null;
845
+ }
846
+ let imageUrls = [];
847
+ let primaryImageUrl = null;
848
+ if (msg.files && typeof msg.files === "object") {
849
+ const filesData = msg.files.data || (Array.isArray(msg.files) ? msg.files : null);
850
+ if (filesData && filesData.length > 0) {
851
+ imageUrls = filesData.filter((fileData) => fileData && typeof fileData === "object" && fileData.url).map((fileData) => fileData.url);
852
+ if (imageUrls.length > 0) {
853
+ primaryImageUrl = imageUrls[0];
854
+ }
855
+ }
856
+ }
857
+ return {
858
+ _id: msg.id,
859
+ text: msg.message,
860
+ createdAt: date,
861
+ user: {
862
+ _id: ((_a3 = msg.author) == null ? void 0 : _a3.id) || "",
863
+ name: `${((_b3 = msg.author) == null ? void 0 : _b3.givenName) || ""} ${((_c2 = msg.author) == null ? void 0 : _c2.familyName) || ""}`,
864
+ avatar: ((_d2 = msg.author) == null ? void 0 : _d2.picture) || ""
865
+ },
866
+ image: primaryImageUrl,
867
+ images: imageUrls,
868
+ sent: msg == null ? void 0 : msg.isDelivered,
869
+ received: msg == null ? void 0 : msg.isRead,
870
+ type: msg == null ? void 0 : msg.type,
871
+ propsConfiguration: msg == null ? void 0 : msg.propsConfiguration,
872
+ replies: (_e = msg == null ? void 0 : msg.replies) != null ? _e : [],
873
+ isShowThreadMessage
874
+ };
875
+ }).filter(Boolean);
876
+ return [...pendingMessages, ...serverMessages];
877
+ }, [channelMessages, pendingUploads, isShowThreadMessage]);
878
+ const renderSend = useCallback((props) => {
879
+ const hasContent = !!props.text || (images == null ? void 0 : images.length) > 0;
880
+ const canSend = (channelId || (rest == null ? void 0 : rest.isCreateNewChannel)) && hasContent;
881
+ const isDisabled = !canSend;
882
+ return /* @__PURE__ */ React__default.createElement(
883
+ Send,
884
+ __spreadProps(__spreadValues({}, props), {
885
+ containerStyle: {
886
+ justifyContent: "center",
887
+ alignItems: "center",
888
+ height: 40,
889
+ width: 44,
890
+ marginRight: 4,
891
+ marginBottom: 0,
892
+ marginLeft: 4
893
+ }
894
+ }),
895
+ /* @__PURE__ */ React__default.createElement(View, { style: {
896
+ padding: 4
897
+ } }, /* @__PURE__ */ React__default.createElement(MaterialCommunityIcons, { name: "send-circle", size: 32, color: isDisabled ? colors.gray[400] : colors.blue[500] }))
898
+ );
899
+ }, [channelId, images, rest == null ? void 0 : rest.isCreateNewChannel, isUploadingImage, loading, isActionSheetVisible]);
900
+ useCallback(() => {
901
+ console.log("Opening action sheet");
902
+ setActionSheetVisible(true);
903
+ }, []);
904
+ useEffect(() => {
905
+ console.log("Action sheet visibility:", isActionSheetVisible);
906
+ if (isActionSheetVisible) {
907
+ setBottomMargin(0);
402
908
  }
403
- return (res == null ? void 0 : res.length) > 0 ? uniqBy([...res], ({
404
- _id
405
- }) => _id) : [];
406
- }, [channelMessages, channelId]);
407
- const renderSend = (props) => {
408
- return /* @__PURE__ */ React__default.createElement(Send, __spreadProps(__spreadValues({}, props), { disabled: channelId || (rest == null ? void 0 : rest.isCreateNewChannel) ? false : true }), /* @__PURE__ */ React__default.createElement(Box, null, /* @__PURE__ */ React__default.createElement(MaterialCommunityIcons, { name: "send-circle", style: {
409
- marginBottom: 5,
410
- marginRight: 5
411
- }, size: 32, color: channelId || (rest == null ? void 0 : rest.isCreateNewChannel) ? "#2e64e5" : "#b8b2b2" })));
412
- };
413
- const renderMessageText = (props) => {
414
- var _a3, _b2, _c, _d, _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;
909
+ }, [isActionSheetVisible]);
910
+ const handleRemoveImage = useCallback((index) => {
911
+ const newImages = [...images];
912
+ newImages.splice(index, 1);
913
+ setImages(newImages);
914
+ if (newImages.length === 0) {
915
+ setSelectedImage("");
916
+ if (textInputRef.current && typeof textInputRef.current.focus === "function") {
917
+ textInputRef.current.focus();
918
+ }
919
+ }
920
+ }, [images]);
921
+ const [textUpdatedInActionSheet, setTextUpdatedInActionSheet] = useState(false);
922
+ useCallback(() => {
923
+ setTextUpdatedInActionSheet(true);
924
+ setActionSheetVisible(false);
925
+ setBottomMargin(0);
926
+ }, []);
927
+ useEffect(() => {
928
+ if (!isActionSheetVisible && textUpdatedInActionSheet) {
929
+ console.log("Action sheet closed with text:", messageText);
930
+ setTextUpdatedInActionSheet(false);
931
+ const currentText = messageText;
932
+ setMessageText("");
933
+ setTimeout(() => {
934
+ setMessageText(currentText);
935
+ }, 50);
936
+ }
937
+ }, [isActionSheetVisible, textUpdatedInActionSheet]);
938
+ useEffect(() => {
939
+ if (isActionSheetVisible && Platform.OS === "ios") {
940
+ console.log("Action sheet is visible, should show the input and options");
941
+ }
942
+ }, [isActionSheetVisible]);
943
+ const handleSend = useCallback(async (messages) => {
944
+ var _a3, _b3, _c2;
945
+ const newMessageText = messages && messages.length > 0 ? ((_a3 = messages[0]) == null ? void 0 : _a3.text) || " " : " ";
946
+ if (!channelId && !(rest == null ? void 0 : rest.isCreateNewChannel)) {
947
+ return;
948
+ }
949
+ const hasText = !!newMessageText && newMessageText !== " ";
950
+ const hasImages = images && images.length > 0;
951
+ if (!hasText && !hasImages) {
952
+ return;
953
+ }
954
+ setMessageText(newMessageText);
955
+ if ((rest == null ? void 0 : rest.isCreateNewChannel) && !channelId) {
956
+ if (((_b3 = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _b3.type) === ((_c2 = RoomType) == null ? void 0 : _c2.Direct)) {
957
+ await createDirectChannelImpl();
958
+ }
959
+ setIsUploadingImage(false);
960
+ setLoading(false);
961
+ return;
962
+ }
963
+ if (hasImages) {
964
+ await sendMessageWithFileImpl();
965
+ } else {
966
+ await sendMessageImpl();
967
+ }
968
+ setIsUploadingImage(false);
969
+ setLoading(false);
970
+ setTimeout(() => {
971
+ if (textInputRef.current) {
972
+ textInputRef.current.focus();
973
+ }
974
+ }, 100);
975
+ }, [channelId, images, rest == null ? void 0 : rest.isCreateNewChannel, (_d = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _d.type, createDirectChannelImpl, sendMessageWithFileImpl, sendMessageImpl]);
976
+ const renderMessageText = useCallback((props) => {
977
+ 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;
415
978
  const {
416
979
  currentMessage
417
980
  } = props;
418
- const lastReply = ((_b2 = (_a3 = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _a3.data) == null ? void 0 : _b2.length) > 0 ? (_d = (_c = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _c.data) == null ? void 0 : _d[0] : null;
981
+ 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;
982
+ if (!(currentMessage == null ? void 0 : currentMessage.text) || currentMessage.text.trim() === "") {
983
+ return null;
984
+ }
419
985
  if (currentMessage.type === "ALERT") {
420
986
  const attachment = (_f = (_e = currentMessage == null ? void 0 : currentMessage.propsConfiguration) == null ? void 0 : _e.contents) == null ? void 0 : _f.attachment;
421
987
  let action = "";
422
988
  let actionId = "";
423
- let params = {};
989
+ let params2 = {};
424
990
  if ((_g = attachment == null ? void 0 : attachment.callToAction) == null ? void 0 : _g.extraParams) {
425
991
  const extraParams = (_h = attachment == null ? void 0 : attachment.callToAction) == null ? void 0 : _h.extraParams;
426
992
  const route = (_i = extraParams == null ? void 0 : extraParams.route) != null ? _i : null;
@@ -437,30 +1003,24 @@ const ConversationViewComponent = (_a) => {
437
1003
  param = ((_y = route == null ? void 0 : route.host) == null ? void 0 : _y.params) ? (_A = (_z = route == null ? void 0 : route.host) == null ? void 0 : _z.params) != null ? _A : null : null;
438
1004
  }
439
1005
  action = path;
440
- params = __spreadValues({}, param);
1006
+ params2 = __spreadValues({}, param);
441
1007
  } else if ((_B = attachment == null ? void 0 : attachment.callToAction) == null ? void 0 : _B.link) {
442
1008
  action = CALL_TO_ACTION_PATH;
443
1009
  actionId = (_C = attachment == null ? void 0 : attachment.callToAction) == null ? void 0 : _C.link.split("/").pop();
444
- params = {
1010
+ params2 = {
445
1011
  reservationId: actionId
446
1012
  };
447
1013
  }
448
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, (attachment == null ? void 0 : attachment.callToAction) && action ? /* @__PURE__ */ React__default.createElement(Box, { bg: CALL_TO_ACTION_BOX_BGCOLOR, borderRadius: 15, pb: "$2" }, /* @__PURE__ */ React__default.createElement(
449
- Button,
450
- {
451
- variant: "outline",
452
- size: "sm",
453
- borderColor: CALL_TO_ACTION_BUTTON_BORDERCOLOR,
454
- onPress: () => action && params && navigation.navigate(action, params)
455
- },
456
- /* @__PURE__ */ React__default.createElement(ButtonText, { color: CALL_TO_ACTION_TEXT_COLOR }, attachment.callToAction.title)
457
- ), /* @__PURE__ */ React__default.createElement(MessageText, __spreadProps(__spreadValues({}, props), { textStyle: {
1014
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, (attachment == null ? void 0 : attachment.callToAction) && action ? /* @__PURE__ */ React__default.createElement(Box, { className: `bg-[${CALL_TO_ACTION_BOX_BGCOLOR}] rounded-[15] pb-2` }, /* @__PURE__ */ React__default.createElement(MessageText, __spreadProps(__spreadValues({}, props), { containerStyle: {
1015
+ left: {
1016
+ paddingLeft: 0,
1017
+ marginLeft: 0
1018
+ }
1019
+ }, textStyle: {
458
1020
  left: {
459
- marginLeft: 5,
460
- color: CALL_TO_ACTION_TEXT_COLOR,
461
- paddingHorizontal: 2
1021
+ marginLeft: 0
462
1022
  }
463
- } }))) : /* @__PURE__ */ React__default.createElement(TouchableHighlight, { underlayColor: "#c0c0c0", style: {
1023
+ } })), /* @__PURE__ */ React__default.createElement(Button, { variant: "outline", size: "sm", className: `border-[${CALL_TO_ACTION_BUTTON_BORDERCOLOR}] my-2 rounded-full `, onPress: () => action && params2 && navigation.navigate(action, params2) }, /* @__PURE__ */ React__default.createElement(ButtonText, { className: `color-[${CALL_TO_ACTION_TEXT_COLOR}]` }, attachment.callToAction.title))) : /* @__PURE__ */ React__default.createElement(TouchableHighlight, { underlayColor: "#c0c0c0", style: {
464
1024
  width: "100%"
465
1025
  }, onPress: () => {
466
1026
  if (currentMessage == null ? void 0 : currentMessage.isShowThreadMessage)
@@ -474,23 +1034,23 @@ const ConversationViewComponent = (_a) => {
474
1034
  left: {
475
1035
  marginLeft: 5
476
1036
  }
477
- } })), ((_E = (_D = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _D.data) == null ? void 0 : _E.length) > 0 && /* @__PURE__ */ React__default.createElement(HStack, { space: "sm", px: "$1", alignItems: "center" }, /* @__PURE__ */ React__default.createElement(HStack, null, (_J = (_I = (_H = (_G = (_F = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _F.data) == null ? void 0 : _G.filter((v, i, a) => a.findIndex((t) => {
478
- var _a4, _b3;
479
- return ((_a4 = t == null ? void 0 : t.author) == null ? void 0 : _a4.id) === ((_b3 = v == null ? void 0 : v.author) == null ? void 0 : _b3.id);
1037
+ } })), ((_E = (_D = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _D.data) == null ? void 0 : _E.length) > 0 && /* @__PURE__ */ React__default.createElement(HStack, { space: "sm", className: "px-1 items-center" }, /* @__PURE__ */ React__default.createElement(HStack, null, (_J = (_I = (_H = (_G = (_F = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _F.data) == null ? void 0 : _G.filter((v, i, a) => a.findIndex((t) => {
1038
+ var _a4, _b4;
1039
+ return ((_a4 = t == null ? void 0 : t.author) == null ? void 0 : _a4.id) === ((_b4 = v == null ? void 0 : v.author) == null ? void 0 : _b4.id);
480
1040
  }) === i)) == null ? void 0 : _H.slice(0, 2)) == null ? void 0 : _I.reverse()) == null ? void 0 : _J.map((p, i) => {
481
- var _a4, _b3, _c2;
482
- return /* @__PURE__ */ React__default.createElement(Avatar, { key: "conversations-view-key-" + i, bg: "transparent", size: "sm" }, /* @__PURE__ */ React__default.createElement(AvatarFallbackText, null, startCase((_b3 = (_a4 = p == null ? void 0 : p.author) == null ? void 0 : _a4.username) == null ? void 0 : _b3.charAt(0))), /* @__PURE__ */ React__default.createElement(AvatarImage, { alt: "user image", style: {
1041
+ var _a4, _b4, _c3;
1042
+ return /* @__PURE__ */ React__default.createElement(Avatar, { key: "conversations-view-key-" + i, size: "sm", className: "bg-transparent" }, /* @__PURE__ */ React__default.createElement(AvatarFallbackText, null, startCase((_b4 = (_a4 = p == null ? void 0 : p.author) == null ? void 0 : _a4.username) == null ? void 0 : _b4.charAt(0))), /* @__PURE__ */ React__default.createElement(AvatarImage, { alt: "user image", style: {
483
1043
  borderRadius: 6,
484
1044
  borderWidth: 2,
485
1045
  borderColor: "#fff"
486
1046
  }, source: {
487
- uri: (_c2 = p == null ? void 0 : p.author) == null ? void 0 : _c2.picture
1047
+ uri: (_c3 = p == null ? void 0 : p.author) == null ? void 0 : _c3.picture
488
1048
  } }));
489
1049
  })), /* @__PURE__ */ React__default.createElement(Text, { style: {
490
1050
  fontSize: 12
491
- }, fontWeight: "$bold", color: "$blue800" }, (_K = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _K.totalCount, " ", ((_L = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _L.totalCount) == 1 ? "reply" : "replies"), /* @__PURE__ */ React__default.createElement(Text, { style: {
1051
+ }, className: "font-bold color-blue-800" }, (_K = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _K.totalCount, " ", ((_L = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _L.totalCount) == 1 ? "reply" : "replies"), /* @__PURE__ */ React__default.createElement(Text, { style: {
492
1052
  fontSize: 12
493
- }, fontWeight: "$bold", color: "$trueGray500" }, lastReply ? createdAtText(lastReply == null ? void 0 : lastReply.createdAt) : "")))));
1053
+ }, className: "font-bold color-gray-500" }, lastReply ? createdAtText(lastReply == null ? void 0 : lastReply.createdAt) : "")))));
494
1054
  } else {
495
1055
  return /* @__PURE__ */ React__default.createElement(TouchableHighlight, { underlayColor: "#c0c0c0", style: {
496
1056
  width: "100%"
@@ -506,72 +1066,97 @@ const ConversationViewComponent = (_a) => {
506
1066
  left: {
507
1067
  marginLeft: 5
508
1068
  }
509
- } })), ((_N = (_M = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _M.data) == null ? void 0 : _N.length) > 0 && /* @__PURE__ */ React__default.createElement(HStack, { space: "sm", px: "$1", alignItems: "center" }, /* @__PURE__ */ React__default.createElement(HStack, null, (_S = (_R = (_Q = (_P = (_O = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _O.data) == null ? void 0 : _P.filter((v, i, a) => a.findIndex((t) => {
510
- var _a4, _b3;
511
- return ((_a4 = t == null ? void 0 : t.author) == null ? void 0 : _a4.id) === ((_b3 = v == null ? void 0 : v.author) == null ? void 0 : _b3.id);
1069
+ } })), ((_N = (_M = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _M.data) == null ? void 0 : _N.length) > 0 && /* @__PURE__ */ React__default.createElement(HStack, { space: "sm", className: "px-1 items-center" }, /* @__PURE__ */ React__default.createElement(HStack, null, (_S = (_R = (_Q = (_P = (_O = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _O.data) == null ? void 0 : _P.filter((v, i, a) => a.findIndex((t) => {
1070
+ var _a4, _b4;
1071
+ return ((_a4 = t == null ? void 0 : t.author) == null ? void 0 : _a4.id) === ((_b4 = v == null ? void 0 : v.author) == null ? void 0 : _b4.id);
512
1072
  }) === i)) == null ? void 0 : _Q.slice(0, 2)) == null ? void 0 : _R.reverse()) == null ? void 0 : _S.map((p, i) => {
513
- var _a4, _b3, _c2;
514
- return /* @__PURE__ */ React__default.createElement(Avatar, { key: "conversation-replies-key-" + i, bg: "transparent", size: "sm" }, /* @__PURE__ */ React__default.createElement(AvatarFallbackText, null, startCase((_b3 = (_a4 = p == null ? void 0 : p.author) == null ? void 0 : _a4.username) == null ? void 0 : _b3.charAt(0))), /* @__PURE__ */ React__default.createElement(AvatarImage, { alt: "user image", style: {
1073
+ var _a4, _b4, _c3;
1074
+ return /* @__PURE__ */ React__default.createElement(Avatar, { key: "conversation-replies-key-" + i, className: "bg-transparent", size: "sm" }, /* @__PURE__ */ React__default.createElement(AvatarFallbackText, null, startCase((_b4 = (_a4 = p == null ? void 0 : p.author) == null ? void 0 : _a4.username) == null ? void 0 : _b4.charAt(0))), /* @__PURE__ */ React__default.createElement(AvatarImage, { alt: "user image", style: {
515
1075
  borderRadius: 6,
516
1076
  borderWidth: 2,
517
1077
  borderColor: "#fff"
518
1078
  }, source: {
519
- uri: (_c2 = p == null ? void 0 : p.author) == null ? void 0 : _c2.picture
1079
+ uri: (_c3 = p == null ? void 0 : p.author) == null ? void 0 : _c3.picture
520
1080
  } }));
521
1081
  })), /* @__PURE__ */ React__default.createElement(Text, { style: {
522
1082
  fontSize: 12
523
- }, fontWeight: "$bold", color: "$blue800" }, (_T = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _T.totalCount, " ", ((_U = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _U.totalCount) == 1 ? "reply" : "replies"), /* @__PURE__ */ React__default.createElement(Text, { style: {
1083
+ }, className: "font-bold color-blue-800" }, (_T = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _T.totalCount, " ", ((_U = currentMessage == null ? void 0 : currentMessage.replies) == null ? void 0 : _U.totalCount) == 1 ? "reply" : "replies"), /* @__PURE__ */ React__default.createElement(Text, { style: {
524
1084
  fontSize: 12
525
- }, fontWeight: "$bold", color: "$trueGray500" }, lastReply ? createdAtText(lastReply == null ? void 0 : lastReply.createdAt) : ""))));
1085
+ }, className: "font-bold color-gray-500" }, lastReply ? createdAtText(lastReply == null ? void 0 : lastReply.createdAt) : ""))));
526
1086
  }
527
- };
528
- const renderActions = (props) => {
529
- return /* @__PURE__ */ React__default.createElement(Actions, __spreadProps(__spreadValues({}, props), { icon: () => /* @__PURE__ */ React__default.createElement(Ionicons, { name: "image", size: 30, color: "black", onPress: onSelectImages }) }));
530
- };
531
- const renderAccessory = (props) => {
532
- return /* @__PURE__ */ React__default.createElement(Box, null, selectedImage !== "" ? /* @__PURE__ */ React__default.createElement(HStack, { alignItems: "center" }, /* @__PURE__ */ React__default.createElement(Image, { ml: "$3", key: selectedImage, alt: "image", source: {
533
- uri: selectedImage
534
- }, size: "xs" }), /* @__PURE__ */ React__default.createElement(
535
- Button,
536
- {
537
- variant: "solid",
538
- bg: "transparent",
539
- onPress: () => {
540
- setFiles([]);
541
- setImage("");
542
- setImages([]);
1087
+ }, [navigation, channelId, role]);
1088
+ useCallback(() => {
1089
+ if (!images.length)
1090
+ return null;
1091
+ return /* @__PURE__ */ React__default.createElement(Box, { style: {
1092
+ position: "relative",
1093
+ height: 70,
1094
+ backgroundColor: "transparent",
1095
+ justifyContent: "center"
1096
+ } }, /* @__PURE__ */ React__default.createElement(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: {
1097
+ flexDirection: "row",
1098
+ paddingLeft: 15,
1099
+ paddingRight: 5
1100
+ }, contentContainerStyle: {
1101
+ alignItems: "center",
1102
+ height: "100%"
1103
+ } }, images.map((img, index) => /* @__PURE__ */ React__default.createElement(View, { key: `image-preview-${index}`, style: {
1104
+ width: 40,
1105
+ height: 40,
1106
+ marginRight: 15,
1107
+ borderRadius: 4,
1108
+ backgroundColor: colors.gray[200],
1109
+ overflow: "hidden",
1110
+ borderWidth: 1,
1111
+ borderColor: "#e0e0e0",
1112
+ position: "relative",
1113
+ zIndex: 10
1114
+ } }, /* @__PURE__ */ React__default.createElement(Image, { source: {
1115
+ uri: img.uri || img.url
1116
+ }, style: {
1117
+ width: "100%",
1118
+ height: "100%"
1119
+ }, alt: `selected image ${index + 1}` }), /* @__PURE__ */ React__default.createElement(TouchableOpacity, { onPress: () => {
1120
+ const newImages = [...images];
1121
+ newImages.splice(index, 1);
1122
+ setImages(newImages);
1123
+ if (newImages.length === 0) {
1124
+ setSelectedImage("");
1125
+ if (textInputRef.current && typeof textInputRef.current.focus === "function") {
1126
+ textInputRef.current.focus();
543
1127
  }
544
- },
545
- /* @__PURE__ */ React__default.createElement(ButtonText, { color: "$black" }, "Cancel")
546
- )) : null);
547
- };
1128
+ }
1129
+ }, style: {
1130
+ position: "absolute",
1131
+ top: -1,
1132
+ right: -1,
1133
+ backgroundColor: "rgba(0,0,0,0.6)",
1134
+ borderRadius: 12,
1135
+ width: 20,
1136
+ height: 20,
1137
+ alignItems: "center",
1138
+ justifyContent: "center",
1139
+ zIndex: 9999
1140
+ } }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "close", size: 16, color: "white" }))))));
1141
+ }, [images]);
548
1142
  const setImageViewerObject = (obj, v) => {
549
1143
  setImageObject(obj);
550
1144
  setImageViewer(v);
551
1145
  };
552
1146
  const modalContent = React__default.useMemo(() => {
553
- if (!imageObject)
554
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null);
1147
+ if (!imageObject || !imageObject.image)
1148
+ return null;
555
1149
  const {
556
1150
  image,
557
1151
  _id
558
1152
  } = imageObject;
559
- return /* @__PURE__ */ React__default.createElement(
560
- CachedImage,
561
- {
562
- style: {
563
- width: "100%",
564
- height: "100%"
565
- },
566
- resizeMode: "cover",
567
- cacheKey: `${_id}-slack-bubble-imageKey`,
568
- source: {
569
- uri: image,
570
- expiresIn: 86400
571
- },
572
- alt: "image"
573
- }
574
- );
1153
+ return /* @__PURE__ */ React__default.createElement(CachedImage, { style: {
1154
+ width: "100%",
1155
+ height: "100%"
1156
+ }, resizeMode: "cover", cacheKey: `${_id}-modal-imageKey`, source: {
1157
+ uri: image,
1158
+ expiresIn: 86400
1159
+ }, alt: "image" });
575
1160
  }, [imageObject]);
576
1161
  const renderMessage = useCallback((props) => {
577
1162
  return /* @__PURE__ */ React__default.createElement(Message, __spreadProps(__spreadValues({}, props), { isShowImageViewer, setImageViewer: setImageViewerObject }));
@@ -581,92 +1166,184 @@ const ConversationViewComponent = (_a) => {
581
1166
  nativeEvent
582
1167
  }) => {
583
1168
  onScroll = true;
584
- console.log("scroll top");
585
- if (!loadingOldMessages && isCloseToTop(nativeEvent) && totalCount > (channelMessages == null ? void 0 : channelMessages.length)) {
586
- await onFetchOld();
1169
+ if (isCloseToTop(nativeEvent)) {
1170
+ onFetchOld();
587
1171
  }
588
1172
  };
589
1173
  const onEndReached = () => {
590
- console.log("on end reached");
591
1174
  if (!onScroll)
592
1175
  return;
593
1176
  onScroll = false;
594
1177
  };
595
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, loadEarlierMsg && /* @__PURE__ */ React__default.createElement(Spinner, { color: "$blue500" }), /* @__PURE__ */ React__default.createElement(
596
- GiftedChat,
1178
+ const renderLoadEarlier = useCallback(() => {
1179
+ return loadingOldMessages ? /* @__PURE__ */ React__default.createElement(View, { style: {
1180
+ padding: 10,
1181
+ backgroundColor: "rgba(255,255,255,0.8)",
1182
+ borderRadius: 10,
1183
+ marginTop: 10
1184
+ } }, /* @__PURE__ */ React__default.createElement(Spinner, { size: "small", color: "#3b82f6" })) : null;
1185
+ }, [loadingOldMessages]);
1186
+ const [inputToolbarHeight, setInputToolbarHeight] = useState(30);
1187
+ useCallback((props) => /* @__PURE__ */ React__default.createElement(View, { style: {
1188
+ backgroundColor: "#fff",
1189
+ paddingBottom: 4,
1190
+ paddingTop: 4
1191
+ } }, /* @__PURE__ */ React__default.createElement(View, { style: {
1192
+ flexDirection: "row",
1193
+ alignItems: "center",
1194
+ minHeight: 44,
1195
+ maxHeight: 56,
1196
+ backgroundColor: "#fff",
1197
+ borderRadius: 22,
1198
+ marginHorizontal: 8,
1199
+ paddingHorizontal: 8,
1200
+ borderTopWidth: 1,
1201
+ borderTopColor: "#e0e0e0"
1202
+ } }, /* @__PURE__ */ React__default.createElement(TouchableOpacity, { onPress: onSelectImages, style: {
1203
+ width: 32,
1204
+ height: 32,
1205
+ borderRadius: 16,
1206
+ backgroundColor: "#fff",
1207
+ alignItems: "center",
1208
+ justifyContent: "center",
1209
+ marginRight: 8
1210
+ } }, /* @__PURE__ */ React__default.createElement(MaterialIcons, { name: "add", size: 24, color: "#888" })), /* @__PURE__ */ React__default.createElement(TextInput, { ref: textInputRef, style: {
1211
+ flex: 1,
1212
+ maxHeight: 44,
1213
+ backgroundColor: "transparent",
1214
+ color: "#444",
1215
+ paddingHorizontal: 8,
1216
+ paddingVertical: 0,
1217
+ alignSelf: "center",
1218
+ textAlignVertical: "center"
1219
+ }, placeholder: "Jot something down", placeholderTextColor: colors.gray[400], multiline: true, value: messageText, onChangeText: setMessageText }), /* @__PURE__ */ React__default.createElement(
1220
+ TouchableOpacity,
1221
+ {
1222
+ onPress: () => handleSend([{
1223
+ text: messageText
1224
+ }]),
1225
+ disabled: false,
1226
+ style: {
1227
+ marginLeft: 8,
1228
+ opacity: !messageText.trim() && images.length === 0 ? 0.5 : 1
1229
+ }
1230
+ },
1231
+ /* @__PURE__ */ React__default.createElement(
1232
+ MaterialCommunityIcons,
1233
+ {
1234
+ name: "send-circle",
1235
+ size: 32,
1236
+ color: !messageText.trim() && images.length === 0 ? colors.gray[400] : colors.blue[500]
1237
+ }
1238
+ )
1239
+ )), images && images.length > 0 && /* @__PURE__ */ React__default.createElement(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: {
1240
+ marginTop: 4,
1241
+ marginLeft: 8
1242
+ } }, images.map((img, index) => /* @__PURE__ */ React__default.createElement(View, { key: `image-preview-${index}`, style: {
1243
+ width: 48,
1244
+ height: 48,
1245
+ marginRight: 8,
1246
+ borderRadius: 6,
1247
+ overflow: "hidden",
1248
+ position: "relative",
1249
+ backgroundColor: colors.gray[200]
1250
+ } }, /* @__PURE__ */ React__default.createElement(Image, { source: {
1251
+ uri: img.uri || img.url
1252
+ }, style: {
1253
+ width: "100%",
1254
+ height: "100%"
1255
+ }, alt: `selected image ${index + 1}` }), /* @__PURE__ */ React__default.createElement(TouchableOpacity, { onPress: () => {
1256
+ handleRemoveImage(index);
1257
+ }, style: {
1258
+ position: "absolute",
1259
+ top: 2,
1260
+ right: 2,
1261
+ backgroundColor: "rgba(0,0,0,0.6)",
1262
+ borderRadius: 10,
1263
+ width: 20,
1264
+ height: 20,
1265
+ alignItems: "center",
1266
+ justifyContent: "center"
1267
+ } }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "close", size: 14, color: "white" })))))), [onSelectImages, messageText, images, isUploadingImage, loading, handleSend, handleRemoveImage]);
1268
+ const imageViewerModal = useMemo(() => /* @__PURE__ */ React__default.createElement(ImageViewerModal, { isVisible: isShowImageViewer, setVisible: setImageViewer, modalContent }), [isShowImageViewer, modalContent]);
1269
+ const renderChatFooter = useCallback(() => {
1270
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, imageViewerModal, /* @__PURE__ */ React__default.createElement(SubscriptionHandler, { subscribeToMore: subscribe, document: CHAT_MESSAGE_ADDED, variables: {
1271
+ channelId: channelId == null ? void 0 : channelId.toString()
1272
+ }, updateQuery: void 0 }));
1273
+ }, [imageViewerModal, subscribe]);
1274
+ const listViewProps = useMemo(() => ({
1275
+ onEndReached,
1276
+ onEndReachedThreshold: 0.5,
1277
+ onMomentumScrollBegin,
1278
+ removeClippedSubviews: true,
1279
+ initialNumToRender: 10,
1280
+ maxToRenderPerBatch: 7,
1281
+ windowSize: 7,
1282
+ updateCellsBatchingPeriod: 50,
1283
+ keyExtractor: (item) => item._id
1284
+ }), [onEndReached, onMomentumScrollBegin]);
1285
+ useCallback((message, prefix = "Message") => {
1286
+ var _a3, _b3, _c2, _d2, _e, _f, _g, _h, _i;
1287
+ if (__DEV__) {
1288
+ console.log(`${prefix} ID: ${message == null ? void 0 : message.id}, Has files object: ${!!(message == null ? void 0 : message.files)}, Files typename: ${(_a3 = message == null ? void 0 : message.files) == null ? void 0 : _a3.__typename}, Files data exists: ${!!((_b3 = message == null ? void 0 : message.files) == null ? void 0 : _b3.data)}, Files count: ${((_d2 = (_c2 = message == null ? void 0 : message.files) == null ? void 0 : _c2.data) == null ? void 0 : _d2.length) || 0}`);
1289
+ if (((_e = message == null ? void 0 : message.files) == null ? void 0 : _e.data) && ((_g = (_f = message == null ? void 0 : message.files) == null ? void 0 : _f.data) == null ? void 0 : _g.length) > 0) {
1290
+ const file = (_h = message == null ? void 0 : message.files) == null ? void 0 : _h.data[0];
1291
+ console.log(`File[0] ID: ${file == null ? void 0 : file.id}, URL: ${(_i = file == null ? void 0 : file.url) == null ? void 0 : _i.substring(0, 30)}..., Name: ${file == null ? void 0 : file.name}, Type: ${file == null ? void 0 : file.mimeType}`);
1292
+ }
1293
+ }
1294
+ }, []);
1295
+ return /* @__PURE__ */ React__default.createElement(KeyboardAvoidingView, { style: {
1296
+ flex: 1,
1297
+ justifyContent: "flex-end"
1298
+ }, behavior: Platform.OS === "ios" ? "padding" : "height", keyboardVerticalOffset: Platform.OS === "ios" ? 64 : 0 }, /* @__PURE__ */ React__default.createElement(View, { style: {
1299
+ flex: 1,
1300
+ backgroundColor: "white",
1301
+ position: "relative",
1302
+ marginBottom: images.length > 0 ? 5 : bottomMargin
1303
+ } }, 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(
1304
+ GiftedChatInboxComponent,
597
1305
  {
598
1306
  ref: messageRootListRef,
599
- wrapInSafeArea: false,
600
- renderLoading: () => /* @__PURE__ */ React__default.createElement(Spinner, { color: "$blue500" }),
1307
+ errorMessage,
1308
+ images,
1309
+ onSelectImages,
1310
+ onRemoveImage: handleRemoveImage,
1311
+ selectedImage,
1312
+ setSelectedImage,
1313
+ isUploadingImage,
1314
+ loading,
1315
+ wrapInSafeArea: true,
1316
+ renderLoading: () => /* @__PURE__ */ React__default.createElement(Spinner, { color: "#3b82f6" }),
601
1317
  messages: messageList,
602
- listViewProps: {
603
- onEndReached,
604
- onEndReachedThreshold: 0.5,
605
- onMomentumScrollBegin
606
- },
607
- onSend: (messages) => {
608
- var _a3, _b2, _c, _d, _e, _f;
609
- return (rest == null ? void 0 : rest.isCreateNewChannel) && !channelId ? ((_a3 = rest == null ? void 0 : rest.newChannelData) == null ? void 0 : _a3.type) === ((_b2 = RoomType) == null ? void 0 : _b2.Direct) ? createDirectChannel((_d = (_c = messages[0]) == null ? void 0 : _c.text) != null ? _d : " ") : null : channelId && handleSend((_f = (_e = messages[0]) == null ? void 0 : _e.text) != null ? _f : " ");
1318
+ renderAvatar: null,
1319
+ showUserAvatar: false,
1320
+ listViewProps: __spreadProps(__spreadValues({}, listViewProps), {
1321
+ contentContainerStyle: {
1322
+ paddingBottom: inputToolbarHeight
1323
+ }
1324
+ }),
1325
+ onSend: handleSend,
1326
+ text: messageText || " ",
1327
+ onInputTextChanged: (text) => {
1328
+ setMessageText(text);
610
1329
  },
611
- text: msg ? msg : " ",
612
- onInputTextChanged: (text) => setMsg(text),
613
- renderFooter: () => loading ? /* @__PURE__ */ React__default.createElement(Spinner, { color: "$blue500" }) : imageLoading ? /* @__PURE__ */ React__default.createElement(Spinner, { color: "$blue500" }) : "",
1330
+ renderFooter: () => isUploadingImage ? /* @__PURE__ */ React__default.createElement(Spinner, { color: "#3b82f6" }) : null,
614
1331
  scrollToBottom: true,
615
1332
  user: {
616
1333
  _id: (auth == null ? void 0 : auth.id) || ""
617
1334
  },
618
- isTyping: true,
619
- alwaysShowSend: loading ? false : true,
620
1335
  renderSend,
621
1336
  renderMessageText,
622
- minInputToolbarHeight: 50,
623
- renderActions: channelId && renderActions,
624
- renderAccessory,
625
1337
  renderMessage,
626
- renderChatFooter: () => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(ImageViewerModal, { isVisible: isShowImageViewer, setVisible: setImageViewer, modalContent }), /* @__PURE__ */ React__default.createElement(SubscriptionHandler, { channelId: channelId == null ? void 0 : channelId.toString(), subscribeToNewMessages: () => subscribeToMore({
627
- document: OnChatMessageAddedDocument,
628
- variables: {
629
- channelId: channelId == null ? void 0 : channelId.toString()
630
- },
631
- updateQuery: (prev, {
632
- subscriptionData
633
- }) => {
634
- var _a3, _b2, _c, _d, _e;
635
- if (!subscriptionData.data)
636
- return prev;
637
- setSkip(0);
638
- const newMessage = (_a3 = subscriptionData == null ? void 0 : subscriptionData.data) == null ? void 0 : _a3.chatMessageAdded;
639
- ((_b2 = prev == null ? void 0 : prev.messages) == null ? void 0 : _b2.data) ? [...prev.messages.data, newMessage] : [];
640
- const totalMsgCount = ((_c = prev == null ? void 0 : prev.messages) == null ? void 0 : _c.totalCount) + 1;
641
- setChannelMessages((oldMessages) => uniqBy([...oldMessages, newMessage], ({
642
- id
643
- }) => id));
644
- setTotalCount(totalMsgCount);
645
- const merged = __spreadProps(__spreadValues({}, prev), {
646
- messages: __spreadProps(__spreadValues({}, prev == null ? void 0 : prev.messages), {
647
- data: [...(_e = (_d = prev == null ? void 0 : prev.messages) == null ? void 0 : _d.data) != null ? _e : [], newMessage],
648
- totalCount: totalMsgCount
649
- })
650
- });
651
- return merged;
652
- }
653
- }) })),
654
- lightboxProps: {
655
- underlayColor: "transparent",
656
- springConfig: {
657
- tension: 9e4,
658
- friction: 9e4
659
- },
660
- disabled: true
661
- }
1338
+ renderChatFooter,
1339
+ renderLoadEarlier,
1340
+ loadEarlier: totalCount > channelMessages.length,
1341
+ isLoadingEarlier: loadingOldMessages,
1342
+ placeholder: "Jot something down",
1343
+ infiniteScroll: true
662
1344
  }
663
- ));
664
- };
665
- const SubscriptionHandler = ({
666
- subscribeToNewMessages,
667
- channelId
668
- }) => {
669
- useEffect(() => subscribeToNewMessages(), [channelId]);
670
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null);
1345
+ )));
671
1346
  };
672
- const ConversationView = React__default.memo(ConversationViewComponent);export{ConversationView};//# sourceMappingURL=ConversationView.js.map
1347
+ const ConversationView = React__default.memo(ConversationViewComponent, (prevProps, nextProps) => {
1348
+ return prevProps.channelId === nextProps.channelId && prevProps.role === nextProps.role && prevProps.isShowThreadMessage === nextProps.isShowThreadMessage;
1349
+ });export{ConversationView};//# sourceMappingURL=ConversationView.js.map