@messenger-box/platform-mobile 10.0.3-alpha.33 → 10.0.3-alpha.36

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.
@@ -360,12 +360,37 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
360
360
  const safeSend = useCallback(
361
361
  (event) => {
362
362
  try {
363
+ console.log('🛠️ Safe send event:', event.type);
363
364
  send(event);
365
+
366
+ // For important events like SET_CHANNEL_MESSAGES, verify they worked
367
+ if (event.type === ConversationActions.SET_CHANNEL_MESSAGES) {
368
+ // Add a verification step to ensure state was updated
369
+ setTimeout(() => {
370
+ // Don't log for every check to avoid console spam
371
+ if (state.context.channelMessages.length === 0 && event.data?.messages?.length > 0) {
372
+ console.warn('🛠️ SET_CHANNEL_MESSAGES did not update state - messages still empty');
373
+ }
374
+ }, 100);
375
+ }
364
376
  } catch (error) {
365
- console.error('Error sending event to state machine:', error, event);
377
+ console.error('🛠️ Error in safeSend:', error, 'Event type:', event.type);
378
+ // Try direct state update as fallback for critical events
379
+ if (event.type === ConversationActions.SET_CHANNEL_MESSAGES && event.data?.messages) {
380
+ console.log('🛠️ Attempting fallback for SET_CHANNEL_MESSAGES');
381
+ try {
382
+ // Direct update as fallback
383
+ send({
384
+ type: 'DIRECT_STATE_UPDATE',
385
+ data: event.data,
386
+ });
387
+ } catch (fallbackError) {
388
+ console.error('🛠️ Even fallback failed:', fallbackError);
389
+ }
390
+ }
366
391
  }
367
392
  },
368
- [send],
393
+ [send, state.context.channelMessages.length],
369
394
  );
370
395
 
371
396
  // Immediately set initial context if needed
@@ -460,13 +485,27 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
460
485
  );
461
486
  console.log('Message count from query:', queryData.messages.data.length);
462
487
  console.log('Total count from query:', queryData.messages.totalCount);
488
+
489
+ // DIRECT STATE UPDATE: Immediately update state to ensure messages are displayed
490
+ if (queryData.messages.data.length > 0) {
491
+ console.log('🔄 IMMEDIATE STATE UPDATE with messages:', queryData.messages.data.length);
492
+ safeSend({
493
+ type: ConversationActions.SET_CHANNEL_MESSAGES,
494
+ data: {
495
+ messages: queryData.messages.data,
496
+ totalCount: queryData.messages.totalCount,
497
+ },
498
+ });
499
+ }
463
500
  }
464
501
  },
465
502
  onError: (error) => {
466
503
  console.error('MESSAGE QUERY ERROR:', error);
504
+ // Report error to state machine
505
+ safeSend({ type: 'ERROR', data: { message: String(error) } });
467
506
  },
468
507
  });
469
-
508
+ // console.log('🔄 MESSAGE QUERY COMPLETED:', JSON.stringify(data));
470
509
  // Modify the fetchMessagesDirectly function to use safe access
