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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/compute.js +2 -3
  3. package/lib/index.js.map +1 -1
  4. package/lib/queries/inboxQueries.js +77 -0
  5. package/lib/queries/inboxQueries.js.map +1 -0
  6. package/lib/routes.json +2 -3
  7. package/lib/screens/inbox/DialogThreadMessages.js +3 -7
  8. package/lib/screens/inbox/DialogThreadMessages.js.map +1 -1
  9. package/lib/screens/inbox/DialogThreads.js +3 -7
  10. package/lib/screens/inbox/DialogThreads.js.map +1 -1
  11. package/lib/screens/inbox/components/DialogsListItem.js +47 -46
  12. package/lib/screens/inbox/components/DialogsListItem.js.map +1 -1
  13. package/lib/screens/inbox/components/GiftedChatInboxComponent.js +313 -0
  14. package/lib/screens/inbox/components/GiftedChatInboxComponent.js.map +1 -0
  15. package/lib/screens/inbox/components/ServiceDialogsListItem.js +72 -57
  16. package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +1 -1
  17. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +115 -14
  18. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  19. package/lib/screens/inbox/components/SubscriptionHandler.js +24 -0
  20. package/lib/screens/inbox/components/SubscriptionHandler.js.map +1 -0
  21. package/lib/screens/inbox/containers/ConversationView.js +640 -493
  22. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  23. package/lib/screens/inbox/containers/Dialogs.js +100 -181
  24. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  25. package/lib/screens/inbox/containers/ThreadConversationView.js +659 -245
  26. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  27. package/lib/screens/inbox/containers/ThreadsView.js +3 -3
  28. package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
  29. package/lib/screens/inbox/hooks/useInboxMessages.js +31 -0
  30. package/lib/screens/inbox/hooks/useInboxMessages.js.map +1 -0
  31. package/package.json +4 -4
  32. package/src/index.ts +2 -0
  33. package/src/queries/inboxQueries.ts +298 -0
  34. package/src/queries/index.d.ts +2 -0
  35. package/src/queries/index.ts +1 -0
  36. package/src/screens/inbox/DialogThreadMessages.tsx +3 -11
  37. package/src/screens/inbox/DialogThreads.tsx +3 -7
  38. package/src/screens/inbox/components/Actionsheet.tsx +30 -0
  39. package/src/screens/inbox/components/DialogsListItem.tsx +89 -148
  40. package/src/screens/inbox/components/ExpandableInput.tsx +460 -0
  41. package/src/screens/inbox/components/ExpandableInputActionSheet.tsx +518 -0
  42. package/src/screens/inbox/components/GiftedChatInboxComponent.tsx +411 -0
  43. package/src/screens/inbox/components/ServiceDialogsListItem.tsx +202 -221
  44. package/src/screens/inbox/components/SlackInput.tsx +23 -0
  45. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +216 -30
  46. package/src/screens/inbox/components/SubscriptionHandler.tsx +41 -0
  47. package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +6 -7
  48. package/src/screens/inbox/containers/ConversationView.tsx +1109 -669
  49. package/src/screens/inbox/containers/Dialogs.tsx +198 -342
  50. package/src/screens/inbox/containers/SupportServiceDialogs.tsx +2 -2
  51. package/src/screens/inbox/containers/ThreadConversationView.tsx +1141 -402
  52. package/src/screens/inbox/containers/ThreadsView.tsx +5 -5
  53. package/src/screens/inbox/hooks/useInboxMessages.ts +34 -0
  54. package/src/screens/inbox/machines/threadsMachine.ts +2 -2
@@ -16,13 +16,13 @@ import { format, isToday, isYesterday } from 'date-fns';
16
16
  import { useFocusEffect } from '@react-navigation/native';
17
17
  import { IChannel, SortEnum, IUserAccount } from 'common';
18
18
  import {
19
- useMessagesQuery,
20
- useOnChatMessageAddedSubscription,
21
- OnChatMessageAddedDocument as CHAT_MESSAGE_ADDED,
22
- useUserAccountQuery,
23
- } from 'common/graphql';
19
+ CHAT_MESSAGE_ADDED,
20
+ useChatMessageAddedSubscription,
21
+ useMessagesQuery as useMessagesQueryFromInbox,
22
+ } from '../../../queries/inboxQueries';
24
23
  import { startCase } from 'lodash-es';
