@messenger-box/platform-mobile 10.0.3-alpha.47 → 10.0.3-alpha.48
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 +4 -0
- package/lib/queries/inboxQueries.js +2 -13
- package/lib/queries/inboxQueries.js.map +1 -1
- package/lib/screens/inbox/components/DialogItem.js +169 -0
- package/lib/screens/inbox/components/DialogItem.js.map +1 -0
- package/lib/screens/inbox/containers/Dialogs.js +10 -20
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/package.json +4 -4
- package/src/screens/inbox/components/DialogItem.tsx +306 -0
- package/src/screens/inbox/components/DialogsListItem.tsx +140 -305
- package/src/screens/inbox/components/ServiceDialogsListItem.tsx +171 -264
- package/src/screens/inbox/containers/Dialogs.tsx +104 -45
- package/lib/screens/inbox/components/DialogsListItem.js +0 -355
- package/lib/screens/inbox/components/DialogsListItem.js.map +0 -1
- package/lib/screens/inbox/components/ServiceDialogsListItem.js +0 -402
- package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +0 -1
|
@@ -15,11 +15,7 @@ import {
|
|
|
15
15
|
import { format, isToday, isYesterday } from 'date-fns';
|
|
16
16
|
import { useFocusEffect } from '@react-navigation/native';
|
|
17
17
|
import { IChannel, SortEnum, IUserAccount } from 'common';
|
|
18
|
-
import {
|
|
19
|
-
CHAT_MESSAGE_ADDED,
|
|
20
|
-
useChatMessageAddedSubscription,
|
|
21
|
-
useMessagesQuery as useMessagesQueryFromInbox,
|
|
22
|
-
} from '../../../queries/inboxQueries';
|
|
18
|
+
import { CHAT_MESSAGE_ADDED, useMessagesQuery as useMessagesQueryFromInbox } from '../../../queries/inboxQueries';
|
|
23
19
|
import { startCase } from 'lodash-es';
|
|
24
20
|
import colors from 'tailwindcss/colors';
|
|
25
21
|
import { SubscriptionHandler } from './SubscriptionHandler';
|
|
@@ -47,30 +43,7 @@ export interface IDialogListItemProps {
|
|
|
47
43
|
}
|
|
48
44
|
|
|
49
45
|
// LastMessage component definition
|
|
50
|
-
const LastMessageComponent = ({
|
|
51
|
-
// Subscribe to new messages when component mounts
|
|
52
|
-
React.useEffect(() => {
|
|
53
|
-
// Subscribe and store the unsubscribe function
|
|
54
|
-
const unsubscribe = subscribeToNewMessages();
|
|
55
|
-
return () => {
|
|
56
|
-
// Cleanup subscription on unmount
|
|
57
|
-
if (unsubscribe && typeof unsubscribe === 'function') {
|
|
58
|
-
unsubscribe();
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
}, [channelId, subscribeToNewMessages]);
|
|
62
|
-
|
|
63
|
-
// Debug output for component rendering
|
|
64
|
-
// React.useEffect(() => {
|
|
65
|
-
// console.log(`LastMessageComponent rendered for channel ${channelId}:`, {
|
|
66
|
-
// hasLastMessage: !!lastMessage,
|
|
67
|
-
// messageId: lastMessage?.id,
|
|
68
|
-
// messageText: lastMessage?.message?.substring(0, 20) + (lastMessage?.message?.length > 20 ? '...' : ''),
|
|
69
|
-
// date: lastMessage?.createdAt ? new Date(lastMessage.createdAt).toISOString() : 'none',
|
|
70
|
-
// hasFiles: lastMessage?.files?.data?.length > 0,
|
|
71
|
-
// });
|
|
72
|
-
// }, [lastMessage, channelId]);
|
|
73
|
-
|
|
46
|
+
const LastMessageComponent = ({ title, lastMessage }) => {
|
|
74
47
|
const count = 30;
|
|
75
48
|
const channelTitle = title?.slice(0, count) + (title?.length > count ? '...' : '') || '';
|
|
76
49
|
|
|
@@ -98,28 +71,20 @@ const LastMessageComponent = ({ subscribeToNewMessages, title, lastMessage, chan
|
|
|
98
71
|
: '';
|
|
99
72
|
|
|
100
73
|
return (
|
|
101
|
-
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
</Text>
|
|
116
|
-
</Box>
|
|
117
|
-
|
|
118
|
-
<Box className="flex-[0.2]">
|
|
119
|
-
<Text color={colors.gray[500]}>{displayDate}</Text>
|
|
120
|
-
</Box>
|
|
121
|
-
</HStack>
|
|
122
|
-
</>
|
|
74
|
+
<HStack space={'sm'} className="flex-1 justify-between">
|
|
75
|
+
<Box className="flex-[0.8]">
|
|
76
|
+
<Text color={colors.gray[600]} className="text-base text-wrap flex-wrap font-semibold">
|
|
77
|
+
{channelTitle}
|
|
78
|
+
</Text>
|
|
79
|
+
<Text color={colors.gray[600]} numberOfLines={1}>
|
|
80
|
+
{displayMessage}
|
|
81
|
+
</Text>
|
|
82
|
+
</Box>
|
|
83
|
+
|
|
84
|
+
<Box className="flex-[0.2]">
|
|
85
|
+
<Text color={colors.gray[500]}>{displayDate}</Text>
|
|
86
|
+
</Box>
|
|
87
|
+
</HStack>
|
|
123
88
|
);
|
|
124
89
|
};
|
|
125
90
|
|
|
@@ -130,7 +95,6 @@ const LastMessageComponent = ({ subscribeToNewMessages, title, lastMessage, chan
|
|
|
130
95
|
*/
|
|
131
96
|
export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function DialogsListItem({
|
|
132
97
|
currentUser,
|
|
133
|
-
// users,
|
|
134
98
|
selectedChannelId,
|
|
135
99
|
channel,
|
|
136
100
|
onOpen,
|
|
@@ -143,58 +107,91 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
|
|
|
143
107
|
// Define parentId early to avoid linter errors
|
|
144
108
|
const parentId: any = null;
|
|
145
109
|
|
|
146
|
-
//
|
|
110
|
+
// Simplified state - only keep loading state, rely on Apollo cache for data
|
|
147
111
|
const [loading, setLoading] = useState(false);
|
|
148
112
|
const [title, setTitle] = useState('');
|
|
149
|
-
const [messages, setMessages] = useState([]);
|
|
150
|
-
const [lastMessage, setLastMessage] = useState(null);
|
|
151
113
|
|
|
152
114
|
// Only run queries/subscriptions if visible
|
|
153
115
|
const shouldQuery = !!channel?.id && visible;
|
|
154
116
|
|
|
155
|
-
//
|
|
117
|
+
// Memoize query variables to prevent unnecessary re-renders
|
|
118
|
+
const queryVariables = useMemo(
|
|
119
|
+
() => ({
|
|
120
|
+
channelId: channel?.id?.toString(),
|
|
121
|
+
parentId: parentId,
|
|
122
|
+
limit: 10,
|
|
123
|
+
}),
|
|
124
|
+
[channel?.id, parentId],
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Optimized message processing function
|
|
128
|
+
const processMessagesData = useCallback((messagesData: any[]) => {
|
|
129
|
+
if (!messagesData?.length) return null;
|
|
130
|
+
|
|
131
|
+
// Sort messages and return the latest one
|
|
132
|
+
const sortedMessages = [...messagesData].sort(
|
|
133
|
+
(a, b) =>
|
|
134
|
+
new Date(b?.updatedAt || b?.createdAt).getTime() - new Date(a?.updatedAt || a?.createdAt).getTime(),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
return sortedMessages[0];
|
|
138
|
+
}, []);
|
|
139
|
+
|
|
140
|
+
// Optimized refetch function - consolidated all refetch logic
|
|
141
|
+
const optimizedRefetch = useCallback(
|
|
142
|
+
async (reason: string = 'manual') => {
|
|
143
|
+
if (!shouldQuery || !channel?.id || !isMountedRef.current) return null;
|
|
144
|
+
|
|
145
|
+
console.log(`Optimized refetch triggered: ${reason} for channel ${channel?.id}`);
|
|
146
|
+
setLoading(true);
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const result = await refetchMessages(queryVariables);
|
|
150
|
+
console.log(
|
|
151
|
+
`Refetch completed: ${reason}, messages count: ${result?.data?.messages?.data?.length || 0}`,
|
|
152
|
+
);
|
|
153
|
+
return result;
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error(`Refetch error (${reason}):`, error);
|
|
156
|
+
return null;
|
|
157
|
+
} finally {
|
|
158
|
+
if (isMountedRef.current) {
|
|
159
|
+
setLoading(false);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
[shouldQuery, channel?.id, queryVariables],
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Query hooks for fetching messages - optimized configuration
|
|
156
167
|
const {
|
|
157
168
|
data: messagesQuery,
|
|
158
169
|
loading: messageLoading,
|
|
159
170
|
refetch: refetchMessages,
|
|
160
171
|
subscribeToMore,
|
|
172
|
+
error,
|
|
161
173
|
} = useMessagesQueryFromInbox({
|
|
162
|
-
variables:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
fetchPolicy: 'cache-and-network',
|
|
169
|
-
refetchWritePolicy: 'overwrite',
|
|
170
|
-
nextFetchPolicy: 'network-only',
|
|
174
|
+
variables: queryVariables,
|
|
175
|
+
skip: !shouldQuery,
|
|
176
|
+
fetchPolicy: 'cache-first', // Changed from cache-and-network for better performance
|
|
177
|
+
nextFetchPolicy: 'cache-first',
|
|
178
|
+
notifyOnNetworkStatusChange: true,
|
|
179
|
+
errorPolicy: 'all', // Handle partial errors gracefully
|
|
171
180
|
onCompleted: (data) => {
|
|
172
|
-
|
|
173
|
-
if (data?.messages?.data)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
(a, b) =>
|
|
177
|
-
new Date(b?.updatedAt || b?.createdAt).getTime() -
|
|
178
|
-
new Date(a?.updatedAt || a?.createdAt).getTime(),
|
|
179
|
-
);
|
|
180
|
-
if (sortedMessages.length > 0) {
|
|
181
|
-
setLastMessage(sortedMessages[0]);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
181
|
+
// Simplified onCompleted - minimal processing
|
|
182
|
+
if (!shouldQuery || !data?.messages?.data) return;
|
|
183
|
+
|
|
184
|
+
console.log(`Query completed for channel ${channel?.id}, messages: ${data.messages.data.length}`);
|
|
184
185
|
},
|
|
185
186
|
onError: (error) => {
|
|
186
187
|
if (!shouldQuery) return;
|
|
187
|
-
console.error(`
|
|
188
|
+
console.error(`Query error for channel ${channel?.id}:`, error);
|
|
188
189
|
},
|
|
189
190
|
});
|
|
190
191
|
|
|
191
|
-
//
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
channelId: channel?.id?.toString(),
|
|
195
|
-
},
|
|
196
|
-
skip: !shouldQuery,
|
|
197
|
-
});
|
|
192
|
+
// Derived state from query data - use Apollo cache as single source of truth
|
|
193
|
+
const messages = useMemo(() => messagesQuery?.messages?.data || [], [messagesQuery]);
|
|
194
|
+
const lastMessage = useMemo(() => processMessagesData(messages), [messages, processMessagesData]);
|
|
198
195
|
|
|
199
196
|
// Set mounted state on mount/unmount
|
|
200
197
|
useEffect(() => {
|
|
@@ -204,184 +201,56 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
|
|
|
204
201
|
};
|
|
205
202
|
}, []);
|
|
206
203
|
|
|
207
|
-
//
|
|
208
|
-
const refreshDialogState = useCallback(() => {
|
|
209
|
-
if (shouldQuery && isMountedRef.current) {
|
|
210
|
-
setLoading(true);
|
|
211
|
-
const options = {
|
|
212
|
-
channelId: channel?.id?.toString(),
|
|
213
|
-
parentId: parentId,
|
|
214
|
-
limit: 10,
|
|
215
|
-
};
|
|
216
|
-
refetchMessages(options)
|
|
217
|
-
.then((result) => {
|
|
218
|
-
if (result.data?.messages?.data && isMountedRef.current) {
|
|
219
|
-
const sortedMessages = [...result.data.messages.data].sort(
|
|
220
|
-
(a, b) =>
|
|
221
|
-
new Date(b?.updatedAt || b?.createdAt).getTime() -
|
|
222
|
-
new Date(a?.updatedAt || a?.createdAt).getTime(),
|
|
223
|
-
);
|
|
224
|
-
const latestMessage = sortedMessages.length > 0 ? sortedMessages[0] : null;
|
|
225
|
-
setMessages(result.data.messages.data);
|
|
226
|
-
setLastMessage(latestMessage);
|
|
227
|
-
}
|
|
228
|
-
setLoading(false);
|
|
229
|
-
})
|
|
230
|
-
.catch((err) => {
|
|
231
|
-
console.error('Error refreshing dialog state:', err);
|
|
232
|
-
setLoading(false);
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
}, [shouldQuery, channel?.id, refetchMessages, parentId]);
|
|
236
|
-
|
|
237
|
-
// Track if this is the first time the component renders
|
|
204
|
+
// Optimized focus effect - single refetch with debouncing
|
|
238
205
|
const firstRenderRef = useRef(true);
|
|
239
|
-
|
|
240
|
-
// Fix messages not refreshing when coming back from detail screen
|
|
241
206
|
useFocusEffect(
|
|
242
|
-
|
|
207
|
+
useCallback(() => {
|
|
243
208
|
if (!channel?.id) return;
|
|
244
209
|
|
|
245
210
|
console.log('DialogsListItem focused for channel:', channel?.id);
|
|
246
211
|
|
|
247
|
-
// Skip refresh on first render
|
|
212
|
+
// Skip refresh on first render
|
|
248
213
|
if (firstRenderRef.current) {
|
|
249
|
-
console.log('Skipping initial focus refresh for channel:', channel?.id);
|
|
250
214
|
firstRenderRef.current = false;
|
|
251
215
|
return;
|
|
252
216
|
}
|
|
253
217
|
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
setLoading(true);
|
|
259
|
-
|
|
260
|
-
// Use a direct refetch with network-only policy to force fresh data
|
|
261
|
-
const fetchFreshData = async () => {
|
|
262
|
-
try {
|
|
263
|
-
// Set up the options for the query to force network fetch
|
|
264
|
-
const options = {
|
|
265
|
-
channelId: channel?.id?.toString(),
|
|
266
|
-
parentId: parentId,
|
|
267
|
-
limit: 10,
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
// Force a network-only fetch by using refetch without extra options
|
|
271
|
-
// Apollo will use the parent query's fetch policy which we've set to network-only
|
|
272
|
-
const result = await refetchMessages(options);
|
|
273
|
-
|
|
274
|
-
// Log the refreshed data
|
|
275
|
-
console.log(
|
|
276
|
-
`FOCUS EFFECT: Refetched ${result?.data?.messages?.data?.length || 0} messages for channel ${
|
|
277
|
-
channel?.id
|
|
278
|
-
}`,
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
if (result?.data?.messages?.data && isMountedRef.current) {
|
|
282
|
-
// Compare with current state to check if we're getting fresh data
|
|
283
|
-
const currentMessages = messages;
|
|
284
|
-
const fetchedMessages = result.data.messages.data;
|
|
285
|
-
|
|
286
|
-
// Log comparison to see if we got new data
|
|
287
|
-
console.log('Data comparison:', {
|
|
288
|
-
currentCount: currentMessages.length,
|
|
289
|
-
fetchedCount: fetchedMessages.length,
|
|
290
|
-
isDifferent: JSON.stringify(currentMessages) !== JSON.stringify(fetchedMessages),
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
// Get the most recent message
|
|
294
|
-
const sortedMessages = [...fetchedMessages].sort(
|
|
295
|
-
(a, b) =>
|
|
296
|
-
new Date(b?.updatedAt || b?.createdAt).getTime() -
|
|
297
|
-
new Date(a?.updatedAt || a?.createdAt).getTime(),
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
const latestMessage = sortedMessages.length > 0 ? sortedMessages[0] : null;
|
|
301
|
-
|
|
302
|
-
// Update state with fresh data
|
|
303
|
-
setMessages(fetchedMessages);
|
|
304
|
-
setLastMessage(latestMessage);
|
|
305
|
-
}
|
|
306
|
-
} catch (error) {
|
|
307
|
-
console.error('Error refetching messages on focus:', error);
|
|
308
|
-
} finally {
|
|
309
|
-
if (isMountedRef.current) {
|
|
310
|
-
setLoading(false);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
// Execute fetch
|
|
316
|
-
fetchFreshData();
|
|
218
|
+
// Debounced refetch on focus
|
|
219
|
+
const timeoutId = setTimeout(() => {
|
|
220
|
+
optimizedRefetch('focus');
|
|
221
|
+
}, 100);
|
|
317
222
|
|
|
318
|
-
return () =>
|
|
319
|
-
|
|
320
|
-
};
|
|
321
|
-
}, [channel?.id, refetchMessages, messages, isMountedRef, parentId]),
|
|
223
|
+
return () => clearTimeout(timeoutId);
|
|
224
|
+
}, [channel?.id, optimizedRefetch]),
|
|
322
225
|
);
|
|
323
226
|
|
|
324
|
-
//
|
|
325
|
-
useEffect(() => {
|
|
326
|
-
if (!shouldQuery) return;
|
|
327
|
-
if (channel?.id && isMountedRef.current) {
|
|
328
|
-
const timer = setTimeout(() => {
|
|
329
|
-
if (isMountedRef.current) {
|
|
330
|
-
refreshDialogState();
|
|
331
|
-
}
|
|
332
|
-
}, 100);
|
|
333
|
-
return () => {
|
|
334
|
-
clearTimeout(timer);
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
}, [shouldQuery, channel?.id, refreshDialogState]);
|
|
338
|
-
|
|
227
|
+
// Simplified effect for force refresh
|
|
339
228
|
useEffect(() => {
|
|
340
|
-
if (forceRefresh && shouldQuery
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
refetchMessages({
|
|
344
|
-
channelId: channel?.id?.toString(),
|
|
345
|
-
parentId: parentId,
|
|
346
|
-
limit: 10,
|
|
347
|
-
})
|
|
348
|
-
.then((result) => {
|
|
349
|
-
if (result?.data?.messages?.data && isMountedRef.current) {
|
|
350
|
-
const sortedMessages = [...result.data.messages.data].sort(
|
|
351
|
-
(a, b) =>
|
|
352
|
-
new Date(b?.updatedAt || b?.createdAt).getTime() -
|
|
353
|
-
new Date(a?.updatedAt || a?.createdAt).getTime(),
|
|
354
|
-
);
|
|
355
|
-
const latestMessage = sortedMessages.length > 0 ? sortedMessages[0] : null;
|
|
356
|
-
setMessages(result.data.messages.data);
|
|
357
|
-
setLastMessage(latestMessage);
|
|
358
|
-
}
|
|
359
|
-
})
|
|
360
|
-
.catch((error) => {
|
|
361
|
-
console.error(`Error force refreshing channel ${channel?.id}:`, error);
|
|
362
|
-
});
|
|
363
|
-
}
|
|
229
|
+
if (forceRefresh && shouldQuery) {
|
|
230
|
+
const timeoutId = setTimeout(() => {
|
|
231
|
+
optimizedRefetch('force');
|
|
364
232
|
}, 50);
|
|
365
|
-
return () => clearTimeout(
|
|
233
|
+
return () => clearTimeout(timeoutId);
|
|
366
234
|
}
|
|
367
|
-
}, [
|
|
235
|
+
}, [forceRefresh, shouldQuery, optimizedRefetch]);
|
|
368
236
|
|
|
237
|
+
// Channel members computation - optimized with better memoization
|
|
369
238
|
const channelMembers = useMemo(
|
|
370
239
|
() =>
|
|
371
240
|
channel?.members
|
|
372
|
-
?.filter((ch: any) => ch?.user?.id
|
|
373
|
-
?.map((m: any) => m?.user) ??
|
|
374
|
-
[currentUser, channel],
|
|
241
|
+
?.filter((ch: any) => ch?.user?.id !== currentUser?.id && ch?.user?.__typename === 'UserAccount')
|
|
242
|
+
?.map((m: any) => m?.user) ?? [],
|
|
243
|
+
[currentUser?.id, channel?.members],
|
|
375
244
|
);
|
|
376
245
|
|
|
377
246
|
// Set title when channel members change
|
|
378
247
|
useEffect(() => {
|
|
379
|
-
if (channelMembers && isMountedRef.current) {
|
|
248
|
+
if (channelMembers.length > 0 && isMountedRef.current) {
|
|
380
249
|
const titleString =
|
|
381
250
|
channelMembers
|
|
382
|
-
?.map((u: any) => u?.givenName
|
|
383
|
-
?.filter(
|
|
384
|
-
?.join(', ')
|
|
251
|
+
?.map((u: any) => `${u?.givenName || ''} ${u?.familyName || ''}`.trim())
|
|
252
|
+
?.filter(Boolean)
|
|
253
|
+
?.join(', ') || '';
|
|
385
254
|
setTitle(titleString);
|
|
386
255
|
}
|
|
387
256
|
}, [channelMembers]);
|
|
@@ -392,38 +261,8 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
|
|
|
392
261
|
return title.length > length ? title.substring(0, length - 3) + '...' : title;
|
|
393
262
|
}, [title]);
|
|
394
263
|
|
|
395
|
-
//
|
|
396
|
-
|
|
397
|
-
console.log(`DialogsListItem for channel ${channel?.id}: `, {
|
|
398
|
-
hasLastMessage: !!lastMessage,
|
|
399
|
-
message: lastMessage?.message?.substring(0, 20) + (lastMessage?.message?.length > 20 ? '...' : ''),
|
|
400
|
-
messagesCount: messages.length,
|
|
401
|
-
});
|
|
402
|
-
}, [channel?.id, lastMessage, messages.length]);
|
|
403
|
-
|
|
404
|
-
// Handle new messages from subscription
|
|
405
|
-
useEffect(() => {
|
|
406
|
-
if (!shouldQuery) return;
|
|
407
|
-
if (newMessage?.chatMessageAdded && channel?.id) {
|
|
408
|
-
const incomingMessage = newMessage.chatMessageAdded;
|
|
409
|
-
if (messages.some((msg) => msg.id === incomingMessage.id)) {
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
setMessages((prevMessages) => [...prevMessages, incomingMessage]);
|
|
413
|
-
setLastMessage(incomingMessage);
|
|
414
|
-
}
|
|
415
|
-
}, [shouldQuery, newMessage, channel?.id, messages]);
|
|
416
|
-
|
|
417
|
-
// Create listener for channel property updates
|
|
418
|
-
useEffect(() => {
|
|
419
|
-
if (!shouldQuery) return;
|
|
420
|
-
if (channel?.lastMessage && channel.lastMessage.id) {
|
|
421
|
-
if (!messages.some((msg) => msg.id === channel.lastMessage.id)) {
|
|
422
|
-
setMessages((prevMessages) => [...prevMessages, channel.lastMessage]);
|
|
423
|
-
setLastMessage(channel.lastMessage);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}, [shouldQuery, channel?.lastMessage?.id, messages]);
|
|
264
|
+
// Combined loading state
|
|
265
|
+
const isLoading = loading || messageLoading;
|
|
427
266
|
|
|
428
267
|
return (
|
|
429
268
|
<Pressable
|
|
@@ -431,7 +270,39 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
|
|
|
431
270
|
className="flex-1 border-gray-200 rounded-md dark:border-gray-600 dark:bg-gray-700"
|
|
432
271
|
style={{ borderBottomWidth: 1, borderColor: '#e5e7eb', marginVertical: 0, paddingHorizontal: 10 }}
|
|
433
272
|
>
|
|
434
|
-
|
|
273
|
+
{/* Optimized subscription handler */}
|
|
274
|
+
<SubscriptionHandler
|
|
275
|
+
subscribeToMore={subscribeToMore}
|
|
276
|
+
document={CHAT_MESSAGE_ADDED}
|
|
277
|
+
variables={{ channelId: channel?.id?.toString() }}
|
|
278
|
+
enabled={shouldQuery}
|
|
279
|
+
updateQuery={(prev, { subscriptionData }) => {
|
|
280
|
+
if (!subscriptionData?.data?.chatMessageAdded || !isMountedRef.current) return prev;
|
|
281
|
+
|
|
282
|
+
const newMessage = subscriptionData.data.chatMessageAdded;
|
|
283
|
+
|
|
284
|
+
// Optimized cache update - check for duplicates more efficiently
|
|
285
|
+
const existingMessages = prev?.messages;
|
|
286
|
+
const messageExists = existingMessages?.data?.some((msg: any) => msg.id === newMessage.id);
|
|
287
|
+
|
|
288
|
+
if (!messageExists) {
|
|
289
|
+
return {
|
|
290
|
+
...prev,
|
|
291
|
+
messages: {
|
|
292
|
+
...existingMessages,
|
|
293
|
+
data: [...(existingMessages?.data || []), newMessage],
|
|
294
|
+
totalCount: (existingMessages?.totalCount || 0) + 1,
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return prev;
|
|
299
|
+
}}
|
|
300
|
+
onError={(error) => {
|
|
301
|
+
console.error(`Subscription error for channel ${channel?.id}:`, error);
|
|
302
|
+
}}
|
|
303
|
+
/>
|
|
304
|
+
|
|
305
|
+
<HStack space={'md'} className="flex-1 w-[100%] py-3 items-center">
|
|
435
306
|
<Box className="flex-[0.1] items-start pl-3">
|
|
436
307
|
<AvatarGroup>
|
|
437
308
|
{channelMembers &&
|
|
@@ -481,42 +352,6 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
|
|
|
481
352
|
key={`last-msg-${lastMessage?.id || 'none'}-${messages.length}`}
|
|
482
353
|
title={displayTitle}
|
|
483
354
|
lastMessage={lastMessage}
|
|
484
|
-
channelId={channel?.id}
|
|
485
|
-
subscribeToNewMessages={() =>
|
|
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
|
|
518
|
-
}
|
|
519
|
-
subscribeToMore={subscribeToMore}
|
|
520
355
|
/>
|
|
521
356
|
</Box>
|
|
522
357
|
</HStack>
|