@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.
- package/CHANGELOG.md +8 -0
- package/lib/screens/inbox/components/DialogsListItem.js +26 -6
- package/lib/screens/inbox/components/DialogsListItem.js.map +1 -1
- package/lib/screens/inbox/components/ServiceDialogsListItem.js +171 -42
- package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +1 -1
- package/lib/screens/inbox/containers/ConversationView.js +116 -51
- package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/Dialogs.js +168 -56
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/package.json +4 -4
- package/src/screens/inbox/components/DialogsListItem.tsx +31 -0
- package/src/screens/inbox/components/ServiceDialogsListItem.tsx +300 -113
- package/src/screens/inbox/containers/ConversationView.tsx +146 -63
- package/src/screens/inbox/containers/Dialogs.tsx +228 -57
|
@@ -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
|
|
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
|
-
//
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
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
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
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
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
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
|
-
//
|
|
1829
|
+
// Store the channelId in a ref to track changes
|
|
1763
1830
|
const channelIdRef = useRef(channelId);
|
|
1764
1831
|
|
|
1765
1832
|
useEffect(() => {
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
console.log('
|
|
1769
|
-
return
|
|
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:
|
|
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, ...
|
|
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: {
|
|
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
|
-
//
|
|
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
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
//
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
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
|
-
|
|
639
|
-
hasTriggeredRefresh = false;
|
|
810
|
+
clearTimeout(focusRefreshTimeout);
|
|
640
811
|
};
|
|
641
|
-
}, [safeSend,
|
|
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={
|
|
919
|
+
forceRefresh={true}
|
|
749
920
|
/>
|
|
750
921
|
);
|
|
751
922
|
}}
|