471
510
  const fetchMessagesDirectly = useCallback(async () => {
472
511
  const channelId = safeGetContext().channelId;
@@ -848,14 +887,35 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
848
887
  if (messages && messages.length > 0) {
849
888
  console.log('📩 QUERY DATA - Setting channel messages, count:', messages.length);
850
889
 
851
- // First try dispatching the update through XState
852
- send({
853
- type: ConversationActions.SET_CHANNEL_MESSAGES,
854
- data: {
855
- messages: uniqBy([...messages, ...state.context.channelMessages], ({ id }) => id),
856
- totalCount: messageTotalCount,
857
- },
858
- });
890
+ // Use timeout to ensure this doesn't conflict with other state updates
891
+ setTimeout(() => {
892
+ // Directly update the state machine with new messages
893
+ safeSend({
894
+ type: ConversationActions.SET_CHANNEL_MESSAGES,
895
+ data: {
896
+ messages: uniqBy([...messages, ...state.context.channelMessages], ({ id }) => id),
897
+ totalCount: messageTotalCount,
898
+ },
899
+ });
900
+
901
+ // Verify the update was processed properly
902
+ setTimeout(() => {
903
+ const currentMessagesCount = state.context.channelMessages?.length || 0;
904
+ console.log('📩 STATE UPDATE VERIFICATION - Current message count:', currentMessagesCount);
905
+
906
+ if (currentMessagesCount === 0) {
907
+ console.warn('⚠️ STATE NOT UPDATED after message data received - triggering fallback');
908
+ // Direct fallback approach
909
+ safeSend({
910
+ type: ConversationActions.SET_CHANNEL_MESSAGES,
911
+ data: {
912
+ messages: messages,
913
+ totalCount: messageTotalCount,
914
+ },
915
+ });
916
+ }
917
+ }, 500);
918
+ }, 0);
859
919
 
860
920
  // Debug: Log the first message to verify data format
861
921
  if (messages[0]) {
@@ -873,16 +933,9 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
873
933
  }),
874
934
  );
875
935
  }
876
-
877
- // Check if the state machine actually updated (debug only)
878
- setTimeout(() => {
879
- if (state.context.channelMessages?.length === 0) {
880
- console.warn('⚠️ STATE NOT UPDATED after message data received - may need fallback');
881
- }
882
- }, 500);
883
936
  }
884
937
  }
885
- }, [data]);
938
+ }, [data, safeSend]);
886
939
 
887
940
  // Optimize onFetchOld by adding debounce logic
888
941
  const onFetchOld = useCallback(() => {
@@ -1561,45 +1614,62 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
1561
1614
  channelId: state?.context?.channelId?.toString(),
1562
1615
  },
1563
1616
  updateQuery: (prev, { subscriptionData }: any) => {
1564
- if (!subscriptionData?.data?.chatMessageAdded) return prev;
1565
-
1566
- const newMessage = subscriptionData.data.chatMessageAdded;
1567
- const currentMessages = prev?.messages?.data || [];
1568
-
1569
- // Check if message already exists to prevent duplicates
1570
- if (currentMessages.some((msg) => msg.id === newMessage.id)) {
1571
- return prev; // Skip update if message already exists
1572
- }
1573
-
1574
- // Use a ref to track the last processed message ID to prevent duplicate processing
1575
- if (lastProcessedMessageRef.current === newMessage.id) {
1576
- return prev;
1577
- }
1578
-
1579
- lastProcessedMessageRef.current = newMessage.id;
1580
-
1581
- // Use a batch update strategy to avoid frequent re-renders
1582
- queueMicrotask(() => {
1583
- safeSend({
1584
- type: ConversationActions.SET_CHANNEL_MESSAGES,
1585
- data: {
1586
- messages: uniqBy(
1587
- [...state.context.channelMessages, newMessage],
1588
- ({ id }) => id,
1589
- ),
1617
+ try {
1618
+ // Log for debugging
1619
+ console.log(
1620
+ '🔔 Subscription data received for channel:',
1621
+ state?.context?.channelId,
1622
+ );
1623
+
1624
+ // Check if we have valid subscription data
1625
+ if (!subscriptionData?.data?.chatMessageAdded) {
1626
+ console.log('🔔 No valid message in subscription data');
1627
+ return prev;
1628
+ }
1629
+
1630
+ const newMessage = subscriptionData.data.chatMessageAdded;
1631
+ console.log('🔔 New message received:', newMessage.id);
1632
+
1633
+ // Check if we already have this message to avoid duplicates
1634
+ const currentMessages = prev?.messages?.data || [];
1635
+ if (currentMessages.some((msg) => msg.id === newMessage.id)) {
1636
+ console.log('🔔 Message already in cache, skipping update');
1637
+ return prev;
1638
+ }
1639
+
1640
+ // Capture the new message in state directly
1641
+ setTimeout(() => {
1642
+ try {
1643
+ // Update state machine directly
1644
+ console.log('🔔 Directly updating state machine with new message');
1645
+ safeSend({
1646
+ type: ConversationActions.SET_CHANNEL_MESSAGES,
1647
+ data: {
1648
+ messages: [...state.context.channelMessages, newMessage],
1649
+ totalCount: (state.context.totalCount || 0) + 1,
1650
+ },
1651
+ });
1652
+ } catch (error) {
1653
+ console.error('🔔 Error updating state with subscription data:', error);
1654
+ }
1655
+ }, 0);
1656
+
1657
+ // Update Apollo cache
1658
+ const updatedData = {
1659
+ ...prev,
1660
+ messages: {
1661
+ ...prev.messages,
1662
+ data: [...currentMessages, newMessage],
1590
1663
  totalCount: (prev?.messages?.totalCount || 0) + 1,
1591
1664
  },
1592
- });
1593
- });
1665
+ };
1594
1666
 
1595
- return {
1596
- ...prev,
1597
- messages: {
1598
- ...prev?.messages,
1599
- data: [...currentMessages, newMessage],
1600
- totalCount: (prev?.messages?.totalCount || 0) + 1,
1601
- },
1602
- };
1667
+ console.log('🔔 Returning updated query data with new messages');
1668
+ return updatedData;
1669
+ } catch (error) {
1670
+ console.error('🔔 Error in subscription updateQuery:', error);
1671
+ return prev;
1672
+ }
1603
1673
  },
1604
1674
  })
