@messenger-box/platform-mobile 10.0.3-alpha.22 → 10.0.3-alpha.23
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/screens/inbox/DialogThreads.js +52 -12
- package/lib/screens/inbox/DialogThreads.js.map +1 -1
- package/lib/screens/inbox/components/ThreadsViewItem.js +66 -44
- package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
- package/lib/screens/inbox/containers/ConversationView.js +36 -34
- package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/Dialogs.js +82 -37
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadConversationView.js +282 -219
- 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/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 +2 -2
- package/src/screens/inbox/DialogThreads.tsx +49 -53
- package/src/screens/inbox/components/SmartLoader.tsx +61 -0
- package/src/screens/inbox/components/ThreadsViewItem.tsx +177 -265
- package/src/screens/inbox/containers/ConversationView.tsx +32 -30
- package/src/screens/inbox/containers/Dialogs.tsx +57 -22
- package/src/screens/inbox/containers/ThreadConversationView.tsx +467 -484
- package/src/screens/inbox/containers/ThreadsView.tsx +102 -183
- 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
|
@@ -2,51 +2,47 @@ import React, { useMemo } from 'react';
|
|
|
2
2
|
import {
|
|
3
3
|
VStack,
|
|
4
4
|
Text,
|
|
5
|
-
Image,
|
|
6
5
|
Pressable,
|
|
7
6
|
HStack,
|
|
8
7
|
Box,
|
|
9
|
-
AvatarGroup,
|
|
10
8
|
Avatar,
|
|
11
9
|
AvatarFallbackText,
|
|
12
10
|
AvatarImage,
|
|
13
|
-
AvatarBadge,
|
|
14
|
-
View,
|
|
15
11
|
Button,
|
|
16
12
|
ButtonText,
|
|
13
|
+
Icon,
|
|
14
|
+
Badge,
|
|
15
|
+
BadgeText,
|
|
16
|
+
Link,
|
|
17
|
+
LinkText,
|
|
17
18
|
} from '@admin-layout/gluestack-ui-mobile';
|
|
18
19
|
import { format, isToday, isYesterday } from 'date-fns';
|
|
19
20
|
import { useFocusEffect } from '@react-navigation/native';
|
|
20
21
|
import { IChannel, IUserAccount } from 'common';
|
|
21
|
-
import {
|
|
22
|
-
useThreadMessagesQuery,
|
|
23
|
-
useMessagesQuery,
|
|
24
|
-
useUserAccountQuery,
|
|
25
|
-
useOnThreadChatMessageAddedSubscription,
|
|
26
|
-
useOnThreadCreatedUpdatedSubscription,
|
|
27
|
-
} from 'common/graphql';
|
|
28
22
|
import { startCase } from 'lodash-es';
|
|
29
23
|
import colors from 'tailwindcss/colors';
|
|
24
|
+
import { useSelector } from 'react-redux';
|
|
25
|
+
import { userSelector } from '@adminide-stack/user-auth0-client';
|
|
30
26
|
|
|
31
|
-
const
|
|
27
|
+
const timeFormat = (value: string) => {
|
|
32
28
|
if (!value) return '';
|
|
33
29
|
let date = new Date(value);
|
|
34
|
-
if (isToday(date)) return '
|
|
35
|
-
|
|
36
|
-
return format(new Date(value), 'MMM dd, yyyy');
|
|
30
|
+
if (isToday(date)) return format(date, 'h:mm a').toUpperCase();
|
|
31
|
+
return format(date, 'MMM do').toUpperCase();
|
|
37
32
|
};
|
|
38
33
|
|
|
39
34
|
export interface IDialogListChannel extends IChannel {
|
|
40
35
|
users: IUserAccount[];
|
|
41
36
|
}
|
|
42
37
|
|
|
43
|
-
export interface
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
export interface ThreadViewItemProps {
|
|
39
|
+
id: string;
|
|
40
|
+
post: any;
|
|
41
|
+
channel: any;
|
|
42
|
+
replies: any[];
|
|
43
|
+
onPress: (id: any, title: any, postParentId?: any) => void;
|
|
44
|
+
channelId?: string;
|
|
45
|
+
channelsDetail?: any;
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
/**
|
|
@@ -54,267 +50,183 @@ export interface IDialogListItemProps {
|
|
|
54
50
|
* - Get Reservation info: reservation date, status
|
|
55
51
|
* - Add ability to get property information: name, logo
|
|
56
52
|
*/
|
|
57
|
-
export const ThreadViewItemComponent: React.FC<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
export const ThreadViewItemComponent: React.FC<ThreadViewItemProps> = function ThreadViewItem({
|
|
54
|
+
id,
|
|
55
|
+
post,
|
|
56
|
+
channel,
|
|
57
|
+
replies,
|
|
58
|
+
onPress,
|
|
59
|
+
channelId,
|
|
60
|
+
channelsDetail,
|
|
64
61
|
}) {
|
|
65
|
-
|
|
66
|
-
// variables: {
|
|
67
|
-
// channelId: thread?.channel?.id?.toString(),
|
|
68
|
-
// postParentId: thread?.post?.id?.toString(),
|
|
69
|
-
// },
|
|
70
|
-
// });
|
|
71
|
-
|
|
72
|
-
useFocusEffect(
|
|
73
|
-
React.useCallback(() => {
|
|
74
|
-
// Do something when the screen is focused
|
|
75
|
-
return () => {
|
|
76
|
-
// Do something when the screen is unfocused
|
|
77
|
-
// Useful for cleanup functions
|
|
78
|
-
};
|
|
79
|
-
}, []),
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
const threadPostReply = React.useMemo(() => {
|
|
83
|
-
if (!thread?.replies) return null;
|
|
84
|
-
return thread?.replies;
|
|
85
|
-
}, [thread]);
|
|
62
|
+
const currentUser = useSelector(userSelector);
|
|
86
63
|
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
64
|
+
// Prepare thread replies for display
|
|
65
|
+
const threadReplies = useMemo(() => {
|
|
66
|
+
return replies || [];
|
|
67
|
+
}, [replies]);
|
|
90
68
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// return threadCreatedUpdated?.threadCreatedUpdated?.data?.replies;
|
|
95
|
-
// } else return thread?.replies;
|
|
96
|
-
// }, [thread, threadCreatedUpdated]);
|
|
97
|
-
|
|
98
|
-
// const lastMessage = useMemo(() => {
|
|
99
|
-
// if (!threadPost) {
|
|
100
|
-
// return null;
|
|
101
|
-
// }
|
|
102
|
-
// const replies = threadPost?.replies?.filter((p: any) => p?.message !== '') ?? [];
|
|
103
|
-
// if (replies?.length) {
|
|
104
|
-
// return replies[0];
|
|
105
|
-
// // return replies[replies.length - 1];
|
|
106
|
-
// } else {
|
|
107
|
-
// const post = threadPost?.post ?? null;
|
|
108
|
-
// return post ? post?.post : null;
|
|
109
|
-
// }
|
|
110
|
-
// }, [threadPost]);
|
|
69
|
+
if (!threadReplies || threadReplies.length === 0) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
111
72
|
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
|
|
73
|
+
// Get the last reply for the thread preview
|
|
74
|
+
const lastReply = threadReplies[0]; // Most recent reply should be first in the array
|
|
75
|
+
// Get total number of replies
|
|
76
|
+
const totalReplies = threadReplies.length;
|
|
116
77
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// participants
|
|
121
|
-
// ?.map((p: any) => {
|
|
122
|
-
// return p?.user?.givenName + ' ' + p?.user?.familyName ?? '';
|
|
123
|
-
// })
|
|
124
|
-
// ?.join(', ') ?? ''
|
|
125
|
-
// );
|
|
126
|
-
// }, [participants]);
|
|
78
|
+
// Get the first user in the thread as the primary user
|
|
79
|
+
const primaryUser = channel?.users?.[0] || lastReply?.author;
|
|
80
|
+
const channelName = channel?.title || `${primaryUser?.givenName || ''} ${primaryUser?.familyName || ''}`;
|
|
127
81
|
|
|
128
|
-
if
|
|
129
|
-
|
|
130
|
-
}
|
|
82
|
+
// Determine if the current user is in the thread
|
|
83
|
+
const userIsInThread = channel?.users?.some((user: any) => user.id === currentUser?.id);
|
|
131
84
|
|
|
132
85
|
return (
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
86
|
+
<Pressable
|
|
87
|
+
onPress={() => onPress(channel?.id, 'Thread', post?.id)}
|
|
88
|
+
style={{
|
|
89
|
+
marginVertical: 5,
|
|
90
|
+
backgroundColor: 'white',
|
|
91
|
+
borderRadius: 10,
|
|
92
|
+
paddingVertical: 5,
|
|
93
|
+
elevation: 1,
|
|
94
|
+
shadowColor: '#000',
|
|
95
|
+
shadowOffset: { width: 0, height: 1 },
|
|
96
|
+
shadowOpacity: 0.1,
|
|
97
|
+
shadowRadius: 2,
|
|
98
|
+
}}
|
|
136
99
|
>
|
|
137
|
-
<
|
|
138
|
-
<
|
|
139
|
-
{/*
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
</Text>
|
|
147
|
-
</Box>
|
|
100
|
+
<Box className="mb-3">
|
|
101
|
+
<VStack space="md">
|
|
102
|
+
{/* Thread header with green dot and users */}
|
|
103
|
+
{/* <HStack space="sm" className="px-4 items-center">
|
|
104
|
+
<Box
|
|
105
|
+
className="bg-green-500 rounded-full"
|
|
106
|
+
style={{ width: 8, height: 8 }}
|
|
107
|
+
/>
|
|
108
|
+
<Text className="text-base text-gray-900">{channelName}</Text>
|
|
148
109
|
</HStack> */}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
110
|
+
|
|
111
|
+
{/* Thread members */}
|
|
112
|
+
<Text className="text-sm font-medium text-gray-600 px-4 pt-2">
|
|
113
|
+
{channel?.users?.map((user: any) => user?.givenName || user?.username)?.join(', ')}
|
|
114
|
+
</Text>
|
|
115
|
+
|
|
116
|
+
{/* Thread messages preview - show up to 3 most recent messages */}
|
|
117
|
+
{threadReplies.slice(0, 3).map((reply: any, index: number) => {
|
|
118
|
+
// Group consecutive messages from the same user
|
|
119
|
+
const previousReply = index > 0 ? threadReplies.slice(0, 3)[index - 1] : null;
|
|
120
|
+
const isConsecutiveReply = previousReply && previousReply.author?.id === reply.author?.id;
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<HStack key={reply.id || index} space="md" className="px-4 py-1">
|
|
124
|
+
{!isConsecutiveReply ? (
|
|
153
125
|
<Avatar
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
126
|
+
size="md"
|
|
127
|
+
style={{
|
|
128
|
+
width: 40,
|
|
129
|
+
height: 40,
|
|
130
|
+
backgroundColor:
|
|
131
|
+
reply?.author?.id === currentUser?.id ? '#2EB67D' : '#E8A54A',
|
|
159
132
|
}}
|
|
160
133
|
>
|
|
161
|
-
|
|
134
|
+
<AvatarFallbackText>
|
|
135
|
+
{startCase(reply?.author?.username?.charAt(0) || 'U')}
|
|
136
|
+
</AvatarFallbackText>
|
|
137
|
+
{reply?.author?.picture && (
|
|
138
|
+
<AvatarImage
|
|
139
|
+
alt={reply?.author?.username || 'User'}
|
|
140
|
+
source={{
|
|
141
|
+
uri: reply?.author?.picture,
|
|
142
|
+
}}
|
|
143
|
+
/>
|
|
144
|
+
)}
|
|
162
145
|
</Avatar>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
{!thread?.replies?.length && (
|
|
178
|
-
<Button
|
|
179
|
-
size={'xs'}
|
|
180
|
-
w={150}
|
|
181
|
-
variant={'outline'}
|
|
182
|
-
_text={{ fontSize: 12, color: '#000' }}
|
|
183
|
-
onPress={() =>
|
|
184
|
-
onOpen(thread?.channel?.id, thread?.channel?.title, thread?.post?.id)
|
|
185
|
-
}
|
|
186
|
-
>
|
|
187
|
-
Reply
|
|
188
|
-
</Button>
|
|
146
|
+
) : (
|
|
147
|
+
<Box style={{ width: 40 }} />
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
<VStack space="xs" className="flex-1">
|
|
151
|
+
{!isConsecutiveReply && (
|
|
152
|
+
<HStack space="sm" className="items-center">
|
|
153
|
+
<Text className="font-bold text-gray-900">
|
|
154
|
+
{reply?.author?.givenName || reply?.author?.username || 'User'}
|
|
155
|
+
</Text>
|
|
156
|
+
<Text className="text-xs text-gray-500">
|
|
157
|
+
{timeFormat(reply?.createdAt)}
|
|
158
|
+
</Text>
|
|
159
|
+
</HStack>
|
|
189
160
|
)}
|
|
190
|
-
</Box>
|
|
191
|
-
</HStack> */}
|
|
192
|
-
{threadPostReply?.length > 0 && (
|
|
193
|
-
<>
|
|
194
|
-
{threadPostReply
|
|
195
|
-
?.slice(0, 2)
|
|
196
|
-
?.reverse()
|
|
197
|
-
?.map((reply: any, index: any) => (
|
|
198
|
-
<HStack key={index} space={'sm'} className="pb-2 pt-1">
|
|
199
|
-
<Box>
|
|
200
|
-
<Avatar
|
|
201
|
-
key={'thread-view-key-' + index}
|
|
202
|
-
size={'md'}
|
|
203
|
-
className="bg-transparent top-0 right-0 z-[1]"
|
|
204
|
-
>
|
|
205
|
-
<AvatarFallbackText>
|
|
206
|
-
{' '}
|
|
207
|
-
{startCase(reply?.author?.username?.charAt(0))}
|
|
208
|
-
</AvatarFallbackText>
|
|
209
|
-
<AvatarImage
|
|
210
|
-
alt="image"
|
|
211
|
-
style={{
|
|
212
|
-
borderRadius: 6,
|
|
213
|
-
borderWidth: 2,
|
|
214
|
-
borderColor: '#fff',
|
|
215
|
-
}}
|
|
216
|
-
source={{
|
|
217
|
-
uri: reply?.author?.picture,
|
|
218
|
-
}}
|
|
219
|
-
/>
|
|
220
|
-
</Avatar>
|
|
221
|
-
</Box>
|
|
222
|
-
<Box>
|
|
223
|
-
<HStack space={'md'}>
|
|
224
|
-
<Text>
|
|
225
|
-
{reply?.author?.givenName ?? '' ?? ''}{' '}
|
|
226
|
-
{reply?.author?.familyName ?? '' ?? ''}
|
|
227
|
-
{/* {lastMessage?.author?.givenName +
|
|
228
|
-
' ' +
|
|
229
|
-
lastMessage?.author?.familyName ?? ''} */}
|
|
230
|
-
</Text>
|
|
231
|
-
<Text color={colors.gray[500]}>
|
|
232
|
-
{reply?.createdAt ? createdAtText(reply?.createdAt) : ''}
|
|
233
|
-
{/* {lastMessage ? createdAtText(lastMessage?.createdAt) : ''} */}
|
|
234
|
-
</Text>
|
|
235
|
-
</HStack>
|
|
236
|
-
<VStack space={'sm'}>
|
|
237
|
-
{reply?.message && (
|
|
238
|
-
<Text color={colors.gray[600]} numberOfLines={2}>
|
|
239
|
-
{reply?.message.length < 70
|
|
240
|
-
? `${reply?.message}`
|
|
241
|
-
: `${reply?.message.substring(0, 68)}....`}
|
|
242
|
-
</Text>
|
|
243
|
-
)}
|
|
244
|
-
{/* <Text color="gray.600" noOfLines={2}>
|
|
245
|
-
{reply?.message
|
|
246
|
-
? reply?.message.length < 70
|
|
247
|
-
? `${reply?.message}`
|
|
248
|
-
: `${reply?.message.substring(0, 68)}....`
|
|
249
|
-
: ''}
|
|
250
|
-
</Text> */}
|
|
251
161
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
className="bg-transparent"
|
|
259
|
-
size={'md'}
|
|
260
|
-
>
|
|
261
|
-
<AvatarFallbackText> I</AvatarFallbackText>
|
|
262
|
-
<AvatarImage
|
|
263
|
-
alt="image"
|
|
264
|
-
style={{
|
|
265
|
-
borderRadius: 6,
|
|
266
|
-
borderWidth: 2,
|
|
267
|
-
borderColor: '#fff',
|
|
268
|
-
}}
|
|
269
|
-
source={{
|
|
270
|
-
uri: f?.url,
|
|
271
|
-
}}
|
|
272
|
-
/>
|
|
273
|
-
</Avatar>
|
|
274
|
-
</Box>
|
|
275
|
-
))}
|
|
276
|
-
</>
|
|
277
|
-
</VStack>
|
|
162
|
+
{reply?.message && (
|
|
163
|
+
<Text color={colors.gray[700]} numberOfLines={2} className="text-base">
|
|
164
|
+
{reply?.message}
|
|
165
|
+
{reply?.edited && <Text className="text-xs text-gray-500"> (edited)</Text>}
|
|
166
|
+
</Text>
|
|
167
|
+
)}
|
|
278
168
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
169
|
+
{reply.email && <Text className="text-blue-500">{reply.email}</Text>}
|
|
170
|
+
|
|
171
|
+
{reply?.files?.data?.length > 0 && (
|
|
172
|
+
<HStack space="sm" className="my-1">
|
|
173
|
+
{reply?.files?.data?.map((file: any, fileIndex: number) => (
|
|
174
|
+
<Box
|
|
175
|
+
key={fileIndex}
|
|
176
|
+
className="overflow-hidden"
|
|
177
|
+
style={{ width: 80, height: 80 }}
|
|
178
|
+
>
|
|
179
|
+
<AvatarImage
|
|
180
|
+
alt="attachment"
|
|
181
|
+
className="rounded-none border-none"
|
|
182
|
+
style={{
|
|
183
|
+
width: '100%',
|
|
184
|
+
height: '100%',
|
|
185
|
+
}}
|
|
186
|
+
source={{
|
|
187
|
+
uri: file?.url,
|
|
188
|
+
}}
|
|
189
|
+
/>
|
|
297
190
|
</Box>
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
191
|
+
))}
|
|
192
|
+
</HStack>
|
|
193
|
+
)}
|
|
194
|
+
</VStack>
|
|
195
|
+
</HStack>
|
|
196
|
+
);
|
|
197
|
+
})}
|
|
198
|
+
|
|
199
|
+
{/* Show more replies indicator */}
|
|
200
|
+
{totalReplies > 3 && (
|
|
201
|
+
<HStack className="px-4 items-center" space="sm">
|
|
202
|
+
<Box style={{ width: 40 }} />
|
|
203
|
+
<Link onPress={() => onPress(channel?.id, 'Thread', post?.id)}>
|
|
204
|
+
<LinkText className="text-blue-600 mt-1">
|
|
205
|
+
{totalReplies - 3} more {totalReplies - 3 === 1 ? 'reply' : 'replies'}
|
|
206
|
+
</LinkText>
|
|
207
|
+
</Link>
|
|
208
|
+
</HStack>
|
|
209
|
+
)}
|
|
210
|
+
|
|
211
|
+
{/* Reply button */}
|
|
212
|
+
<Box className="px-4 pb-2">
|
|
213
|
+
<Button
|
|
214
|
+
size="sm"
|
|
215
|
+
className="self-start rounded-full"
|
|
216
|
+
variant="outline"
|
|
217
|
+
style={{
|
|
218
|
+
borderColor: '#E2E8F0',
|
|
219
|
+
paddingHorizontal: 16,
|
|
220
|
+
paddingVertical: 6,
|
|
221
|
+
}}
|
|
222
|
+
onPress={() => onPress(channel?.id, 'Thread', post?.id)}
|
|
223
|
+
>
|
|
224
|
+
<ButtonText style={{ fontSize: 14, color: colors.gray[800] }}>Reply</ButtonText>
|
|
225
|
+
</Button>
|
|
226
|
+
</Box>
|
|
227
|
+
</VStack>
|
|
228
|
+
</Box>
|
|
229
|
+
</Pressable>
|
|
318
230
|
);
|
|
319
231
|
};
|
|
320
232
|
|
|
@@ -1066,19 +1066,6 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
|
|
|
1066
1066
|
return [];
|
|
1067
1067
|
}
|
|
1068
1068
|
|
|
1069
|
-
// Log the first message for debugging
|
|
1070
|
-
if (state.context.channelMessages[0]) {
|
|
1071
|
-
const sampleMsg = state.context.channelMessages[0];
|
|
1072
|
-
console.log(
|
|
1073
|
-
'📷 Sample message files:',
|
|
1074
|
-
JSON.stringify({
|
|
1075
|
-
hasFiles: !!sampleMsg.files,
|
|
1076
|
-
fileCount: sampleMsg.files?.data?.length || 0,
|
|
1077
|
-
fileUrl: sampleMsg.files?.data?.[0]?.url || 'none',
|
|
1078
|
-
}),
|
|
1079
|
-
);
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
1069
|
// Use a more efficient approach - pre-filter messages once
|
|
1083
1070
|
const filteredMessages = uniqBy(state.context.channelMessages, ({ id }) => id);
|
|
1084
1071
|
|
|
@@ -1097,7 +1084,6 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
|
|
|
1097
1084
|
const fileData = msg.files.data[0];
|
|
1098
1085
|
if (fileData && fileData.url) {
|
|
1099
1086
|
imageUrl = fileData.url;
|
|
1100
|
-
console.log('📷 Found image URL for message', msg.id, ':', imageUrl);
|
|
1101
1087
|
}
|
|
1102
1088
|
}
|
|
1103
1089
|
|
|
@@ -1120,7 +1106,7 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
|
|
|
1120
1106
|
isShowThreadMessage,
|
|
1121
1107
|
};
|
|
1122
1108
|
});
|
|
1123
|
-
}, [state?.context?.channelMessages,
|
|
1109
|
+
}, [state?.context?.channelMessages, isShowThreadMessage]);
|
|
1124
1110
|
|
|
1125
1111
|
// Memoize the renderMessageText function
|
|
1126
1112
|
const renderMessageText = useCallback(
|
|
@@ -1592,8 +1578,8 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
|
|
|
1592
1578
|
|
|
1593
1579
|
lastProcessedMessageRef.current = newMessage.id;
|
|
1594
1580
|
|
|
1595
|
-
//
|
|
1596
|
-
|
|
1581
|
+
// Use a batch update strategy to avoid frequent re-renders
|
|
1582
|
+
queueMicrotask(() => {
|
|
1597
1583
|
safeSend({
|
|
1598
1584
|
type: ConversationActions.SET_CHANNEL_MESSAGES,
|
|
1599
1585
|
data: {
|
|
@@ -1604,7 +1590,7 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
|
|
|
1604
1590
|
totalCount: (prev?.messages?.totalCount || 0) + 1,
|
|
1605
1591
|
},
|
|
1606
1592
|
});
|
|
1607
|
-
}
|
|
1593
|
+
});
|
|
1608
1594
|
|
|
1609
1595
|
return {
|
|
1610
1596
|
...prev,
|
|
@@ -1632,7 +1618,7 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
|
|
|
1632
1618
|
// Add ref to track last processed message
|
|
1633
1619
|
const lastProcessedMessageRef = useRef(null);
|
|
1634
1620
|
|
|
1635
|
-
// Add optimized listViewProps to reduce re-renders
|
|
1621
|
+
// Add optimized listViewProps to reduce re-renders and improve list performance
|
|
1636
1622
|
const listViewProps = useMemo(
|
|
1637
1623
|
() => ({
|
|
1638
1624
|
onEndReached: onEndReached,
|
|
@@ -1640,8 +1626,10 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
|
|
|
1640
1626
|
onMomentumScrollBegin: onMomentumScrollBegin,
|
|
1641
1627
|
removeClippedSubviews: true, // Improve performance by unmounting components when not visible
|
|
1642
1628
|
initialNumToRender: 10, // Reduce initial render amount
|
|
1643
|
-
maxToRenderPerBatch:
|
|
1644
|
-
windowSize:
|
|
1629
|
+
maxToRenderPerBatch: 7, // Reduce number in each render batch
|
|
1630
|
+
windowSize: 7, // Reduce the window size
|
|
1631
|
+
updateCellsBatchingPeriod: 50, // Batch cell updates to improve scrolling
|
|
1632
|
+
keyExtractor: (item) => item._id, // Add explicit key extractor
|
|
1645
1633
|
}),
|
|
1646
1634
|
[onEndReached, onMomentumScrollBegin],
|
|
1647
1635
|
);
|
|
@@ -1712,13 +1700,9 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
|
|
|
1712
1700
|
safeSend({ type: ConversationActions.SET_MESSAGE_TEXT, data: { messageText: text } })
|
|
1713
1701
|
}
|
|
1714
1702
|
renderFooter={() =>
|
|
1715
|
-
safeContextProperty('loading') ? (
|
|
1716
|
-
<Spinner color={'#3b82f6'} />
|
|
1717
|
-
) : safeContextProperty('imageLoading') ? (
|
|
1703
|
+
safeContextProperty('loading') || safeContextProperty('imageLoading') ? (
|
|
1718
1704
|
<Spinner color={'#3b82f6'} />
|
|
1719
|
-
) :
|
|
1720
|
-
''
|
|
1721
|
-
)
|
|
1705
|
+
) : null
|
|
1722
1706
|
}
|
|
1723
1707
|
scrollToBottom
|
|
1724
1708
|
user={{
|
|
@@ -1775,8 +1759,26 @@ const ConversationViewComponent = ({ channelId: ChannelId, role, isShowThreadMes
|
|
|
1775
1759
|
};
|
|
1776
1760
|
|
|
1777
1761
|
const SubscriptionHandler = ({ subscribeToNewMessages, channelId }: ISubscriptionHandlerProps) => {
|
|
1778
|
-
|
|
1779
|
-
|
|
1762
|
+
// Use memo for the channelId dependency to prevent unnecessary subscriptions
|
|
1763
|
+
const channelIdRef = useRef(channelId);
|
|
1764
|
+
|
|
1765
|
+
useEffect(() => {
|
|
1766
|
+
if (channelId && channelId !== channelIdRef.current) {
|
|
1767
|
+
channelIdRef.current = channelId;
|
|
1768
|
+
console.log('Setting up subscription for channel:', channelId);
|
|
1769
|
+
return subscribeToNewMessages();
|
|
1770
|
+
}
|
|
1771
|
+
}, [channelId, subscribeToNewMessages]);
|
|
1772
|
+
|
|
1773
|
+
return null;
|
|
1780
1774
|
};
|
|
1781
1775
|
|
|
1782
|
-
|
|
1776
|
+
// Export with React.memo to prevent unnecessary re-renders
|
|
1777
|
+
export const ConversationView = React.memo(ConversationViewComponent, (prevProps, nextProps) => {
|
|
1778
|
+
// Only re-render if these critical props change
|
|
1779
|
+
return (
|
|
1780
|
+
prevProps.channelId === nextProps.channelId &&
|
|
1781
|
+
prevProps.role === nextProps.role &&
|
|
1782
|
+
prevProps.isShowThreadMessage === nextProps.isShowThreadMessage
|
|
1783
|
+
);
|
|
1784
|
+
});
|