25
24
  import colors from 'tailwindcss/colors';
25
+ import { SubscriptionHandler } from './SubscriptionHandler';
26
26
 
27
27
  const createdAtText = (value: string) => {
28
28
  if (!value) return '';
@@ -43,10 +43,11 @@ export interface IDialogListItemProps {
43
43
  channel?: any;
44
44
  onOpen: (id: any, title: any) => void;
45
45
  forceRefresh?: boolean;
46
+ visible?: boolean;
46
47
  }
47
48
 
48
49
  // LastMessage component definition
49
- const LastMessageComponent = ({ subscribeToNewMessages, title, lastMessage, channelId }) => {
50
+ const LastMessageComponent = ({ subscribeToNewMessages, title, lastMessage, channelId, subscribeToMore }) => {
50
51
  // Subscribe to new messages when component mounts
51
52
  React.useEffect(() => {
52
53
  // Subscribe and store the unsubscribe function
@@ -97,20 +98,28 @@ const LastMessageComponent = ({ subscribeToNewMessages, title, lastMessage, chan
97
98
  : '';
98
99
 
99
100
  return (
100
- <HStack space={'sm'} className="flex-1 justify-between">
101
- <Box className="flex-[0.8]">
102
- <Text color={colors.gray[600]} className="text-base text-wrap flex-wrap font-semibold">
103
- {channelTitle}
104
- </Text>
105
- <Text color={colors.gray[600]} numberOfLines={1}>
106
- {displayMessage}
107
- </Text>
108
- </Box>
109
-
110
- <Box className="flex-[0.2]">
111
- <Text color={colors.gray[500]}>{displayDate}</Text>
112
- </Box>
113
- </HStack>
101
+ <>
102
+ <SubscriptionHandler
103
+ subscribeToMore={subscribeToMore}
104
+ document={CHAT_MESSAGE_ADDED}
105
+ variables={{ channelId: channelId?.toString() }}
106
+ updateQuery={undefined} // Provide custom updateQuery if needed
107
+ />
108
+ <HStack space={'sm'} className="flex-1 justify-between">
109
+ <Box className="flex-[0.8]">
110
+ <Text color={colors.gray[600]} className="text-base text-wrap flex-wrap font-semibold">
111
+ {channelTitle}
112
+ </Text>
113
+ <Text color={colors.gray[600]} numberOfLines={1}>
114
+ {displayMessage}
115
+ </Text>
116
+ </Box>
117
+
118
+ <Box className="flex-[0.2]">
119
+ <Text color={colors.gray[500]}>{displayDate}</Text>
120
+ </Box>
121
+ </HStack>
122
+ </>
114
123
  );
115
124
  };
116
125
 
@@ -126,6 +135,7 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
126
135
  channel,
127
136
  onOpen,
128
137
  forceRefresh,
138
+ visible = true,
129
139
  }) {
130
140
  // Create a ref to track if component is mounted
131
141
  const isMountedRef = useRef(true);
@@ -139,55 +149,51 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
139
149
  const [messages, setMessages] = useState([]);
140
150
  const [lastMessage, setLastMessage] = useState(null);
141
151
 
142
- // Query hooks for fetching messages
152
+ // Only run queries/subscriptions if visible
153
+ const shouldQuery = !!channel?.id && visible;
154
+
155
+ // Query hooks for fetching messages (minimal fields if possible)
143
156
  const {
144
157
  data: messagesQuery,
145
158
  loading: messageLoading,
146
159
  refetch: refetchMessages,
147
160
  subscribeToMore,
148
- } = useMessagesQuery({
161
+ } = useMessagesQueryFromInbox({
149
162
  variables: {
150
163
  channelId: channel?.id?.toString(),
151
164
  parentId: parentId,
152
165
  limit: 10,
153
166
  },
154
- fetchPolicy: 'cache-and-network', // Use cache first, then network
155
- refetchWritePolicy: 'overwrite', // Ensure refetches overwrite existing data
156
- nextFetchPolicy: 'network-only', // Force subsequent fetches to use network
167
+ skip: !shouldQuery, // Only run if visible
168
+ fetchPolicy: 'cache-and-network',
169
+ refetchWritePolicy: 'overwrite',
170
+ nextFetchPolicy: 'network-only',
157
171
  onCompleted: (data) => {
158
- console.log(
159
- `Completed message query for channel ${channel?.id}:`,
160
- data?.messages?.data?.length ? 'Has messages' : 'No messages',
161
- );
162
-
172
+ if (!shouldQuery) return;
163
173
  if (data?.messages?.data) {
164
174
  setMessages(data.messages.data);
165
-
166
- // Find the newest message
167
175
  const sortedMessages = [...data.messages.data].sort(
168
176
  (a, b) =>
169
177
  new Date(b?.updatedAt || b?.createdAt).getTime() -
170
178
  new Date(a?.updatedAt || a?.createdAt).getTime(),
171
179
  );
172
-
173
180
  if (sortedMessages.length > 0) {
174
181
  setLastMessage(sortedMessages[0]);
175
182
  }
176
183
  }
177
184
  },
178
185
  onError: (error) => {
186
+ if (!shouldQuery) return;
179
187
  console.error(`Error fetching messages for channel ${channel?.id}:`, error);
180
188
  },
181
189
  });
182
190
 
183
- const {
184
- data: newMessage,
185
- loading: newMsgLoading,
186
- error: newMsgError,
187
- }: any = useOnChatMessageAddedSubscription({
191
+ // Subscription for new messages (only if visible)
192
+ const { data: newMessage } = useChatMessageAddedSubscription({
188
193
  variables: {
189
194
  channelId: channel?.id?.toString(),
190
195
  },
196
+ skip: !shouldQuery,
191
197
  });
192
198
 
193
199
  // Set mounted state on mount/unmount
@@ -200,44 +206,22 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
200
206
 
201
207
  // Function to force refresh the component state
202
208
  const refreshDialogState = useCallback(() => {
203
- if (channel?.id && isMountedRef.current) {
204
- console.log('Forcing dialog state refresh for channel:', channel?.id);
205
- // First ensure we're in a loading state to trigger UI updates
209
+ if (shouldQuery && isMountedRef.current) {
206
210
  setLoading(true);
207
-
208
- // Set up the options for the query to force network fetch
209
211
  const options = {
210
212
  channelId: channel?.id?.toString(),
211
213
  parentId: parentId,
212
214
  limit: 10,
213
215
  };
214
-
215
- // Refetch messages from server
216
216
  refetchMessages(options)
217
217
  .then((result) => {
218
- // Update the state with fresh data
219
218
  if (result.data?.messages?.data && isMountedRef.current) {
220
- console.log(
221
- `Refreshed ${result.data.messages.data.length} messages for channel ${channel?.id}`,
222
- );
223
-
224
- // Get the most recent message for debug comparison
225
219
  const sortedMessages = [...result.data.messages.data].sort(
226
220
  (a, b) =>
227
221
  new Date(b?.updatedAt || b?.createdAt).getTime() -
228
222
  new Date(a?.updatedAt || a?.createdAt).getTime(),
229
223
  );
230
-
231
224
  const latestMessage = sortedMessages.length > 0 ? sortedMessages[0] : null;
232
-
233
- if (latestMessage) {
234
- console.log('Latest message after refresh:', {
235
- id: latestMessage.id,
236
- message: latestMessage.message?.substring(0, 20) + '...',
237
- date: latestMessage.createdAt || latestMessage.updatedAt,
238
- });
239
- }
240
-
241
225
  setMessages(result.data.messages.data);
242
226
  setLastMessage(latestMessage);
243
227
  }
@@ -248,7 +232,7 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
248
232
  setLoading(false);
249
233
  });
250
234
  }
251
- }, [channel?.id, refetchMessages, isMountedRef, parentId]);
235
+ }, [shouldQuery, channel?.id, refetchMessages, parentId]);
252
236
 
253
237
  // Track if this is the first time the component renders
254
238
  const firstRenderRef = useRef(true);
@@ -337,31 +321,25 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
337
321
  }, [channel?.id, refetchMessages, messages, isMountedRef, parentId]),
338
322
  );
339
323
 
340
- // Force a refresh on initial mount to ensure we have fresh data
324
+ // Only run effects if visible
341
325
  useEffect(() => {
326
+ if (!shouldQuery) return;
342
327
  if (channel?.id && isMountedRef.current) {
343
328
  const timer = setTimeout(() => {
344
329
  if (isMountedRef.current) {
345
- console.log('Initial data refresh for channel:', channel.id);
346
330
  refreshDialogState();
347
331
  }
348
332
  }, 100);
349
-
350
333
  return () => {
351
334
  clearTimeout(timer);
352
335
  };
353
336
  }
354
- }, [channel?.id, refreshDialogState, isMountedRef]);
337
+ }, [shouldQuery, channel?.id, refreshDialogState]);
355
338
 
356
- // Use forceRefresh prop to trigger immediate refresh
357
339
  useEffect(() => {
358
- if (forceRefresh && channel?.id && isMountedRef.current) {
359
- console.log(`Force refreshing messages for channel ${channel?.id} due to forceRefresh prop`);
360
-
361
- // Set a very slight delay to ensure component is fully mounted
340
+ if (forceRefresh && shouldQuery && channel?.id && isMountedRef.current) {
362
341
  const timer = setTimeout(() => {
363
342
  if (isMountedRef.current && refetchMessages) {
364
- // Force a full network-only fetch
365
343
  refetchMessages({
366
344
  channelId: channel?.id?.toString(),
367
345
  parentId: parentId,
@@ -369,20 +347,12 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
369
347
  })
370
348
  .then((result) => {
371
349
  if (result?.data?.messages?.data && isMountedRef.current) {
372
- console.log(
373
- `Force refresh completed for channel ${channel?.id} with ${result.data.messages.data.length} messages`,
374
- );
375
-
376
- // Get the most recent message
377
350
  const sortedMessages = [...result.data.messages.data].sort(
378
351
  (a, b) =>
379
352
  new Date(b?.updatedAt || b?.createdAt).getTime() -
380
353
  new Date(a?.updatedAt || a?.createdAt).getTime(),
381
354
  );
382
-
383
355
  const latestMessage = sortedMessages.length > 0 ? sortedMessages[0] : null;
384
-
385
- // Update state with fresh data
386
356
  setMessages(result.data.messages.data);
387
357
  setLastMessage(latestMessage);
388
358
  }
@@ -392,10 +362,9 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
392
362
  });
393
363
  }
394
364
  }, 50);
395
-
396
365
  return () => clearTimeout(timer);
397
366
  }
398
- }, [channel?.id, forceRefresh, isMountedRef, refetchMessages, parentId]);
367
+ }, [shouldQuery, channel?.id, forceRefresh, refetchMessages, parentId]);
399
368
 
400
369
  const channelMembers = useMemo(
401
370
  () =>
@@ -413,10 +382,9 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
413
382
  ?.map((u: any) => u?.givenName + ' ' + (u?.familyName ?? ''))
414
383
  ?.filter((mu: any) => mu)
415
384
  ?.join(', ') ?? '';
416
-
417
385
  setTitle(titleString);
418
386
  }
419
- }, [channelMembers, isMountedRef]);
387
+ }, [channelMembers]);
420
388
 