1605
1675
  }
@@ -1615,9 +1685,6 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
1615
1685
  safeSend,
1616
1686
  ]);
1617
1687
 
1618
- // Add ref to track last processed message
1619
- const lastProcessedMessageRef = useRef(null);
1620
-
1621
1688
  // Add optimized listViewProps to reduce re-renders and improve list performance
1622
1689
  const listViewProps = useMemo(
1623
1690
  () => ({
@@ -1759,15 +1826,31 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
1759
1826
  };
1760
1827
 
1761
1828
  const SubscriptionHandler = ({ subscribeToNewMessages, channelId }: ISubscriptionHandlerProps) => {
1762
- // Use memo for the channelId dependency to prevent unnecessary subscriptions
1829
+ // Store the channelId in a ref to track changes
1763
1830
  const channelIdRef = useRef(channelId);
1764
1831
 
1765
1832
  useEffect(() => {
1766
- if (channelId && channelId !== channelIdRef.current) {
1767
- channelIdRef.current = channelId;
1768
- console.log('Setting up subscription for channel:', channelId);
1769
- return subscribeToNewMessages();
1833
+ // Don't set up subscription if there's no channel ID
1834
+ if (!channelId) {
1835
+ console.log('⚠️ No channel ID for subscription');
1836
+ return;
1770
1837
  }
1838
+
1839
+ console.log('🔄 Setting up NEW subscription for channel:', channelId);
1840
+
1841
+ // Call the subscribe function and store the unsubscribe function
1842
+ const unsubscribe = subscribeToNewMessages();
1843
+
1844
+ // Update the ref with the current channelId
1845
+ channelIdRef.current = channelId;
1846
+
1847
+ // Return cleanup function
1848
+ return () => {
1849
+ if (unsubscribe && typeof unsubscribe === 'function') {
1850
+ console.log('🔄 Cleaning up subscription for channel:', channelIdRef.current);
1851
+ unsubscribe();
1852
+ }
1853
+ };
1771
1854
  }, [channelId, subscribeToNewMessages]);
1772
1855
 
1773
1856
  return null;
@@ -6,7 +6,7 @@ import { useNavigation, useRoute, useFocusEffect } from '@react-navigation/nativ
6
6
  import { orderBy } from 'lodash-es';
7
7
  import { DialogsListItem } from '../components/DialogsListItem';
8
8
  import { ServiceDialogsListItem } from '../components/ServiceDialogsListItem';
9
- import { useGetChannelsByUserWithServiceChannelsQuery } from 'common/graphql';
9
+ import { useGetChannelsByUserWithServiceChannelsQuery, OnChatMessageAddedDocument } from 'common/graphql';
10
10
  import { RoomType } from 'common';
11
11
  import { userSelector } from '@adminide-stack/user-auth0-client';
12
12
  import { config } from '../config';
@@ -25,6 +25,8 @@ const Actions = {
25
25
  STOP_LOADING: 'STOP_LOADING',
26
26
  LOAD_MORE_CHANNELS: 'LOAD_MORE_CHANNELS',
27
27
  SET_SEARCH_QUERY: 'SET_SEARCH_QUERY',
28
+ UPDATE_CHANNEL: 'UPDATE_CHANNEL',
29
+ REORDER_CHANNELS: 'REORDER_CHANNELS',
28
30
  };
29
31
 
30
32
  const BaseState = {
@@ -112,11 +114,34 @@ function useSafeMachine(machine) {
112
114
  }));
113
115
  } else if (event.type === Actions.FETCH_CHANNELS) {
114
116
  console.log('Setting channels:', event.data?.channels?.length || 0);
117
+
118
+ // Process channels to ensure lastMessage property is properly structured for child components
119
+ const processedChannels =
120
+ event.data?.channels?.map((channel) => {
121
+ // If channel has a lastMessage, ensure it's properly formatted
122
+ if (channel.lastMessage) {
123
+ return {
124
+ ...channel,
125
+ lastMessage: {
126
+ ...channel.lastMessage,
127
+ // Ensure these essential properties exist
128
+ id: channel.lastMessage.id,
129
+ message: channel.lastMessage.message,
130
+ createdAt: channel.lastMessage.createdAt || channel.lastMessage.updatedAt,
131
+ updatedAt: channel.lastMessage.updatedAt || channel.lastMessage.createdAt,
132
+ userId: channel.lastMessage.userId,
133
+ channelId: channel.lastMessage.channelId || channel.id,
134
+ },
135
+ };
136
+ }
137
+ return channel;
138
+ }) || [];
139
+
115
140
  setState((prev) => ({
116
141
  ...prev,
117
142
  context: {
118
143
  ...prev.context,
119
- channels: event.data?.channels || [],
144
+ channels: processedChannels,
120
145
  hasMoreChannels: (event.data?.channels?.length || 0) > 0,
121
146
  loading: event.data?.stopLoading ? false : prev.context.loading,
122
147
  refreshing: event.data?.stopLoading ? false : prev.context.refreshing,
@@ -128,17 +153,74 @@ function useSafeMachine(machine) {
128
153
  const newChannels = event.data?.channels || [];
129
154
  console.log('Appending channels:', newChannels.length);
130
155
 
156
+ // Process new channels to ensure lastMessage property is properly structured
157
+ const processedNewChannels = newChannels.map((channel) => {
158
+ // If channel has a lastMessage, ensure it's properly formatted
159
+ if (channel.lastMessage) {
160
+ return {
161
+ ...channel,
162
+ lastMessage: {
163
+ ...channel.lastMessage,
164
+ // Ensure these essential properties exist
165
+ id: channel.lastMessage.id,
166
+ message: channel.lastMessage.message,
167
+ createdAt: channel.lastMessage.createdAt || channel.lastMessage.updatedAt,
168
+ updatedAt: channel.lastMessage.updatedAt || channel.lastMessage.createdAt,
169
+ userId: channel.lastMessage.userId,
170
+ channelId: channel.lastMessage.channelId || channel.id,
171
+ },
172
+ };
173
+ }
174
+ return channel;
175
+ });
176
+
131
177
  setState((prev) => ({
132
178
  ...prev,
133
179
  context: {
134
180
  ...prev.context,
135
- channels: [...prev.context.channels, ...newChannels],
181
+ channels: [...prev.context.channels, ...processedNewChannels],
136
182
  hasMoreChannels: newChannels.length >= 10, // If we got fewer than 10 channels, assume no more are available
137
183
  page: prev.context.page + 1,
138
184
  loadingMore: false,
139
185
  },
140
186
  value: BaseState.Idle,
141
187
  }));
188
+ } else if (event.type === Actions.UPDATE_CHANNEL) {
189
+ // Handle channel update from subscription
190
+ setState((prev) => {
191
+ const updatedChannel = event.data?.channel;
192
+ if (!updatedChannel || !updatedChannel.id) return prev;
193
+
194
+ // Find and update specific channel
195
+ const updatedChannels = prev.context.channels.map((channel) =>
196
+ channel.id === updatedChannel.id ? updatedChannel : channel,
197
+ );
198
+
199
+ return {
200
+ ...prev,
201
+ context: {
202
+ ...prev.context,
203
+ channels: updatedChannels,
204
+ },
205
+ };
206
+ });
207
+ } else if (event.type === Actions.REORDER_CHANNELS) {
208
+ // Re-sort channels by updateAt timestamp to move newly updated ones to top
209
+ setState((prev) => {
210
+ const sortedChannels = [...prev.context.channels].sort((a, b) => {
211
+ const dateA = new Date(a?.updatedAt || a?.createdAt).getTime();
212
+ const dateB = new Date(b?.updatedAt || b?.createdAt).getTime();
213
+ return dateB - dateA; // Newest first
214
+ });
215
+
216
+ return {
217
+ ...prev,
218
+ context: {
219
+ ...prev.context,
220
+ channels: sortedChannels,
221
+ },
222
+ };
223
+ });
142
224
  } else if (event.type === Actions.REFRESH_CHANNELS) {
143
225
  setState((prev) => ({
144
226
  ...prev,
@@ -335,7 +417,7 @@ const DialogsComponent = (props: InboxProps) => {
335
417
  }, []);
336
418
 
337
419
  // Apollo query for fetching channels
338
- const { refetch: getChannelsRefetch } = useGetChannelsByUserWithServiceChannelsQuery({
420
+ const { refetch: getChannelsRefetch, subscribeToMore } = useGetChannelsByUserWithServiceChannelsQuery({
339
421
  variables: {
340
422
  role: channelRole,
341
423
  criteria: channelFilters,
@@ -407,8 +489,8 @@ const DialogsComponent = (props: InboxProps) => {
407
489
  // Use more efficient sorting
408
490
  const sortedChannels =
409
491
  filteredChannels.sort((a, b) => {
410
- const dateA = new Date(a.updatedAt);
411
- const dateB = new Date(b.updatedAt);
492
+ const dateA = new Date(a.updatedAt || a.createdAt);
493
+ const dateB = new Date(b.updatedAt || b.createdAt);
412
494
  return dateB.getTime() - dateA.getTime();
413
495
  }) || [];
414
496
 
@@ -421,9 +503,13 @@ const DialogsComponent = (props: InboxProps) => {
421
503
  data: { channels: sortedChannels },
422
504
  });
423
505
  } else {
506
+ // Use a single update to prevent UI jumping
424
507
  safeSend({
425
508
  type: Actions.FETCH_CHANNELS,
426
- data: { channels: sortedChannels, stopLoading: true },
509
+ data: {
510
+ channels: sortedChannels,
511
+ stopLoading: true,
512
+ },
427
513
  });
428
514
  }
429
515
 
@@ -495,7 +581,7 @@ const DialogsComponent = (props: InboxProps) => {
495
581
 
496
582
  console.log(`📊 Fast refresh completed: ${sortedChannels.length} channels`);
497
583
 
498
- // Update the state with the new channels, but only if still mounted
584
+ // Use a single update to prevent UI jumping
499
585
  if (isMountedRef.current) {
500
586
  // Use a single update to prevent UI jumping
501
587
  safeSend({
@@ -514,6 +600,106 @@ const DialogsComponent = (props: InboxProps) => {
514
600
  }
515
601
  }, [getChannelsRefetch, channelRole, channelFilters, supportServices, auth?.id, safeSend]);
516
602
 
603
+ // Subscription ref to track and reuse the subscription
604
+ const messageSubscriptionRef = useRef(null);
605
+
606
+ // Set up message subscription for real-time updates
607
+ useEffect(() => {
608
+ if (!auth || !auth.id || messageSubscriptionRef.current) return; // Skip if already subscribed or no auth
609
+
610
+ console.log('📱 Setting up global message subscription for dialog updates');
611
+
612
+ // Set up subscription for message updates
613
+ const unsubscribe = subscribeToMore({
614
+ document: OnChatMessageAddedDocument,
615
+ variables: {}, // No specific channel ID - we'll filter in the updateQuery
616
+ updateQuery: (prev, { subscriptionData }) => {
617
+ try {
618
+ if (!subscriptionData.data || !isMountedRef.current) return prev;
619
+
620
+ // Access chatMessageAdded from the subscription data
621
+ // Cast to any to avoid TypeScript errors with dynamic subscription data
622
+ const subData = subscriptionData.data as any;
623
+ const newMessage = subData.chatMessageAdded;
624
+
625
+ console.log('📱 Dialog subscription received message update:', newMessage?.id);
626
+
627
+ // Skip if no message or no channelId
628
+ if (!newMessage || !newMessage.channelId) return prev;
629
+
630
+ // Get the current channels from state context rather than closure
631
+ const currentChannels = safeGetContext().channels || [];
632
+
633
+ // Find the channel that needs to be updated
634
+ const channelToUpdate = currentChannels.find(
635
+ (c) => c.id?.toString() === newMessage.channelId?.toString(),
636
+ );
637
+
638
+ if (channelToUpdate) {
639
+ console.log('📱 Found channel to update:', channelToUpdate.id);
640
+
641
+ // Create a more complete updated channel object with the new message
642
+ const updatedChannel = {
643
+ ...channelToUpdate,
644
+ updatedAt: newMessage.createdAt || newMessage.updatedAt,
645
+ lastMessage: {
646
+ ...newMessage,
647
+ // Ensure these properties are present for rendering in child components
648
+ id: newMessage.id,
649
+ message: newMessage.message,
650
+ createdAt: newMessage.createdAt || newMessage.updatedAt,
651
+ updatedAt: newMessage.updatedAt || newMessage.createdAt,
652
+ userId: newMessage.userId,
653
+ channelId: newMessage.channelId,
654
+ },
655
+ };
656
+
657
+ // Update the channel with new message immediately
658
+ if (isMountedRef.current) {
659
+ // Update the channel
660
+ safeSend({
661
+ type: Actions.UPDATE_CHANNEL,
662
+ data: {
663
+ channel: updatedChannel,
664
+ },
665
+ });
666
+
667
+ // Reorder channels to bring updated one to top
668
+ safeSend({
669
+ type: Actions.REORDER_CHANNELS,
670
+ });
671
+ }
672
+ } else {
673
+ console.log('📱 Channel not found in current list, triggering refresh');
674
+ // If we received a message for a channel that's not in our current list
675
+ // trigger a refresh to get the updated channel list
676
+ if (isMountedRef.current && !safeGetContext().refreshing && !safeGetContext().loading) {
677
+ fastRefresh();
678
+ }
679
+ }
680
+
681
+ // Return unchanged prev (we're updating via state machine instead)
682
+ return prev;
683
+ } catch (error) {
684
+ console.error('Error in dialog subscription handler:', error);
685
+ return prev;
686
+ }
687
+ },
688
+ });
689
+
690
+ // Save subscription in ref for reuse
691
+ messageSubscriptionRef.current = unsubscribe;
692
+
693
+ // Clean up subscription when component unmounts
694
+ return () => {
695
+ if (messageSubscriptionRef.current) {
696
+ console.log('📱 Cleaning up dialog message subscription');
697
+ messageSubscriptionRef.current();
698
+ messageSubscriptionRef.current = null;
699
+ }
700
+ };
701
+ }, [auth?.id, isMountedRef, safeGetContext, fastRefresh, safeSend, subscribeToMore]);
702
+
517
703
  // Process state changes and execute side effects
518
704
  useEffect(() => {
519
705
  // Only execute if not already refreshing or loading to prevent loops
@@ -584,61 +770,46 @@ const DialogsComponent = (props: InboxProps) => {
584
770
 
585
771
  // Handle refresh on focus (when navigating back to this screen)
586
772
  const focusRefreshRef = useRef<number | null>(null);
773
+ // Add a timestamp ref to track last refresh time
774
+ const lastRefreshTimeRef = useRef(Date.now());
775
+ // Minimum interval between refreshes (2 seconds)
776
+ const MIN_REFRESH_INTERVAL = 2000;
587
777
 
588
778
  useFocusEffect(
589
779
  useCallback(() => {
590
- // Use a flag to ensure we only trigger refresh once per focus
591
- let hasTriggeredRefresh = false;
592
-
593
- // Reset the focus refresh tracking when component gets focus
594
- const now = Date.now();
595
- const lastRefresh = focusRefreshRef.current;
596
-
597
- // Only refresh if at least 2 seconds have passed since last refresh
598
- const shouldRefresh = lastRefresh === null || now - lastRefresh > 2000;
599
-
600
- // Only refresh if component is mounted and not in initial state,
601
- // and not already refreshing/loading
602
- const context = safeGetContext();
603
- const isAlreadyFetching = context.refreshing || context.loading;
604
-
605
- if (
606
- isMountedRef.current &&
607
- !hasTriggeredRefresh &&
608
- !isAlreadyFetching &&
609
- shouldRefresh &&
610
- (channels.length > 0 || safeMatches(BaseState.Idle))
611
- ) {
612
- hasTriggeredRefresh = true;
613
- focusRefreshRef.current = now;
614
-
615
- // Use fast refresh for better performance
616
- console.log('🔄 Focus effect: triggering fast refresh');
617
- safeSend({
618
- type: Actions.START_LOADING,
619
- data: { refreshing: true },
620
- });
780
+ console.log('📱 Focus effect triggered for Dialogs screen');
781
+
782
+ // Always do a lightweight refresh on focus for the latest messages
783
+ // This ensures we always have up-to-date message status when returning to the screen
784
+ const performRefresh = () => {
785
+ // Check if enough time has passed since last refresh
786
+ const now = Date.now();
787
+ if (now - lastRefreshTimeRef.current < MIN_REFRESH_INTERVAL) {
788
+ console.log('⏩ Skipping refresh: too soon after previous refresh');
789
+ return;
790
+ }
621
791
 
622
- // Execute fast refresh with a short delay to prevent UI jank
623
- setTimeout(() => {
624
- if (isMountedRef.current) {
625
- fastRefresh();
626
- }
627
- }, 100);
628
- } else {
629
- console.log('⏩ Skipping focus refresh:', {
630
- isAlreadyFetching,
631
- hasTriggeredRefresh,
632
- shouldRefresh,
633
- timeGap: lastRefresh === null ? 'first refresh' : now - lastRefresh,
634
- });
635
- }
792
+ console.log('🔄 Performing forced refresh on screen focus');
793
+ if (isMountedRef.current) {
794
+ // Update last refresh timestamp
795
+ lastRefreshTimeRef.current = now;
796
+
797
+ safeSend({
798
+ type: Actions.START_LOADING,
799
+ data: { refreshing: true },
800
+ });
801
+ fastRefresh();
802
+ }
803
+ };
804
+
805
+ // Always refresh when returning to the screen, with a small delay
806
+ const focusRefreshTimeout = setTimeout(performRefresh, 100);
636
807
 
808
+ // Cleanup function to remove the timeout if the component unmounts or loses focus
637
809
  return () => {
638
- // Reset flag when focus is lost
639
- hasTriggeredRefresh = false;
810
+ clearTimeout(focusRefreshTimeout);
640
811
  };
641
- }, [safeSend, channels.length, safeMatches, safeGetContext, fastRefresh]),
812
+ }, [safeSend, fastRefresh]),
642
813
  );
643
814
 
644
815
  // Navigation handlers
@@ -745,7 +916,7 @@ const DialogsComponent = (props: InboxProps) => {
745
916
  currentUser={auth}
746
917
  channel={channel}
747
918
  selectedChannelId={selectedChannelId}
748
- forceRefresh={false} // Change to false to avoid unnecessary refreshes
919
+ forceRefresh={true}
749
920
  />
750
921
  );
751
922
  }}