@messenger-box/platform-mobile 10.0.3-alpha.5 → 10.0.3-alpha.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +96 -0
- package/lib/compute.js +2 -3
- package/lib/compute.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/queries/inboxQueries.js +65 -0
- package/lib/queries/inboxQueries.js.map +1 -0
- package/lib/routes.json +2 -3
- package/lib/screens/inbox/DialogMessages.js +1 -1
- package/lib/screens/inbox/DialogMessages.js.map +1 -1
- package/lib/screens/inbox/DialogThreadMessages.js +4 -8
- package/lib/screens/inbox/DialogThreadMessages.js.map +1 -1
- package/lib/screens/inbox/DialogThreads.js +57 -12
- package/lib/screens/inbox/DialogThreads.js.map +1 -1
- package/lib/screens/inbox/Inbox.js +1 -1
- package/lib/screens/inbox/Inbox.js.map +1 -1
- package/lib/screens/inbox/components/CachedImage/consts.js +1 -1
- package/lib/screens/inbox/components/CachedImage/consts.js.map +1 -1
- package/lib/screens/inbox/components/CachedImage/index.js +168 -46
- package/lib/screens/inbox/components/CachedImage/index.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/components/GiftedChatInboxComponent.js +313 -0
- package/lib/screens/inbox/components/GiftedChatInboxComponent.js.map +1 -0
- package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +147 -31
- package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
- package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js +6 -1
- package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js.map +1 -1
- package/lib/screens/inbox/components/SubscriptionHandler.js +24 -0
- package/lib/screens/inbox/components/SubscriptionHandler.js.map +1 -0
- package/lib/screens/inbox/components/ThreadsViewItem.js +66 -55
- package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
- package/lib/screens/inbox/config/config.js +2 -2
- package/lib/screens/inbox/config/config.js.map +1 -1
- package/lib/screens/inbox/containers/ConversationView.js +1111 -434
- package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/Dialogs.js +193 -80
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadConversationView.js +725 -216
- package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadsView.js +83 -50
- package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
- package/lib/screens/inbox/hooks/useInboxMessages.js +31 -0
- package/lib/screens/inbox/hooks/useInboxMessages.js.map +1 -0
- package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js +108 -0
- package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js.map +1 -0
- package/lib/screens/inbox/workflow/dialog-threads-xstate.js +151 -0
- package/lib/screens/inbox/workflow/dialog-threads-xstate.js.map +1 -0
- package/package.json +4 -4
- package/src/compute.ts +5 -6
- package/src/index.ts +2 -0
- package/src/navigation/InboxNavigation.tsx +3 -3
- package/src/queries/inboxQueries.ts +299 -0
- package/src/queries/index.d.ts +2 -0
- package/src/queries/index.ts +1 -0
- package/src/screens/inbox/DialogMessages.tsx +1 -1
- package/src/screens/inbox/DialogThreadMessages.tsx +7 -14
- package/src/screens/inbox/DialogThreads.tsx +55 -61
- package/src/screens/inbox/Inbox.tsx +1 -1
- package/src/screens/inbox/components/Actionsheet.tsx +30 -0
- package/src/screens/inbox/components/CachedImage/consts.ts +4 -3
- package/src/screens/inbox/components/CachedImage/index.tsx +232 -61
- package/src/screens/inbox/components/DialogItem.tsx +306 -0
- package/src/screens/inbox/components/DialogsHeader.tsx +6 -13
- package/src/screens/inbox/components/DialogsListItem.tsx +262 -198
- package/src/screens/inbox/components/ExpandableInput.tsx +460 -0
- package/src/screens/inbox/components/ExpandableInputActionSheet.tsx +518 -0
- package/src/screens/inbox/components/GiftedChatInboxComponent.tsx +411 -0
- package/src/screens/inbox/components/ServiceDialogsListItem.tsx +337 -194
- package/src/screens/inbox/components/SlackInput.tsx +23 -0
- package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +233 -23
- package/src/screens/inbox/components/SlackMessageContainer/SlackMessage.tsx +1 -1
- package/src/screens/inbox/components/SmartLoader.tsx +61 -0
- package/src/screens/inbox/components/SubscriptionHandler.tsx +41 -0
- package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +53 -55
- package/src/screens/inbox/components/ThreadsViewItem.tsx +178 -285
- package/src/screens/inbox/components/workflow/dialogs-list-item-xstate.ts +145 -0
- package/src/screens/inbox/components/workflow/service-dialogs-list-item-xstate.ts +159 -0
- package/src/screens/inbox/config/config.ts +2 -2
- package/src/screens/inbox/containers/ConversationView.tsx +1843 -702
- package/src/screens/inbox/containers/ConversationView.tsx.bk +1467 -0
- package/src/screens/inbox/containers/Dialogs.tsx +402 -204
- package/src/screens/inbox/containers/SupportServiceDialogs.tsx +4 -4
- package/src/screens/inbox/containers/ThreadConversationView.tsx +1350 -319
- package/src/screens/inbox/containers/ThreadsView.tsx +105 -193
- package/src/screens/inbox/containers/workflow/apollo/handleResult.ts +20 -0
- package/src/screens/inbox/containers/workflow/conversation-xstate.ts +313 -0
- package/src/screens/inbox/containers/workflow/dialogs-xstate.ts +196 -0
- package/src/screens/inbox/containers/workflow/thread-conversation-xstate.ts +401 -0
- package/src/screens/inbox/hooks/useInboxMessages.ts +34 -0
- package/src/screens/inbox/hooks/useSafeDialogThreadsMachine.ts +136 -0
- package/src/screens/inbox/index.ts +37 -0
- package/src/screens/inbox/machines/threadsMachine.ts +147 -0
- package/src/screens/inbox/workflow/dialog-threads-xstate.ts +163 -0
- package/tsconfig.json +11 -54
- package/lib/screens/inbox/components/DialogsListItem.js +0 -171
- package/lib/screens/inbox/components/DialogsListItem.js.map +0 -1
- package/lib/screens/inbox/components/ServiceDialogsListItem.js +0 -171
- package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useMemo, useState } from 'react';
|
|
1
|
+
import React, { useMemo, useState, useCallback, useRef, useEffect } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Text,
|
|
4
4
|
Image,
|
|
@@ -15,13 +15,10 @@ 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
|
-
useMessagesQuery,
|
|
20
|
-
useOnChatMessageAddedSubscription,
|
|
21
|
-
OnChatMessageAddedDocument as CHAT_MESSAGE_ADDED,
|
|
22
|
-
useUserAccountQuery,
|
|
23
|
-
} from 'common/lib/generated/generated.js';
|
|
18
|
+
import { CHAT_MESSAGE_ADDED, useMessagesQuery as useMessagesQueryFromInbox } from '../../../queries/inboxQueries';
|
|
24
19
|
import { startCase } from 'lodash-es';
|
|
20
|
+
import colors from 'tailwindcss/colors';
|
|
21
|
+
import { SubscriptionHandler } from './SubscriptionHandler';
|
|
25
22
|
|
|
26
23
|
const createdAtText = (value: string) => {
|
|
27
24
|
if (!value) return '';
|
|
@@ -41,8 +38,56 @@ export interface IDialogListItemProps {
|
|
|
41
38
|
selectedChannelId?: any;
|
|
42
39
|
channel?: any;
|
|
43
40
|
onOpen: (id: any, title: any) => void;
|
|
41
|
+
forceRefresh?: boolean;
|
|
42
|
+
visible?: boolean;
|
|
44
43
|
}
|
|
45
44
|
|
|
45
|
+
// LastMessage component definition
|
|
46
|
+
const LastMessageComponent = ({ title, lastMessage }) => {
|
|
47
|
+
const count = 30;
|
|
48
|
+
const channelTitle = title?.slice(0, count) + (title?.length > count ? '...' : '') || '';
|
|
49
|
+
|
|
50
|
+
// Define message display text
|
|
51
|
+
let displayMessage = 'No messages yet';
|
|
52
|
+
|
|
53
|
+
if (lastMessage) {
|
|
54
|
+
if (lastMessage.message && lastMessage.message.trim() !== '') {
|
|
55
|
+
// Show text message
|
|
56
|
+
displayMessage = lastMessage.message;
|
|
57
|
+
} else if (lastMessage.files?.data?.length > 0) {
|
|
58
|
+
// Show message with files
|
|
59
|
+
displayMessage = '📎 File attachment';
|
|
60
|
+
} else {
|
|
61
|
+
// Default for empty message
|
|
62
|
+
displayMessage = '(Empty message)';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Determine the date/time to display
|
|
67
|
+
const displayDate = lastMessage?.createdAt
|
|
68
|
+
? createdAtText(lastMessage.createdAt)
|
|
69
|
+
: lastMessage?.updatedAt
|
|
70
|
+
? createdAtText(lastMessage.updatedAt)
|
|
71
|
+
: '';
|
|
72
|
+
|
|
73
|
+
return (
|
|
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>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
46
91
|
/**
|
|
47
92
|
* TODO:
|
|
48
93
|
* - Get Reservation info: reservation date, status
|
|
@@ -50,249 +95,268 @@ export interface IDialogListItemProps {
|
|
|
50
95
|
*/
|
|
51
96
|
export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function DialogsListItem({
|
|
52
97
|
currentUser,
|
|
53
|
-
// users,
|
|
54
98
|
selectedChannelId,
|
|
55
99
|
channel,
|
|
56
100
|
onOpen,
|
|
101
|
+
forceRefresh,
|
|
102
|
+
visible = true,
|
|
57
103
|
}) {
|
|
104
|
+
// Create a ref to track if component is mounted
|
|
105
|
+
const isMountedRef = useRef(true);
|
|
106
|
+
|
|
107
|
+
// Define parentId early to avoid linter errors
|
|
58
108
|
const parentId: any = null;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
109
|
+
|
|
110
|
+
// Simplified state - only keep loading state, rely on Apollo cache for data
|
|
111
|
+
const [loading, setLoading] = useState(false);
|
|
112
|
+
const [title, setTitle] = useState('');
|
|
113
|
+
|
|
114
|
+
// Only run queries/subscriptions if visible
|
|
115
|
+
const shouldQuery = !!channel?.id && visible;
|
|
116
|
+
|
|
117
|
+
// Memoize query variables to prevent unnecessary re-renders
|
|
118
|
+
const queryVariables = useMemo(
|
|
119
|
+
() => ({
|
|
67
120
|
channelId: channel?.id?.toString(),
|
|
68
121
|
parentId: parentId,
|
|
69
122
|
limit: 10,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
+
}
|
|
75
162
|
},
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
163
|
+
[shouldQuery, channel?.id, queryVariables],
|
|
164
|
+
);
|
|
79
165
|
|
|
166
|
+
// Query hooks for fetching messages - optimized configuration
|
|
80
167
|
const {
|
|
81
|
-
data:
|
|
82
|
-
loading:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
168
|
+
data: messagesQuery,
|
|
169
|
+
loading: messageLoading,
|
|
170
|
+
refetch: refetchMessages,
|
|
171
|
+
subscribeToMore,
|
|
172
|
+
error,
|
|
173
|
+
} = useMessagesQueryFromInbox({
|
|
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
|
|
180
|
+
onCompleted: (data) => {
|
|
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}`);
|
|
185
|
+
},
|
|
186
|
+
onError: (error) => {
|
|
187
|
+
if (!shouldQuery) return;
|
|
188
|
+
console.error(`Query error for channel ${channel?.id}:`, error);
|
|
87
189
|
},
|
|
88
190
|
});
|
|
89
191
|
|
|
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]);
|
|
195
|
+
|
|
196
|
+
// Set mounted state on mount/unmount
|
|
197
|
+
useEffect(() => {
|
|
198
|
+
isMountedRef.current = true;
|
|
199
|
+
return () => {
|
|
200
|
+
isMountedRef.current = false;
|
|
201
|
+
};
|
|
202
|
+
}, []);
|
|
203
|
+
|
|
204
|
+
// Optimized focus effect - single refetch with debouncing
|
|
205
|
+
const firstRenderRef = useRef(true);
|
|
90
206
|
useFocusEffect(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
parentId: parentId,
|
|
96
|
-
limit: 10,
|
|
97
|
-
// sort: {
|
|
98
|
-
// key: 'updatedAt',
|
|
99
|
-
// value: SortEnum.Desc,
|
|
100
|
-
// },
|
|
101
|
-
//limit: 25
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
return () => {
|
|
105
|
-
// Do something when the screen is unfocused
|
|
106
|
-
// Useful for cleanup functions
|
|
107
|
-
};
|
|
108
|
-
}, []),
|
|
109
|
-
);
|
|
207
|
+
useCallback(() => {
|
|
208
|
+
if (!channel?.id) return;
|
|
209
|
+
|
|
210
|
+
console.log('DialogsListItem focused for channel:', channel?.id);
|
|
110
211
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
setMessages((pre: any[]) => [...pre, ...msg]);
|
|
212
|
+
// Skip refresh on first render
|
|
213
|
+
if (firstRenderRef.current) {
|
|
214
|
+
firstRenderRef.current = false;
|
|
215
|
+
return;
|
|
116
216
|
}
|
|
117
|
-
}
|
|
118
|
-
}, [messagesQuery]);
|
|
119
217
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
218
|
+
// Debounced refetch on focus
|
|
219
|
+
const timeoutId = setTimeout(() => {
|
|
220
|
+
optimizedRefetch('focus');
|
|
221
|
+
}, 100);
|
|
222
|
+
|
|
223
|
+
return () => clearTimeout(timeoutId);
|
|
224
|
+
}, [channel?.id, optimizedRefetch]),
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
// Simplified effect for force refresh
|
|
228
|
+
useEffect(() => {
|
|
229
|
+
if (forceRefresh && shouldQuery) {
|
|
230
|
+
const timeoutId = setTimeout(() => {
|
|
231
|
+
optimizedRefetch('force');
|
|
232
|
+
}, 50);
|
|
233
|
+
return () => clearTimeout(timeoutId);
|
|
123
234
|
}
|
|
124
|
-
|
|
125
|
-
const data = messages;
|
|
126
|
-
const filteredData: any = data?.filter((p: any) => p?.message !== '');
|
|
127
|
-
// return filteredData[0];
|
|
128
|
-
let filteredLastMessage =
|
|
129
|
-
filteredData && filteredData?.length
|
|
130
|
-
? filteredData?.reduce((a, b) => {
|
|
131
|
-
return new Date(a?.updatedAt) > new Date(b?.updatedAt) ? a : b;
|
|
132
|
-
}, []) ?? null
|
|
133
|
-
: null;
|
|
134
|
-
return filteredLastMessage;
|
|
135
|
-
//return data[data.length - 1];
|
|
136
|
-
}, [messages]);
|
|
235
|
+
}, [forceRefresh, shouldQuery, optimizedRefetch]);
|
|
137
236
|
|
|
237
|
+
// Channel members computation - optimized with better memoization
|
|
138
238
|
const channelMembers = useMemo(
|
|
139
239
|
() =>
|
|
140
240
|
channel?.members
|
|
141
|
-
?.filter((ch: any) => ch?.user?.id
|
|
142
|
-
?.map((m: any) => m?.user) ??
|
|
143
|
-
[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],
|
|
144
244
|
);
|
|
145
245
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
246
|
+
// Set title when channel members change
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
if (channelMembers.length > 0 && isMountedRef.current) {
|
|
249
|
+
const titleString =
|
|
250
|
+
channelMembers
|
|
251
|
+
?.map((u: any) => `${u?.givenName || ''} ${u?.familyName || ''}`.trim())
|
|
252
|
+
?.filter(Boolean)
|
|
253
|
+
?.join(', ') || '';
|
|
254
|
+
setTitle(titleString);
|
|
255
|
+
}
|
|
256
|
+
}, [channelMembers]);
|
|
152
257
|
|
|
258
|
+
// Compute title with proper truncation
|
|
259
|
+
const displayTitle = useMemo(() => {
|
|
153
260
|
const length = 30;
|
|
154
|
-
return
|
|
155
|
-
}, [
|
|
261
|
+
return title.length > length ? title.substring(0, length - 3) + '...' : title;
|
|
262
|
+
}, [title]);
|
|
263
|
+
|
|
264
|
+
// Combined loading state
|
|
265
|
+
const isLoading = loading || messageLoading;
|
|
156
266
|
|
|
157
267
|
return (
|
|
158
268
|
<Pressable
|
|
159
|
-
onPress={() =>
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
borderColor={'$trueGray200'}
|
|
163
|
-
flex={1}
|
|
164
|
-
$dark-borderColor="$coolGray600"
|
|
165
|
-
$dark-backgroundColor="$trueGray700"
|
|
166
|
-
$light-backgroundColor="$trueGray50"
|
|
167
|
-
$light-borderColor="$trueGray200"
|
|
269
|
+
onPress={() => onOpen(channel?.id, displayTitle)}
|
|
270
|
+
className="flex-1 border-gray-200 rounded-md dark:border-gray-600 dark:bg-gray-700"
|
|
271
|
+
style={{ borderBottomWidth: 1, borderColor: '#e5e7eb', marginVertical: 0, paddingHorizontal: 10 }}
|
|
168
272
|
>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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">
|
|
306
|
+
<Box className="flex-[0.1] items-start pl-3">
|
|
181
307
|
<AvatarGroup>
|
|
182
308
|
{channelMembers &&
|
|
183
309
|
channelMembers?.length > 0 &&
|
|
184
|
-
channelMembers?.slice(0,
|
|
310
|
+
channelMembers?.slice(0, 1)?.map((ch: any, i: Number) => (
|
|
185
311
|
<Avatar
|
|
186
312
|
key={'dialogs-list-' + i}
|
|
187
|
-
bg={'transparent'}
|
|
188
313
|
size={'sm'}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
314
|
+
className={`bg-transparent top-[${i == 1 ? '4' : '0'}] right-[${
|
|
315
|
+
i == 1 ? '-2' : '0'
|
|
316
|
+
}] z-[${i == 1 ? 5 : 1}]`}
|
|
192
317
|
>
|
|
193
318
|
<AvatarFallbackText>{startCase(ch?.username?.charAt(0))}</AvatarFallbackText>
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
319
|
+
{channelMembers?.length > 1 && (
|
|
320
|
+
<AvatarBadge
|
|
321
|
+
style={{
|
|
322
|
+
width: '100%',
|
|
323
|
+
height: '100%',
|
|
324
|
+
backgroundColor: '#e5e7eb',
|
|
325
|
+
borderRadius: 5,
|
|
326
|
+
}}
|
|
327
|
+
className="items-center justify-center bg-gray-200 rounded-md"
|
|
328
|
+
>
|
|
329
|
+
<Text style={{ fontSize: 12, fontWeight: 'bold', color: '#000' }}>
|
|
330
|
+
{channelMembers?.length}
|
|
331
|
+
</Text>
|
|
332
|
+
</AvatarBadge>
|
|
333
|
+
)}
|
|
201
334
|
{channelMembers?.length == 1 && (
|
|
202
|
-
|
|
335
|
+
<>
|
|
336
|
+
<AvatarImage
|
|
337
|
+
alt="user image"
|
|
338
|
+
style={{ borderRadius: 6, borderWidth: 2, borderColor: '#fff' }}
|
|
339
|
+
source={{
|
|
340
|
+
uri: ch?.picture,
|
|
341
|
+
}}
|
|
342
|
+
/>
|
|
343
|
+
<AvatarBadge style={{ width: 10, height: 10 }} />
|
|
344
|
+
</>
|
|
203
345
|
)}
|
|
204
346
|
</Avatar>
|
|
205
347
|
))}
|
|
206
348
|
</AvatarGroup>
|
|
207
349
|
</Box>
|
|
208
|
-
<Box flex
|
|
209
|
-
{/* <HStack space={1} flex={1} direction={'row'} justifyContent={'center'} alignItems={'center'}>
|
|
210
|
-
<Box flex={0.8}>
|
|
211
|
-
<Text color="gray.600" fontSize="lg" flexWrap={'wrap'} fontWeight="semibold">
|
|
212
|
-
{title}
|
|
213
|
-
</Text>
|
|
214
|
-
<Text color="gray.600" noOfLines={1}>
|
|
215
|
-
{lastMessage?.message ?? ''}
|
|
216
|
-
</Text>
|
|
217
|
-
</Box>
|
|
218
|
-
|
|
219
|
-
<Box flex={0.2}>
|
|
220
|
-
<Text color="gray.500">{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
|
|
221
|
-
</Box>
|
|
222
|
-
</HStack> */}
|
|
350
|
+
<Box className="flex-1">
|
|
223
351
|
<LastMessageComponent
|
|
224
|
-
|
|
352
|
+
key={`last-msg-${lastMessage?.id || 'none'}-${messages.length}`}
|
|
353
|
+
title={displayTitle}
|
|
225
354
|
lastMessage={lastMessage}
|
|
226
|
-
channelId={channel?.id}
|
|
227
|
-
subscribeToNewMessages={() =>
|
|
228
|
-
subscribeToMore({
|
|
229
|
-
document: CHAT_MESSAGE_ADDED,
|
|
230
|
-
variables: {
|
|
231
|
-
channelId: channel.id?.toString(),
|
|
232
|
-
},
|
|
233
|
-
updateQuery: (prev, { subscriptionData }: any) => {
|
|
234
|
-
if (!subscriptionData.data) return prev;
|
|
235
|
-
const newMessage: any = subscriptionData?.data?.chatMessageAdded;
|
|
236
|
-
const existingMessages: any = prev?.messages;
|
|
237
|
-
const previousData = existingMessages?.data
|
|
238
|
-
? [...existingMessages.data, newMessage]
|
|
239
|
-
: [];
|
|
240
|
-
const totalMsgCount = existingMessages?.totalCount + 1;
|
|
241
|
-
const merged = {
|
|
242
|
-
...prev,
|
|
243
|
-
messages: {
|
|
244
|
-
...existingMessages,
|
|
245
|
-
data: previousData,
|
|
246
|
-
totalCount: totalMsgCount,
|
|
247
|
-
},
|
|
248
|
-
};
|
|
249
|
-
return merged;
|
|
250
|
-
},
|
|
251
|
-
})
|
|
252
|
-
}
|
|
253
355
|
/>
|
|
254
|
-
{/* <Text
|
|
255
|
-
flex={1}
|
|
256
|
-
color="gray.600"
|
|
257
|
-
p={0}
|
|
258
|
-
m={0}
|
|
259
|
-
w={'100%'}
|
|
260
|
-
justifyContent={''}
|
|
261
|
-
fontSize="lg"
|
|
262
|
-
fontWeight="semibold"
|
|
263
|
-
>
|
|
264
|
-
{title}
|
|
265
|
-
</Text> */}
|
|
266
|
-
{/* <Text flex={0.1} color="gray.600">
|
|
267
|
-
{lastMessage?.message ?? ''}
|
|
268
|
-
</Text> */}
|
|
269
356
|
</Box>
|
|
270
|
-
{/* <Text flex={0.2} color="gray.500">
|
|
271
|
-
{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}
|
|
272
|
-
</Text> */}
|
|
273
357
|
</HStack>
|
|
274
358
|
</Pressable>
|
|
275
359
|
);
|
|
276
360
|
};
|
|
277
361
|
|
|
278
|
-
const LastMessageComponent = ({ subscribeToNewMessages, title, lastMessage, channelId }) => {
|
|
279
|
-
React.useEffect(() => subscribeToNewMessages(), [channelId]);
|
|
280
|
-
return (
|
|
281
|
-
<HStack space={'sm'} flex={1} justifyContent={'center'} alignItems={'center'}>
|
|
282
|
-
<Box flex={0.8}>
|
|
283
|
-
<Text color="$trueGray600" fontSize="$lg" flexWrap={'wrap'} fontWeight="$semibold">
|
|
284
|
-
{title}
|
|
285
|
-
</Text>
|
|
286
|
-
<Text color="$trueGray600" numberOfLines={1}>
|
|
287
|
-
{lastMessage?.message ?? ''}
|
|
288
|
-
</Text>
|
|
289
|
-
</Box>
|
|
290
|
-
|
|
291
|
-
<Box flex={0.2}>
|
|
292
|
-
<Text color="$trueGray500">{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
|
|
293
|
-
</Box>
|
|
294
|
-
</HStack>
|
|
295
|
-
);
|
|
296
|
-
};
|
|
297
|
-
|
|
298
362
|
export const DialogsListItem = React.memo(DialogsListItemComponent);
|