421
389
  // Compute title with proper truncation
422
390
  const displayTitle = useMemo(() => {
@@ -435,41 +403,27 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
435
403
 
436
404
  // Handle new messages from subscription
437
405
  useEffect(() => {
406
+ if (!shouldQuery) return;
438
407
  if (newMessage?.chatMessageAdded && channel?.id) {
439
408
  const incomingMessage = newMessage.chatMessageAdded;
440
-
441
- // Check if we already have this message
442
409
  if (messages.some((msg) => msg.id === incomingMessage.id)) {
443
- console.log('Message already in local state, skipping update:', incomingMessage.id);
444
410
  return;
445
411
  }
446
-
447
- console.log('New message received from subscription:', {
448
- channelId: channel.id,
449
- messageId: incomingMessage.id,
450
- message: incomingMessage.message?.substring(0, 20) + '...',
451
- timestamp: incomingMessage.createdAt,
452
- });
453
-
454
- // Update messages and last message state
455
412
  setMessages((prevMessages) => [...prevMessages, incomingMessage]);
456
413
  setLastMessage(incomingMessage);
457
414
  }
458
- }, [newMessage, channel?.id, messages]);
415
+ }, [shouldQuery, newMessage, channel?.id, messages]);
459
416
 
460
417
  // Create listener for channel property updates
