@messenger-box/platform-mobile 10.0.3-alpha.16 → 10.0.3-alpha.162
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 +248 -0
- package/lib/compute.js +2 -3
- package/lib/compute.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/module.js.map +1 -1
- package/lib/queries/inboxQueries.js +65 -0
- package/lib/queries/inboxQueries.js.map +1 -0
- package/lib/routes.json +13 -1
- package/lib/screens/inbox/DialogMessages.js +5 -3
- package/lib/screens/inbox/DialogMessages.js.map +1 -1
- package/lib/screens/inbox/DialogThreadMessages.js +3 -7
- package/lib/screens/inbox/DialogThreadMessages.js.map +1 -1
- package/lib/screens/inbox/DialogThreads.js +57 -18
- package/lib/screens/inbox/DialogThreads.js.map +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/ImageViewerModal.js.map +1 -1
- package/lib/screens/inbox/components/SlackMessageContainer/PaymentMessage.js +197 -0
- package/lib/screens/inbox/components/SlackMessageContainer/PaymentMessage.js.map +1 -0
- package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +141 -31
- package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -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 -44
- 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 +1205 -432
- 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 +724 -207
- 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 +5 -5
- package/src/index.ts +2 -0
- 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 +2 -1
- package/src/screens/inbox/DialogThreadMessages.tsx +3 -11
- package/src/screens/inbox/DialogThreads.tsx +53 -60
- 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/DialogsListItem.tsx +230 -170
- 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 +330 -171
- package/src/screens/inbox/components/SlackInput.tsx +23 -0
- package/src/screens/inbox/components/SlackMessageContainer/PaymentMessage.tsx +199 -0
- package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +233 -23
- 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 +41 -24
- package/src/screens/inbox/components/ThreadsViewItem.tsx +177 -265
- 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 +2004 -698
- package/src/screens/inbox/containers/ConversationView.tsx.bk +1467 -0
- package/src/screens/inbox/containers/Dialogs.tsx +402 -196
- package/src/screens/inbox/containers/SupportServiceDialogs.tsx +2 -2
- package/src/screens/inbox/containers/ThreadConversationView.tsx +1337 -301
- package/src/screens/inbox/containers/ThreadsView.tsx +105 -186
- 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/lib/screens/inbox/components/DialogsListItem.js +0 -175
- package/lib/screens/inbox/components/DialogsListItem.js.map +0 -1
- package/lib/screens/inbox/components/ServiceDialogsListItem.js +0 -165
- package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +0 -1
|
@@ -1,36 +1,47 @@
|
|
|
1
|
-
import React, { useMemo } from 'react';
|
|
1
|
+
import React, { useMemo, useState, useCallback, useRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Text,
|
|
4
|
-
Image,
|
|
5
4
|
Pressable,
|
|
6
5
|
HStack,
|
|
7
6
|
Box,
|
|
8
|
-
AvatarGroup,
|
|
9
7
|
Avatar,
|
|
10
8
|
AvatarFallbackText,
|
|
11
9
|
AvatarImage,
|
|
12
|
-
AvatarBadge,
|
|
13
|
-
View,
|
|
14
10
|
} from '@admin-layout/gluestack-ui-mobile';
|
|
15
11
|
import { format, isToday, isYesterday } from 'date-fns';
|
|
16
12
|
import { useFocusEffect } from '@react-navigation/native';
|
|
17
13
|
import { IChannel, IUserAccount } from 'common';
|
|
18
|
-
import {
|
|
19
|
-
useOnThreadCreatedUpdatedSubscription,
|
|
20
|
-
useOnThreadChatMessageAddedSubscription,
|
|
21
|
-
useThreadMessagesQuery,
|
|
22
|
-
OnThreadCreatedUpdatedDocument as THREAD_CHAT_ADDED,
|
|
23
|
-
OnThreadChatMessageAddedDocument as CHAT_MESSAGE_ADDED,
|
|
24
|
-
} from 'common/graphql';
|
|
14
|
+
import { THREAD_CREATED_UPDATED, CHAT_MESSAGE_ADDED, useThreadMessagesQuery } from '../../../queries/inboxQueries';
|
|
25
15
|
import { startCase } from 'lodash-es';
|
|
26
16
|
import colors from 'tailwindcss/colors';
|
|
17
|
+
import { SubscriptionHandler } from './SubscriptionHandler';
|
|
18
|
+
|
|
19
|
+
// Helper function to safely create a Date object
|
|
20
|
+
const safeDate = (dateValue) => {
|
|
21
|
+
if (!dateValue) return null;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const date = new Date(dateValue);
|
|
25
|
+
// Check if the date is valid by seeing if it returns a valid time value
|
|
26
|
+
if (isNaN(date.getTime())) {
|
|
27
|
+
console.warn('Invalid date value detected:', dateValue);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return date;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.warn('Error creating date from value:', dateValue, error);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
27
36
|
|
|
28
37
|
const createdAtText = (value: string) => {
|
|
29
38
|
if (!value) return '';
|
|
30
|
-
|
|
39
|
+
const date = safeDate(value);
|
|
40
|
+
if (!date) return '';
|
|
41
|
+
|
|
31
42
|
if (isToday(date)) return 'Today';
|
|
32
43
|
if (isYesterday(date)) return 'Yesterday';
|
|
33
|
-
return format(
|
|
44
|
+
return format(date, 'MMM dd, yyyy');
|
|
34
45
|
};
|
|
35
46
|
|
|
36
47
|
export interface IDialogListChannel extends IChannel {
|
|
@@ -45,8 +56,120 @@ export interface IDialogListItemProps {
|
|
|
45
56
|
onOpen: (id: any, title: any, postParentId?: any) => void;
|
|
46
57
|
refreshing: boolean;
|
|
47
58
|
role: any;
|
|
59
|
+
visible?: boolean;
|
|
48
60
|
}
|
|
49
61
|
|
|
62
|
+
// Helper function to compute the last message from a list of messages
|
|
63
|
+
const computeLastMessage = (threadMessages) => {
|
|
64
|
+
if (!threadMessages || !threadMessages.length) return null;
|
|
65
|
+
|
|
66
|
+
// Extract the post and replies from thread messages
|
|
67
|
+
let posts = [];
|
|
68
|
+
let replies = [];
|
|
69
|
+
|
|
70
|
+
// Helper function to check if a message is an image or contains only image content
|
|
71
|
+
const isTextMessage = (msg) => {
|
|
72
|
+
if (!msg) return false;
|
|
73
|
+
|
|
74
|
+
// If message is empty or only contains image-specific markers, ignore it
|
|
75
|
+
if (!msg.message || msg.message === '') return false;
|
|
76
|
+
|
|
77
|
+
// Check if message looks like an image URL or reference
|
|
78
|
+
const isImageMessage =
|
|
79
|
+
msg.message.includes('<img') ||
|
|
80
|
+
msg.message.includes('[Image]') ||
|
|
81
|
+
msg.message.includes('![') ||
|
|
82
|
+
(/\.(jpeg|jpg|gif|png|bmp|webp)/i.test(msg.message) &&
|
|
83
|
+
(msg.message.includes('http') || msg.message.includes('/images/')));
|
|
84
|
+
|
|
85
|
+
// Return true only for text messages (not image messages)
|
|
86
|
+
return !isImageMessage;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
threadMessages.forEach((thread) => {
|
|
90
|
+
if (thread?.post && isTextMessage(thread.post)) {
|
|
91
|
+
posts.push(thread.post);
|
|
92
|
+
}
|
|
93
|
+
if (thread?.replies?.length) {
|
|
94
|
+
replies = [...replies, ...thread.replies.filter((r) => isTextMessage(r))];
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Combine and sort all messages
|
|
99
|
+
const allMessages = [...posts, ...replies];
|
|
100
|
+
if (!allMessages.length) return null;
|
|
101
|
+
|
|
102
|
+
// Return the most recent message - use safe date comparison
|
|
103
|
+
return allMessages.reduce((a, b) => {
|
|
104
|
+
const dateA = safeDate(a?.createdAt);
|
|
105
|
+
const dateB = safeDate(b?.createdAt);
|
|
106
|
+
|
|
107
|
+
// If either date is invalid, prefer the message with valid date
|
|
108
|
+
if (!dateA) return b;
|
|
109
|
+
if (!dateB) return a;
|
|
110
|
+
|
|
111
|
+
return dateA > dateB ? a : b;
|
|
112
|
+
}, allMessages[0]);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const ServiceChannelWithLastMessage = React.memo(({ channel, lastMessage }: { channel: any; lastMessage: any }) => {
|
|
116
|
+
// Debug output for component rendering
|
|
117
|
+
React.useEffect(() => {
|
|
118
|
+
console.log(`ServiceChannelWithLastMessage rendered for channel ${channel?.id}:`, {
|
|
119
|
+
hasLastMessage: !!lastMessage,
|
|
120
|
+
messageId: lastMessage?.id,
|
|
121
|
+
messageText: lastMessage?.message?.substring(0, 20) + (lastMessage?.message?.length > 20 ? '...' : ''),
|
|
122
|
+
date: lastMessage?.createdAt ? safeDate(lastMessage.createdAt)?.toISOString() : 'none',
|
|
123
|
+
});
|
|
124
|
+
}, [lastMessage, channel?.id]);
|
|
125
|
+
|
|
126
|
+
const count = 30;
|
|
127
|
+
const title = channel?.title.slice(0, count) + (channel?.title.length > count ? '...' : '');
|
|
128
|
+
|
|
129
|
+
// Define message display text
|
|
130
|
+
let displayMessage = 'No messages yet';
|
|
131
|
+
|
|
132
|
+
if (lastMessage) {
|
|
133
|
+
// Check for file attachments
|
|
134
|
+
const hasFileAttachments = lastMessage.files?.data?.length > 0;
|
|
135
|
+
|
|
136
|
+
// Check if the message appears to be an image
|
|
137
|
+
const isImageMessage =
|
|
138
|
+
lastMessage.message?.includes('<img') ||
|
|
139
|
+
lastMessage.message?.includes('[Image]') ||
|
|
140
|
+
lastMessage.message?.includes('![') ||
|
|
141
|
+
(/\.(jpeg|jpg|gif|png|bmp|webp)/i.test(lastMessage.message || '') &&
|
|
142
|
+
((lastMessage.message || '').includes('http') || (lastMessage.message || '').includes('/images/')));
|
|
143
|
+
|
|
144
|
+
if (hasFileAttachments) {
|
|
145
|
+
displayMessage = '📎 File attachment';
|
|
146
|
+
} else if (isImageMessage) {
|
|
147
|
+
displayMessage = '[Image]';
|
|
148
|
+
} else if (lastMessage.message && lastMessage.message.trim() !== '') {
|
|
149
|
+
displayMessage = lastMessage.message;
|
|
150
|
+
} else {
|
|
151
|
+
displayMessage = '(Empty message)';
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<HStack space={'sm'} className="flex-1 justify-between">
|
|
157
|
+
<Box className="flex-[0.8]">
|
|
158
|
+
<Text color={colors.gray[600]} className="text-base text-wrap flex-wrap font-semibold">
|
|
159
|
+
{title}
|
|
160
|
+
</Text>
|
|
161
|
+
<Text color={colors.gray[600]} numberOfLines={1}>
|
|
162
|
+
{displayMessage}
|
|
163
|
+
</Text>
|
|
164
|
+
</Box>
|
|
165
|
+
|
|
166
|
+
<Box className="flex-[0.2]">
|
|
167
|
+
<Text color={colors.gray[500]}>{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
|
|
168
|
+
</Box>
|
|
169
|
+
</HStack>
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
50
173
|
/**
|
|
51
174
|
* TODO:
|
|
52
175
|
* - Get Reservation info: reservation date, status
|
|
@@ -60,10 +183,17 @@ export const ServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = f
|
|
|
60
183
|
onOpen,
|
|
61
184
|
refreshing,
|
|
62
185
|
role,
|
|
186
|
+
visible = true,
|
|
63
187
|
}) {
|
|
64
|
-
const
|
|
188
|
+
const isMountedRef = useRef(true);
|
|
189
|
+
const [subscriptionsTimestamp, setSubscriptionsTimestamp] = useState(Date.now());
|
|
190
|
+
|
|
191
|
+
// Only run queries/subscriptions if visible
|
|
192
|
+
const shouldQuery = !!channel?.id && visible;
|
|
193
|
+
|
|
194
|
+
// Query for thread messages (minimal fields if possible)
|
|
65
195
|
const {
|
|
66
|
-
data:
|
|
196
|
+
data: threadMessagesData,
|
|
67
197
|
loading: threadMessageLoading,
|
|
68
198
|
error,
|
|
69
199
|
refetch: refetchThreadMessages,
|
|
@@ -74,56 +204,41 @@ export const ServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = f
|
|
|
74
204
|
role,
|
|
75
205
|
limit: 2,
|
|
76
206
|
},
|
|
207
|
+
skip: !shouldQuery, // Only run if visible
|
|
77
208
|
fetchPolicy: 'cache-and-network',
|
|
209
|
+
onCompleted: (data) => {
|
|
210
|
+
if (!shouldQuery) return;
|
|
211
|
+
},
|
|
212
|
+
onError: (error) => {
|
|
213
|
+
if (!shouldQuery) return;
|
|
214
|
+
console.error(`Error fetching thread messages for channel ${channel?.id}:`, error);
|
|
215
|
+
},
|
|
78
216
|
});
|
|
79
217
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
// Do something when the screen is focused
|
|
83
|
-
// refetchMessages({ channelId: channel?.id?.toString(), limit: 25 });
|
|
84
|
-
refetchThreadMessages({ channelId: channel?.id?.toString(), role, limit: 2 });
|
|
85
|
-
return () => {
|
|
86
|
-
// Do something when the screen is unfocused
|
|
87
|
-
// Useful for cleanup functions
|
|
88
|
-
};
|
|
89
|
-
}, [refreshing]),
|
|
90
|
-
);
|
|
218
|
+
// Extract threadMessages data for easier access
|
|
219
|
+
const threadMessages = useMemo(() => threadMessagesData?.threadMessages?.data || [], [threadMessagesData]);
|
|
91
220
|
|
|
221
|
+
// Calculate lastMessage directly from threadMessages
|
|
92
222
|
const lastMessage = useMemo(() => {
|
|
93
|
-
if (!
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (replies?.length) {
|
|
103
|
-
return replies[0];
|
|
104
|
-
// return replies[replies.length - 1];
|
|
105
|
-
} else {
|
|
106
|
-
const post =
|
|
107
|
-
data?.find((t: any) => {
|
|
108
|
-
return t?.post?.message !== '';
|
|
109
|
-
}) ??
|
|
110
|
-
data?.find((t: any) => {
|
|
111
|
-
return t?.post;
|
|
112
|
-
}) ??
|
|
113
|
-
null;
|
|
114
|
-
return post ? post?.post : null;
|
|
115
|
-
}
|
|
116
|
-
}, [threadMessages]);
|
|
223
|
+
if (!shouldQuery) return null;
|
|
224
|
+
return computeLastMessage(threadMessages);
|
|
225
|
+
}, [shouldQuery, threadMessages]);
|
|
226
|
+
|
|
227
|
+
// Calculate servicePostParentId based on lastMessage
|
|
228
|
+
const servicePostParentId = useMemo(() => {
|
|
229
|
+
if (!shouldQuery || !lastMessage) return null;
|
|
230
|
+
return lastMessage?.parentId ? lastMessage?.parentId : lastMessage?.id;
|
|
231
|
+
}, [shouldQuery, lastMessage]);
|
|
117
232
|
|
|
233
|
+
// Handle component unmount
|
|
118
234
|
React.useEffect(() => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}, [lastMessage]);
|
|
235
|
+
return () => {
|
|
236
|
+
isMountedRef.current = false;
|
|
237
|
+
};
|
|
238
|
+
}, []);
|
|
124
239
|
|
|
125
|
-
const creatorAndMembersId =
|
|
126
|
-
if (!channel?.members) return null;
|
|
240
|
+
const creatorAndMembersId = useMemo(() => {
|
|
241
|
+
if (!shouldQuery || !channel?.members) return null;
|
|
127
242
|
const membersIds: any =
|
|
128
243
|
channel?.members
|
|
129
244
|
?.filter((m: any) => m !== null && m?.user?.id !== currentUser?.id)
|
|
@@ -131,39 +246,55 @@ export const ServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = f
|
|
|
131
246
|
const creatorId: any = channel?.creator?.id;
|
|
132
247
|
const mergedIds: any = [].concat(membersIds, creatorId) ?? [];
|
|
133
248
|
return mergedIds?.filter((m: any, pos: any) => mergedIds?.indexOf(m) === pos) ?? [];
|
|
134
|
-
}, [channel]);
|
|
135
|
-
|
|
136
|
-
const postParentId = React.useMemo(() => {
|
|
137
|
-
if (!creatorAndMembersId?.length) return null;
|
|
249
|
+
}, [shouldQuery, channel, currentUser]);
|
|
138
250
|
|
|
251
|
+
const postParentId = useMemo(() => {
|
|
252
|
+
if (!shouldQuery || !creatorAndMembersId?.length) return null;
|
|
139
253
|
return creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id)
|
|
140
254
|
? null
|
|
141
255
|
: lastMessage?.parentId
|
|
142
256
|
? lastMessage?.parentId
|
|
143
257
|
: lastMessage?.id ?? 0;
|
|
144
|
-
}, [creatorAndMembersId, lastMessage]);
|
|
145
|
-
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
258
|
+
}, [shouldQuery, creatorAndMembersId, lastMessage, currentUser]);
|
|
259
|
+
|
|
260
|
+
// Function to force refresh the component state
|
|
261
|
+
const refreshThreadState = useCallback(() => {
|
|
262
|
+
if (shouldQuery && channel?.id && isMountedRef.current) {
|
|
263
|
+
refetchThreadMessages({
|
|
264
|
+
channelId: channel?.id?.toString(),
|
|
265
|
+
role,
|
|
266
|
+
limit: 2,
|
|
267
|
+
}).catch((err) => {
|
|
268
|
+
console.error('Error refreshing thread state:', err);
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}, [shouldQuery, channel?.id, refetchThreadMessages, role]);
|
|
272
|
+
|
|
273
|
+
// Reset subscriptions when the component gains focus
|
|
274
|
+
useFocusEffect(
|
|
275
|
+
React.useCallback(() => {
|
|
276
|
+
if (!shouldQuery || !channel?.id) return;
|
|
277
|
+
setSubscriptionsTimestamp(Date.now());
|
|
278
|
+
const fetchFreshData = async () => {
|
|
279
|
+
try {
|
|
280
|
+
await refetchThreadMessages({
|
|
281
|
+
channelId: channel?.id?.toString(),
|
|
282
|
+
role,
|
|
283
|
+
limit: 2,
|
|
284
|
+
});
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error('Error refetching thread messages on focus:', error);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
fetchFreshData();
|
|
290
|
+
return () => {};
|
|
291
|
+
}, [shouldQuery, refreshing, channel?.id, refetchThreadMessages, role]),
|
|
292
|
+
);
|
|
163
293
|
|
|
164
294
|
return (
|
|
165
295
|
<Pressable
|
|
166
|
-
onPress={() => channel?.id !== selectedChannelId && onOpen(channel?.id, channel?.title, postParentId)}
|
|
296
|
+
// onPress={() => channel?.id !== selectedChannelId && onOpen(channel?.id, channel?.title, postParentId)}
|
|
297
|
+
onPress={() => onOpen(channel?.id, channel?.title, postParentId)}
|
|
167
298
|
className="flex-1 rounded-md border-gray-200 dark:border-gray-600 dark:bg-gray-700"
|
|
168
299
|
style={{ borderBottomWidth: 1, borderColor: '#e5e7eb', marginVertical: 0 }}
|
|
169
300
|
>
|
|
@@ -186,102 +317,130 @@ export const ServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = f
|
|
|
186
317
|
</Box>
|
|
187
318
|
<Box className="flex-1">
|
|
188
319
|
<ServiceChannelWithLastMessage
|
|
320
|
+
key={`channel-${channel?.id}-${subscriptionsTimestamp}`}
|
|
189
321
|
channel={channel}
|
|
190
322
|
lastMessage={lastMessage}
|
|
191
|
-
subscribeToNewMessages={() =>
|
|
192
|
-
subscribeToMore({
|
|
193
|
-
document: THREAD_CHAT_ADDED,
|
|
194
|
-
variables: {
|
|
195
|
-
channelId: channel?.id?.toString(),
|
|
196
|
-
postParentId: postParentId ? servicePostParentId : null,
|
|
197
|
-
},
|
|
198
|
-
updateQuery: (prev, { subscriptionData }: any) => {
|
|
199
|
-
if (!subscriptionData.data) return prev;
|
|
200
|
-
|
|
201
|
-
const newPostThreadData: any = subscriptionData?.data?.threadCreatedUpdated?.data;
|
|
202
|
-
const newMessage: any = subscriptionData?.data?.threadCreatedUpdated?.lastMessage;
|
|
203
|
-
const data =
|
|
204
|
-
prev?.threadMessages?.data?.map((t: any) =>
|
|
205
|
-
t.id === newPostThreadData?.id
|
|
206
|
-
? {
|
|
207
|
-
...t,
|
|
208
|
-
replies: [...t?.replies, newMessage],
|
|
209
|
-
replyCount: newPostThreadData?.replyCount,
|
|
210
|
-
lastReplyAt: newPostThreadData?.lastReplyAt,
|
|
211
|
-
updatedAt: newPostThreadData?.updatedAt,
|
|
212
|
-
}
|
|
213
|
-
: t,
|
|
214
|
-
) ?? [];
|
|
215
|
-
|
|
216
|
-
return Object.assign({}, prev, {
|
|
217
|
-
threadMessages: {
|
|
218
|
-
...prev?.threadMessages,
|
|
219
|
-
totalCount: newPostThreadData?.totalCount ?? 0,
|
|
220
|
-
data: data?.length > 0 ? data : [newPostThreadData],
|
|
221
|
-
// totalCount: prev?.threadMessages?.totalCount + 1,
|
|
222
|
-
//data: data,
|
|
223
|
-
},
|
|
224
|
-
});
|
|
225
|
-
},
|
|
226
|
-
})
|
|
227
|
-
}
|
|
228
323
|
/>
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
324
|
+
|
|
325
|
+
{/* Subscription handlers for real-time updates */}
|
|
326
|
+
{shouldQuery && (
|
|
327
|
+
<>
|
|
328
|
+
<SubscriptionHandler
|
|
329
|
+
subscribeToMore={subscribeToMore}
|
|
330
|
+
document={THREAD_CREATED_UPDATED}
|
|
331
|
+
variables={{
|
|
332
|
+
channelId: channel?.id?.toString(),
|
|
333
|
+
postParentId: postParentId || servicePostParentId || null,
|
|
334
|
+
}}
|
|
335
|
+
updateQuery={(prev, { subscriptionData }: any) => {
|
|
336
|
+
if (!subscriptionData?.data) {
|
|
337
|
+
return prev;
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
const newPostThreadData: any =
|
|
341
|
+
subscriptionData?.data?.threadCreatedUpdated?.data;
|
|
342
|
+
const newMessage: any =
|
|
343
|
+
subscriptionData?.data?.threadCreatedUpdated?.lastMessage;
|
|
344
|
+
if (!newPostThreadData || !newMessage) {
|
|
345
|
+
return prev;
|
|
346
|
+
}
|
|
347
|
+
const prevThreads = prev?.threadMessages?.data || [];
|
|
348
|
+
const threadExists = prevThreads.some(
|
|
349
|
+
(t: any) => t.id === newPostThreadData?.id,
|
|
350
|
+
);
|
|
351
|
+
let updatedThreads;
|
|
352
|
+
if (threadExists) {
|
|
353
|
+
updatedThreads = prevThreads.map((t: any) =>
|
|
354
|
+
t.id === newPostThreadData?.id
|
|
355
|
+
? {
|
|
356
|
+
...t,
|
|
357
|
+
replies: [...(t?.replies || []), newMessage],
|
|
358
|
+
replyCount: newPostThreadData?.replyCount,
|
|
359
|
+
lastReplyAt: newPostThreadData?.lastReplyAt,
|
|
360
|
+
updatedAt: newPostThreadData?.updatedAt,
|
|
361
|
+
}
|
|
362
|
+
: t,
|
|
363
|
+
);
|
|
364
|
+
} else {
|
|
365
|
+
updatedThreads = [...prevThreads, newPostThreadData];
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
...prev,
|
|
369
|
+
threadMessages: {
|
|
370
|
+
...prev?.threadMessages,
|
|
371
|
+
totalCount:
|
|
372
|
+
newPostThreadData?.totalCount ??
|
|
373
|
+
prev?.threadMessages?.totalCount ??
|
|
374
|
+
0,
|
|
375
|
+
data: updatedThreads,
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
} catch (error) {
|
|
379
|
+
console.error(`Thread subscription error for channel ${channel?.id}:`, error);
|
|
380
|
+
return prev;
|
|
381
|
+
}
|
|
382
|
+
}}
|
|
383
|
+
/>
|
|
384
|
+
<SubscriptionHandler
|
|
385
|
+
subscribeToMore={subscribeToMore}
|
|
386
|
+
document={CHAT_MESSAGE_ADDED}
|
|
387
|
+
variables={{
|
|
388
|
+
channelId: channel?.id?.toString(),
|
|
389
|
+
postParentId: postParentId || servicePostParentId || null,
|
|
390
|
+
}}
|
|
391
|
+
updateQuery={(prev, { subscriptionData }: any) => {
|
|
392
|
+
if (!subscriptionData?.data) {
|
|
393
|
+
return prev;
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
const newMessage = subscriptionData?.data?.chatMessageAdded;
|
|
397
|
+
if (!newMessage) {
|
|
398
|
+
return prev;
|
|
399
|
+
}
|
|
400
|
+
const prevThreads = prev?.threadMessages?.data || [];
|
|
401
|
+
const threadIndex = prevThreads.findIndex((t: any) => {
|
|
402
|
+
if (newMessage.parentId && t.post?.id === newMessage.parentId) {
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
if (t.replies && t.replies.some((r: any) => r.id === newMessage.parentId)) {
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
return false;
|
|
409
|
+
});
|
|
410
|
+
if (threadIndex === -1) {
|
|
411
|
+
return prev;
|
|
412
|
+
}
|
|
413
|
+
const updatedThreads = [...prevThreads];
|
|
414
|
+
const thread = { ...updatedThreads[threadIndex] };
|
|
415
|
+
thread.replies = [...(thread.replies || []), newMessage];
|
|
416
|
+
const currentReplyCount =
|
|
417
|
+
typeof thread.replyCount === 'number' ? thread.replyCount : 0;
|
|
418
|
+
thread.replyCount = currentReplyCount + 1;
|
|
419
|
+
thread.lastReplyAt = newMessage.createdAt;
|
|
420
|
+
thread.updatedAt = newMessage.createdAt;
|
|
421
|
+
updatedThreads[threadIndex] = thread;
|
|
422
|
+
return {
|
|
423
|
+
...prev,
|
|
424
|
+
threadMessages: {
|
|
425
|
+
...prev?.threadMessages,
|
|
426
|
+
data: updatedThreads,
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
} catch (error) {
|
|
430
|
+
console.error(
|
|
431
|
+
`Chat message subscription error for channel ${channel?.id}:`,
|
|
432
|
+
error,
|
|
433
|
+
);
|
|
434
|
+
return prev;
|
|
435
|
+
}
|
|
436
|
+
}}
|
|
437
|
+
/>
|
|
438
|
+
</>
|
|
439
|
+
)}
|
|
244
440
|
</Box>
|
|
245
|
-
{/* <Text flex={0.2} color="gray.500">
|
|
246
|
-
{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}
|
|
247
|
-
</Text> */}
|
|
248
441
|
</HStack>
|
|
249
442
|
</Pressable>
|
|
250
443
|
);
|
|
251
444
|
};
|
|
252
445
|
|
|
253
|
-
const ServiceChannelWithLastMessage = React.memo(({ channel, lastMessage, subscribeToNewMessages }: any) => {
|
|
254
|
-
React.useEffect(() => subscribeToNewMessages(), []);
|
|
255
|
-
const count = 20;
|
|
256
|
-
const title = channel?.title.slice(0, count) + (channel?.title.length > count ? '...' : '');
|
|
257
|
-
return (
|
|
258
|
-
<HStack space={'sm'} className="flex-1 justify-between">
|
|
259
|
-
<Box className="flex-[0.8]">
|
|
260
|
-
<Text color={colors.gray[600]} className="text-base text-wrap flex-wrap font-semibold">
|
|
261
|
-
{title}
|
|
262
|
-
</Text>
|
|
263
|
-
<Text color={colors.gray[600]} numberOfLines={1}>
|
|
264
|
-
{/* {creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id)
|
|
265
|
-
? lastMessageCreatorAndMembers?.message ?? ''
|
|
266
|
-
: lastMessage?.message ?? ''} */}
|
|
267
|
-
{lastMessage?.message ?? ''}
|
|
268
|
-
</Text>
|
|
269
|
-
</Box>
|
|
270
|
-
|
|
271
|
-
<Box className="flex-[0.2]">
|
|
272
|
-
{/* {creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id) ? (
|
|
273
|
-
<Text color="gray.500">
|
|
274
|
-
{lastMessageCreatorAndMembers
|
|
275
|
-
? createdAtText(lastMessageCreatorAndMembers?.createdAt)
|
|
276
|
-
: ''}
|
|
277
|
-
</Text>
|
|
278
|
-
) : (
|
|
279
|
-
<Text color="gray.500">{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
|
|
280
|
-
)} */}
|
|
281
|
-
<Text color={colors.gray[500]}>{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
|
|
282
|
-
</Box>
|
|
283
|
-
</HStack>
|
|
284
|
-
);
|
|
285
|
-
});
|
|
286
|
-
|
|
287
446
|
export const ServiceDialogsListItem = React.memo(ServiceDialogsListItemComponent);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TextInput, TextInputProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export const SlackInput = React.forwardRef<TextInput, TextInputProps>((props, ref) => {
|
|
5
|
+
return (
|
|
6
|
+
<TextInput
|
|
7
|
+
ref={ref}
|
|
8
|
+
{...props}
|
|
9
|
+
style={[
|
|
10
|
+
{
|
|
11
|
+
flex: 1,
|
|
12
|
+
fontSize: 16,
|
|
13
|
+
padding: 10,
|
|
14
|
+
borderRadius: 8,
|
|
15
|
+
backgroundColor: '#f8f8f8',
|
|
16
|
+
borderColor: '#e0e0e0',
|
|
17
|
+
borderWidth: 1,
|
|
18
|
+
},
|
|
19
|
+
props.style,
|
|
20
|
+
]}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
});
|