461
418
  useEffect(() => {
462
- // Check if channel has a lastMessage property (set by parent Dialogs component)
419
+ if (!shouldQuery) return;
463
420
  if (channel?.lastMessage && channel.lastMessage.id) {
464
- console.log('Channel has lastMessage property:', channel.lastMessage.id);
465
-
466
- // Check if we already have this message
467
421
  if (!messages.some((msg) => msg.id === channel.lastMessage.id)) {
468
422
  setMessages((prevMessages) => [...prevMessages, channel.lastMessage]);
469
423
  setLastMessage(channel.lastMessage);
470
424
  }
471
425
  }
472
- }, [channel?.lastMessage?.id, messages]);
426
+ }, [shouldQuery, channel?.lastMessage?.id, messages]);
473
427
 
474
428
  return (
475
429
  <Pressable
@@ -491,7 +445,6 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
491
445
  }] z-[${i == 1 ? 5 : 1}]`}
492
446
  >
493
447
  <AvatarFallbackText>{startCase(ch?.username?.charAt(0))}</AvatarFallbackText>
494
-
495
448
  {channelMembers?.length > 1 && (
496
449
  <AvatarBadge
497
450
  style={{
@@ -530,52 +483,40 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
530
483
  lastMessage={lastMessage}
531
484
  channelId={channel?.id}
532
485
  subscribeToNewMessages={() =>
533
- subscribeToMore({
534
- document: CHAT_MESSAGE_ADDED,
535
- variables: {
536
- channelId: channel.id?.toString(),
537
- },
538
- updateQuery: (prev, { subscriptionData }: any) => {
539
- if (!subscriptionData.data) return prev;
540
- const newMessage: any = subscriptionData?.data?.chatMessageAdded;
541
-
542
- // Add debug info for the new message
543
- // console.log('New message added (subscription):', {
544
- // channelId: channel.id,
545
- // messageId: newMessage.id,
546
- // message: newMessage.message?.substring(0, 20) + '...',
547
- // hasFiles: newMessage?.files?.data?.length > 0,
548
- // filesCount: newMessage?.files?.data?.length || 0,
549
- // timestamp: newMessage.createdAt || newMessage.updatedAt,
550
- // });
551
-
552
- // Direct optimistic update through local state
553
- if (isMountedRef.current) {
554
- // Update messages array with the new message if it doesn't exist
555
- if (!messages.some((msg) => msg.id === newMessage.id)) {
556
- setMessages((prevMessages) => [...prevMessages, newMessage]);
557
- setLastMessage(newMessage);
558
- }
559
- }
560
-
561
- // Update the Apollo cache
562
- const existingMessages: any = prev?.messages;
563
- const previousData = existingMessages?.data
564
- ? [...existingMessages.data, newMessage]
565
- : [];
566
- const totalMsgCount = existingMessages?.totalCount + 1;
567
- const merged = {
568
- ...prev,
569
- messages: {
570
- ...existingMessages,
571
- data: previousData,
572
- totalCount: totalMsgCount,
573
- },
574
- };
575
- return merged;
576
- },
577
- })
486
+ shouldQuery
487
+ ? subscribeToMore({
488
+ document: CHAT_MESSAGE_ADDED,
489
+ variables: {
490
+ channelId: channel.id?.toString(),
491
+ },
492
+ updateQuery: (prev, { subscriptionData }: any) => {
493
+ if (!subscriptionData.data) return prev;
494
+ const newMessage: any = subscriptionData?.data?.chatMessageAdded;
495
+ if (isMountedRef.current) {
496
+ if (!messages.some((msg) => msg.id === newMessage.id)) {
497
+ setMessages((prevMessages) => [...prevMessages, newMessage]);
498
+ setLastMessage(newMessage);
499
+ }
500
+ }
501
+ const existingMessages: any = prev?.messages;
502
+ const previousData = existingMessages?.data
503
+ ? [...existingMessages.data, newMessage]
504
+ : [];
505
+ const totalMsgCount = existingMessages?.totalCount + 1;
506
+ const merged = {
507
+ ...prev,
508
+ messages: {
509
+ ...existingMessages,
510
+ data: previousData,
511
+ totalCount: totalMsgCount,
512
+ },
513
+ };
514
+ return merged;
515
+ },
516
+ })
517
+ : undefined
578
518
  }
519
+ subscribeToMore={subscribeToMore}
579
520
  />
580
521
  </Box>
581
522
  </HStack>