@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
|
@@ -307,7 +307,6 @@ function useSafeMachine(machine) {
|
|
|
307
307
|
`Merging ${newMessages.length} older messages with ${prev.context.threadMessages.length} existing messages`,
|
|
308
308
|
);
|
|
309
309
|
|
|
310
|
-
// Debug: Log the dates of the messages for troubleshooting
|
|
311
310
|
if (newMessages.length > 0) {
|
|
312
311
|
try {
|
|
313
312
|
console.log(
|
|
@@ -677,7 +676,14 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
677
676
|
// Fetch thread messages function
|
|
678
677
|
const fetchThreadMessages = useCallback(() => {
|
|
679
678
|
if (channelId && parentId) {
|
|
680
|
-
console.log('Initial fetch of thread messages using larger limit (50)');
|
|
679
|
+
if (__DEV__) console.log('Initial fetch of thread messages using larger limit (50)');
|
|
680
|
+
|
|
681
|
+
// Set loading state
|
|
682
|
+
safeSend({
|
|
683
|
+
type: ThreadActions.START_LOADING,
|
|
684
|
+
data: { loading: true },
|
|
685
|
+
});
|
|
686
|
+
|
|
681
687
|
getThreadMessages({
|
|
682
688
|
variables: {
|
|
683
689
|
channelId: channelId?.toString(),
|
|
@@ -695,10 +701,12 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
695
701
|
const messageTotalCount = threads?.replyCount ?? 0;
|
|
696
702
|
const messages = [...threadReplies];
|
|
697
703
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
704
|
+
if (__DEV__)
|
|
705
|
+
console.log(
|
|
706
|
+
`Initial fetch complete. Got ${messages.length} messages of ${messageTotalCount} total`,
|
|
707
|
+
);
|
|
701
708
|
|
|
709
|
+
// Use batch updates to reduce render cycles
|
|
702
710
|
safeSend({
|
|
703
711
|
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
704
712
|
data: {
|
|
@@ -717,7 +725,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
717
725
|
});
|
|
718
726
|
});
|
|
719
727
|
}
|
|
720
|
-
}, [channelId, parentId, role]);
|
|
728
|
+
}, [channelId, parentId, role, getThreadMessages, safeSend]);
|
|
721
729
|
|
|
722
730
|
React.useEffect(() => {
|
|
723
731
|
if (data?.getPostThread) {
|
|
@@ -819,193 +827,41 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
819
827
|
}
|
|
820
828
|
}, [threadMessageListRef]);
|
|
821
829
|
|
|
822
|
-
const
|
|
823
|
-
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
// Set the loading state specifically for old messages
|
|
830
|
-
safeSend({
|
|
831
|
-
type: ThreadActions.FETCH_MORE_MESSAGES,
|
|
832
|
-
data: { loadingOldMessages: true },
|
|
833
|
-
});
|
|
834
|
-
|
|
835
|
-
// Since Skip=0, Limit=50 worked well, let's use that approach
|
|
836
|
-
console.log('Using proven approach: Skip=0, Limit=50');
|
|
837
|
-
|
|
838
|
-
// Try with a larger limit and skip=0, which we know works
|
|
839
|
-
const queryVariables = {
|
|
840
|
-
channelId: channelId?.toString(),
|
|
841
|
-
role: role?.toString(),
|
|
842
|
-
postParentId: !parentId || parentId == 0 ? null : parentId?.toString(),
|
|
843
|
-
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
844
|
-
limit: 50, // Use larger limit that proved to work
|
|
845
|
-
skip: 0, // Start from the beginning
|
|
846
|
-
};
|
|
847
|
-
|
|
848
|
-
console.log('Query variables:', JSON.stringify(queryVariables));
|
|
849
|
-
|
|
850
|
-
fetchMoreMessages({
|
|
851
|
-
variables: queryVariables,
|
|
852
|
-
})
|
|
853
|
-
.then((res: any) => {
|
|
854
|
-
console.log('API response received:', JSON.stringify(res?.data, null, 2));
|
|
855
|
-
|
|
856
|
-
if (res?.data?.getPostThread) {
|
|
857
|
-
const threads: any = res?.data?.getPostThread;
|
|
858
|
-
const threadReplies = threads?.replies ?? [];
|
|
859
|
-
// Get the actual total count from the response
|
|
860
|
-
const actualTotalCount = threads?.replyCount ?? 0;
|
|
861
|
-
|
|
862
|
-
console.log('API response details:');
|
|
863
|
-
console.log('- replyCount:', threads?.replyCount);
|
|
864
|
-
console.log('- replies array length:', threadReplies.length);
|
|
865
|
-
console.log(
|
|
866
|
-
'- replies structure:',
|
|
867
|
-
threadReplies.length > 0
|
|
868
|
-
? `First item has fields: ${Object.keys(threadReplies[0]).join(', ')}`
|
|
869
|
-
: 'No items',
|
|
870
|
-
);
|
|
871
|
-
|
|
872
|
-
if (threadReplies.length > 0) {
|
|
873
|
-
console.log('- Sample message:', JSON.stringify(threadReplies[0], null, 2));
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
console.log(
|
|
877
|
-
'Successfully loaded more messages:',
|
|
878
|
-
threadReplies.length,
|
|
879
|
-
'of total:',
|
|
880
|
-
actualTotalCount,
|
|
881
|
-
);
|
|
882
|
-
console.log('Thread reply IDs:', threadReplies.map((msg) => msg.id).join(', '));
|
|
883
|
-
|
|
884
|
-
// Compare with our existing messages to find the ones we're missing
|
|
885
|
-
const existingIds = new Set(threadMessages.map((msg) => msg.id));
|
|
886
|
-
const newUniqueMessages = threadReplies.filter((msg) => !existingIds.has(msg.id));
|
|
887
|
-
|
|
888
|
-
console.log(
|
|
889
|
-
`Found ${newUniqueMessages.length} unique new messages out of ${threadReplies.length} received`,
|
|
890
|
-
);
|
|
891
|
-
|
|
892
|
-
// If we've received all messages but our count doesn't match, update the total count
|
|
893
|
-
if (actualTotalCount !== totalCount) {
|
|
894
|
-
console.log(
|
|
895
|
-
`Updating totalCount from ${totalCount} to ${actualTotalCount} based on API response`,
|
|
896
|
-
);
|
|
897
|
-
// This will be applied below when we process the messages
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
// If no new unique messages, it means we already have everything
|
|
901
|
-
if (newUniqueMessages.length === 0) {
|
|
902
|
-
console.log('No new unique messages found, adjusting total count');
|
|
903
|
-
|
|
904
|
-
// Register this as a failed load attempt
|
|
905
|
-
registerLoadAttemptResult(false);
|
|
906
|
-
|
|
907
|
-
// Adjust total count to match what we have
|
|
908
|
-
safeSend({
|
|
909
|
-
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
910
|
-
data: {
|
|
911
|
-
messages: threadMessages,
|
|
912
|
-
totalCount: threadMessages.length,
|
|
913
|
-
threadPost: safeContextProperty('threadPost', []),
|
|
914
|
-
postThread: safeContextProperty('postThread', null),
|
|
915
|
-
},
|
|
916
|
-
});
|
|
917
|
-
return;
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
// Register success since we found new messages
|
|
921
|
-
registerLoadAttemptResult(true);
|
|
922
|
-
|
|
923
|
-
console.log(`Adding ${newUniqueMessages.length} new messages to thread`);
|
|
924
|
-
|
|
925
|
-
safeSend({
|
|
926
|
-
type: 'FETCH_MORE_MESSAGES_SUCCESS',
|
|
927
|
-
data: {
|
|
928
|
-
messages: newUniqueMessages,
|
|
929
|
-
totalCount: actualTotalCount,
|
|
930
|
-
loadingOldMessages: false,
|
|
931
|
-
},
|
|
932
|
-
});
|
|
933
|
-
} else {
|
|
934
|
-
console.log('No thread data returned when loading more messages');
|
|
935
|
-
registerLoadAttemptResult(false);
|
|
936
|
-
safeSend({
|
|
937
|
-
type: ThreadActions.STOP_LOADING,
|
|
938
|
-
data: { loadingOldMessages: false },
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
})
|
|
942
|
-
.catch((error: any) => {
|
|
943
|
-
console.error('Error fetching more messages:', error);
|
|
944
|
-
registerLoadAttemptResult(false);
|
|
945
|
-
safeSend({
|
|
946
|
-
type: 'ERROR',
|
|
947
|
-
data: {
|
|
948
|
-
message: error.message,
|
|
949
|
-
loadingOldMessages: false,
|
|
950
|
-
},
|
|
951
|
-
});
|
|
952
|
-
});
|
|
953
|
-
} else {
|
|
954
|
-
console.log('No more messages to load or already loading');
|
|
955
|
-
// Make sure we're not stuck in loading state
|
|
956
|
-
if (safeContextProperty('loadingOldMessages', false)) {
|
|
957
|
-
safeSend({
|
|
958
|
-
type: ThreadActions.STOP_LOADING,
|
|
959
|
-
data: { loadingOldMessages: false },
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
}, [parentId, channelId, state.context, registerLoadAttemptResult]);
|
|
964
|
-
|
|
965
|
-
let onScroll = false;
|
|
830
|
+
const isCloseToTop = useCallback(({ layoutMeasurement, contentOffset, contentSize }) => {
|
|
831
|
+
// We consider being "close to top" when scrolled to top 15% of visible area
|
|
832
|
+
const visibleHeight = layoutMeasurement.height;
|
|
833
|
+
const topThreshold = Math.min(80, visibleHeight * 0.15);
|
|
834
|
+
return contentOffset.y <= topThreshold;
|
|
835
|
+
}, []);
|
|
966
836
|
|
|
967
|
-
const handleScrollToTop = (
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
837
|
+
const handleScrollToTop = useCallback(
|
|
838
|
+
({ nativeEvent }: any) => {
|
|
839
|
+
// Check if we're near the top of the list
|
|
840
|
+
if (isCloseToTop(nativeEvent)) {
|
|
841
|
+
const isLoading = safeContextProperty('loadingOldMessages', false);
|
|
842
|
+
const totalCount = safeContextProperty('totalCount', 0);
|
|
843
|
+
const currentCount = safeContextProperty('threadMessages', []).length;
|
|
844
|
+
const hasMoreMessages = totalCount > currentCount;
|
|
974
845
|
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
846
|
+
if (__DEV__)
|
|
847
|
+
console.log(
|
|
848
|
+
`Scroll near top - Loading state: ${isLoading}, Messages: ${currentCount}/${totalCount}, Has more: ${hasMoreMessages}`,
|
|
849
|
+
);
|
|
978
850
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
851
|
+
if (!isLoading && hasMoreMessages) {
|
|
852
|
+
if (__DEV__) console.log('Near top of list - loading older messages');
|
|
853
|
+
safeSend({ type: ThreadActions.FETCH_MORE_MESSAGES });
|
|
854
|
+
}
|
|
982
855
|
}
|
|
983
|
-
}
|
|
984
|
-
|
|
856
|
+
},
|
|
857
|
+
[isCloseToTop, safeContextProperty, safeSend],
|
|
858
|
+
);
|
|
985
859
|
|
|
986
860
|
const handleEndReached = () => {
|
|
987
861
|
// This triggers when scrolled to the bottom
|
|
988
862
|
console.log('Reached end of message list');
|
|
989
863
|
};
|
|
990
864
|
|
|
991
|
-
const isCloseToTop = ({ layoutMeasurement, contentOffset, contentSize }) => {
|
|
992
|
-
// We consider being "close to top" when scrolled to top 15% of visible area
|
|
993
|
-
const visibleHeight = layoutMeasurement.height;
|
|
994
|
-
const topThreshold = Math.min(80, visibleHeight * 0.15);
|
|
995
|
-
|
|
996
|
-
// For debugging
|
|
997
|
-
const distanceFromTop = contentOffset.y;
|
|
998
|
-
const totalContentHeight = contentSize.height;
|
|
999
|
-
|
|
1000
|
-
console.log(
|
|
1001
|
-
`Scroll position: ${distanceFromTop.toFixed(0)}px from top, threshold: ${topThreshold.toFixed(
|
|
1002
|
-
0,
|
|
1003
|
-
)}px, content height: ${totalContentHeight.toFixed(0)}px`,
|
|
1004
|
-
);
|
|
1005
|
-
|
|
1006
|
-
return contentOffset.y <= topThreshold;
|
|
1007
|
-
};
|
|
1008
|
-
|
|
1009
865
|
const onSelectImages = async () => {
|
|
1010
866
|
try {
|
|
1011
867
|
safeSend({ type: ThreadActions.START_LOADING });
|
|
@@ -1299,236 +1155,112 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1299
1155
|
}
|
|
1300
1156
|
};
|
|
1301
1157
|
|
|
1158
|
+
// Optimize messageList memo to avoid unnecessary recalculations
|
|
1302
1159
|
const messageList = useMemo(() => {
|
|
1303
1160
|
const threadMessages = safeContextProperty('threadMessages', []);
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
let res: any = [];
|
|
1307
|
-
if (threadMessages?.length) {
|
|
1308
|
-
// We need to convert the threadMessages into the format expected by GiftedChat
|
|
1309
|
-
// Use a Set to track IDs and prevent duplicates
|
|
1310
|
-
const messageIds = new Set();
|
|
1311
|
-
|
|
1312
|
-
res = threadMessages
|
|
1313
|
-
.filter((msg) => {
|
|
1314
|
-
// Skip duplicate IDs
|
|
1315
|
-
if (!msg.id || messageIds.has(msg.id)) {
|
|
1316
|
-
console.log('Skipping duplicate message ID:', msg.id);
|
|
1317
|
-
return false;
|
|
1318
|
-
}
|
|
1319
|
-
messageIds.add(msg.id);
|
|
1320
|
-
return true;
|
|
1321
|
-
})
|
|
1322
|
-
.map((msg) => {
|
|
1323
|
-
// Generate a unique _id if needed by combining id and createdAt
|
|
1324
|
-
const uniqueId = msg.id || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1161
|
+
// Avoid excessive logging in production
|
|
1162
|
+
if (__DEV__) console.log(`Creating message list from ${threadMessages.length} thread messages`);
|
|
1325
1163
|
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1164
|
+
if (!threadMessages?.length) return [];
|
|
1165
|
+
|
|
1166
|
+
// We need to convert the threadMessages into the format expected by GiftedChat
|
|
1167
|
+
// Use a Set to track IDs and prevent duplicates
|
|
1168
|
+
const messageIds = new Set();
|
|
1169
|
+
|
|
1170
|
+
const res = threadMessages
|
|
1171
|
+
.filter((msg) => {
|
|
1172
|
+
// Skip duplicate IDs
|
|
1173
|
+
if (!msg.id || messageIds.has(msg.id)) return false;
|
|
1174
|
+
messageIds.add(msg.id);
|
|
1175
|
+
return true;
|
|
1176
|
+
})
|
|
1177
|
+
.map((msg) => {
|
|
1178
|
+
// Generate a unique _id if needed by combining id and createdAt
|
|
1179
|
+
const uniqueId = msg.id || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1180
|
+
|
|
1181
|
+
// Safely create a Date object with validation
|
|
1182
|
+
let messageDate;
|
|
1183
|
+
try {
|
|
1184
|
+
// Check if createdAt is a valid date string
|
|
1185
|
+
if (msg.createdAt && !isNaN(new Date(msg.createdAt).getTime())) {
|
|
1186
|
+
messageDate = new Date(msg.createdAt);
|
|
1187
|
+
} else {
|
|
1188
|
+
// Use current time as fallback if date is invalid
|
|
1189
|
+
messageDate = new Date();
|
|
1340
1190
|
}
|
|
1191
|
+
} catch (error) {
|
|
1192
|
+
messageDate = new Date(); // Fallback to current time
|
|
1193
|
+
}
|
|
1341
1194
|
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
console.log('📷 Found image URL for message', msg.id, ':', imageUrl);
|
|
1349
|
-
}
|
|
1195
|
+
// Extract image URL from files data
|
|
1196
|
+
let imageUrl = null;
|
|
1197
|
+
if (msg.files?.data && msg.files.data.length > 0) {
|
|
1198
|
+
const fileData = msg.files.data[0];
|
|
1199
|
+
if (fileData && fileData.url) {
|
|
1200
|
+
imageUrl = fileData.url;
|
|
1350
1201
|
}
|
|
1202
|
+
}
|
|
1351
1203
|
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
});
|
|
1375
|
-
}
|
|
1204
|
+
// Get the message text without adding "File attachment" for image-only messages
|
|
1205
|
+
let messageText = msg.message || '';
|
|
1206
|
+
|
|
1207
|
+
return {
|
|
1208
|
+
_id: uniqueId,
|
|
1209
|
+
text: messageText,
|
|
1210
|
+
createdAt: messageDate,
|
|
1211
|
+
user: {
|
|
1212
|
+
_id: msg?.author?.id ?? auth?.profile?.id,
|
|
1213
|
+
name:
|
|
1214
|
+
msg?.author?.givenName ??
|
|
1215
|
+
auth?.profile?.given_name + ' ' + msg?.author?.familyName ??
|
|
1216
|
+
auth?.profile?.family_name,
|
|
1217
|
+
avatar: msg?.author?.picture ?? auth?.profile?.picture,
|
|
1218
|
+
},
|
|
1219
|
+
type: msg?.type || '',
|
|
1220
|
+
image: imageUrl,
|
|
1221
|
+
sent: msg?.isDelivered || true,
|
|
1222
|
+
received: msg?.isRead || false,
|
|
1223
|
+
propsConfiguration: msg?.propsConfiguration,
|
|
1224
|
+
};
|
|
1225
|
+
});
|
|
1376
1226
|
|
|
1377
1227
|
// Sort messages by date (newest first as required by GiftedChat)
|
|
1378
1228
|
// Use a safer getTime() approach with error handling
|
|
1379
|
-
|
|
1229
|
+
return orderBy(
|
|
1380
1230
|
res,
|
|
1381
1231
|
[
|
|
1382
1232
|
(msg) => {
|
|
1383
1233
|
try {
|
|
1384
1234
|
return msg.createdAt instanceof Date ? msg.createdAt.getTime() : new Date().getTime();
|
|
1385
1235
|
} catch (error) {
|
|
1386
|
-
console.error('Error sorting message by date:', error);
|
|
1387
1236
|
return 0; // Fallback to a default value
|
|
1388
1237
|
}
|
|
1389
1238
|
},
|
|
1390
1239
|
],
|
|
1391
1240
|
['desc'],
|
|
1392
1241
|
);
|
|
1393
|
-
|
|
1394
|
-
// Log message dates to help with debugging
|
|
1395
|
-
if (sortedMessages.length > 0) {
|
|
1396
|
-
try {
|
|
1397
|
-
const firstMsg = sortedMessages[0];
|
|
1398
|
-
const lastMsg = sortedMessages[sortedMessages.length - 1];
|
|
1399
|
-
|
|
1400
|
-
console.log(
|
|
1401
|
-
'Message date range:',
|
|
1402
|
-
lastMsg.createdAt instanceof Date ? lastMsg.createdAt.toISOString() : 'invalid date',
|
|
1403
|
-
'to',
|
|
1404
|
-
firstMsg.createdAt instanceof Date ? firstMsg.createdAt.toISOString() : 'invalid date',
|
|
1405
|
-
);
|
|
1406
|
-
} catch (error) {
|
|
1407
|
-
console.error('Error logging message date range:', error);
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
return sortedMessages;
|
|
1412
1242
|
}, [safeContextProperty('threadMessages'), auth]);
|
|
1413
1243
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1244
|
+
// Optimize render functions with memoization
|
|
1245
|
+
const renderSend = useCallback(
|
|
1246
|
+
(props) => {
|
|
1247
|
+
// Check if there's an image selected
|
|
1248
|
+
const hasImage = safeContextProperty('selectedImage', '') !== '';
|
|
1417
1249
|
|
|
1418
|
-
|
|
1419
|
-
|
|
1250
|
+
// Enable send button if there's text OR an image
|
|
1251
|
+
const isDisabled = !hasImage && (!props.text || props.text.trim().length === 0);
|
|
1420
1252
|
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
alignItems: 'center',
|
|
1426
|
-
justifyContent: 'center',
|
|
1427
|
-
marginHorizontal: 4,
|
|
1428
|
-
marginBottom: 0,
|
|
1429
|
-
}}
|
|
1430
|
-
disabled={isDisabled}
|
|
1431
|
-
>
|
|
1432
|
-
<Box
|
|
1433
|
-
style={{
|
|
1434
|
-
width: 32,
|
|
1435
|
-
height: 32,
|
|
1253
|
+
return (
|
|
1254
|
+
<Send
|
|
1255
|
+
{...props}
|
|
1256
|
+
containerStyle={{
|
|
1436
1257
|
alignItems: 'center',
|
|
1437
1258
|
justifyContent: 'center',
|
|
1259
|
+
marginHorizontal: 4,
|
|
1260
|
+
marginBottom: 0,
|
|
1438
1261
|
}}
|
|
1262
|
+
disabled={isDisabled}
|
|
1439
1263
|
>
|
|
1440
|
-
<MaterialCommunityIcons
|
|
1441
|
-
name="send-circle"
|
|
1442
|
-
size={30}
|
|
1443
|
-
color={isDisabled ? colors.gray[400] : colors.blue[500]}
|
|
1444
|
-
/>
|
|
1445
|
-
</Box>
|
|
1446
|
-
</Send>
|
|
1447
|
-
);
|
|
1448
|
-
};
|
|
1449
|
-
|
|
1450
|
-
const renderMessageText = (props: any) => {
|
|
1451
|
-
const { currentMessage } = props;
|
|
1452
|
-
|
|
1453
|
-
// For ALERT type messages with call to action
|
|
1454
|
-
if (currentMessage.type === 'ALERT') {
|
|
1455
|
-
const attachment = currentMessage?.propsConfiguration?.contents?.attachment;
|
|
1456
|
-
let action: string = '';
|
|
1457
|
-
let actionId: any = '';
|
|
1458
|
-
let params: any = {};
|
|
1459
|
-
if (attachment?.callToAction?.extraParams) {
|
|
1460
|
-
const extraParams: any = attachment?.callToAction?.extraParams;
|
|
1461
|
-
const route: any = extraParams?.route ?? null;
|
|
1462
|
-
let path: any = null;
|
|
1463
|
-
let param: any = null;
|
|
1464
|
-
if (role && role == PreDefinedRole.Guest) {
|
|
1465
|
-
path = route?.guest?.name ? route?.guest?.name ?? null : null;
|
|
1466
|
-
param = route?.guest?.params ? route?.guest?.params ?? null : null;
|
|
1467
|
-
} else if (role && role == PreDefinedRole.Owner) {
|
|
1468
|
-
path = route?.host?.name ? route?.host?.name ?? null : null;
|
|
1469
|
-
param = route?.host?.params ? route?.host?.params ?? null : null;
|
|
1470
|
-
} else {
|
|
1471
|
-
path = route?.host?.name ? route?.host?.name ?? null : null;
|
|
1472
|
-
param = route?.host?.params ? route?.host?.params ?? null : null;
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
action = path;
|
|
1476
|
-
params = { ...param };
|
|
1477
|
-
} else if (attachment?.callToAction?.link) {
|
|
1478
|
-
action = CALL_TO_ACTION_PATH;
|
|
1479
|
-
actionId = attachment?.callToAction?.link.split('/').pop();
|
|
1480
|
-
params = { reservationId: actionId };
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
return (
|
|
1484
|
-
<>
|
|
1485
|
-
{attachment?.callToAction && action ? (
|
|
1486
|
-
<Box className={`bg-[${CALL_TO_ACTION_BOX_BGCOLOR}] rounded-[15] pb-2`}>
|
|
1487
|
-
<Button
|
|
1488
|
-
variant={'outline'}
|
|
1489
|
-
size={'sm'}
|
|
1490
|
-
className={`border-[${CALL_TO_ACTION_BUTTON_BORDERCOLOR}]`}
|
|
1491
|
-
onPress={() => action && params && navigation.navigate(action, params)}
|
|
1492
|
-
>
|
|
1493
|
-
<ButtonText className={`color-[${CALL_TO_ACTION_TEXT_COLOR}]`}>
|
|
1494
|
-
{attachment.callToAction.title}
|
|
1495
|
-
</ButtonText>
|
|
1496
|
-
</Button>
|
|
1497
|
-
<MessageText
|
|
1498
|
-
{...props}
|
|
1499
|
-
textStyle={{
|
|
1500
|
-
left: { marginLeft: 5, color: CALL_TO_ACTION_TEXT_COLOR, paddingHorizontal: 2 },
|
|
1501
|
-
}}
|
|
1502
|
-
/>
|
|
1503
|
-
</Box>
|
|
1504
|
-
) : (
|
|
1505
|
-
<MessageText {...props} textStyle={{ left: { marginLeft: 5 } }} />
|
|
1506
|
-
)}
|
|
1507
|
-
</>
|
|
1508
|
-
);
|
|
1509
|
-
}
|
|
1510
|
-
// For file attachment messages, don't show the "File attachment" text
|
|
1511
|
-
else if (currentMessage.text === '📎 File attachment') {
|
|
1512
|
-
// Return null to not render any text for these messages
|
|
1513
|
-
return null;
|
|
1514
|
-
}
|
|
1515
|
-
// Default text rendering
|
|
1516
|
-
else {
|
|
1517
|
-
return <MessageText {...props} textStyle={{ left: { marginLeft: 5 } }} />;
|
|
1518
|
-
}
|
|
1519
|
-
};
|
|
1520
|
-
|
|
1521
|
-
const renderActions = (props) => {
|
|
1522
|
-
return (
|
|
1523
|
-
<Actions
|
|
1524
|
-
{...props}
|
|
1525
|
-
options={{
|
|
1526
|
-
['Choose from Library']: onSelectImages,
|
|
1527
|
-
['Cancel']: () => {}, // Add this option to make the sheet dismissible
|
|
1528
|
-
}}
|
|
1529
|
-
optionTintColor="#000000"
|
|
1530
|
-
cancelButtonIndex={1} // Set the Cancel option as the cancel button
|
|
1531
|
-
icon={() => (
|
|
1532
1264
|
<Box
|
|
1533
1265
|
style={{
|
|
1534
1266
|
width: 32,
|
|
@@ -1537,88 +1269,226 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1537
1269
|
justifyContent: 'center',
|
|
1538
1270
|
}}
|
|
1539
1271
|
>
|
|
1540
|
-
<
|
|
1272
|
+
<MaterialCommunityIcons
|
|
1273
|
+
name="send-circle"
|
|
1274
|
+
size={30}
|
|
1275
|
+
color={isDisabled ? colors.gray[400] : colors.blue[500]}
|
|
1276
|
+
/>
|
|
1541
1277
|
</Box>
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1278
|
+
</Send>
|
|
1279
|
+
);
|
|
1280
|
+
},
|
|
1281
|
+
[safeContextProperty],
|
|
1282
|
+
);
|
|
1283
|
+
|
|
1284
|
+
const renderActions = useCallback(
|
|
1285
|
+
(props) => {
|
|
1286
|
+
return (
|
|
1287
|
+
<Actions
|
|
1288
|
+
{...props}
|
|
1289
|
+
options={{
|
|
1290
|
+
['Choose from Library']: onSelectImages,
|
|
1291
|
+
['Cancel']: () => {}, // Add this option to make the sheet dismissible
|
|
1292
|
+
}}
|
|
1293
|
+
optionTintColor="#000000"
|
|
1294
|
+
cancelButtonIndex={1} // Set the Cancel option as the cancel button
|
|
1295
|
+
icon={() => (
|
|
1296
|
+
<Box
|
|
1297
|
+
style={{
|
|
1298
|
+
width: 32,
|
|
1299
|
+
height: 32,
|
|
1300
|
+
alignItems: 'center',
|
|
1301
|
+
justifyContent: 'center',
|
|
1302
|
+
}}
|
|
1303
|
+
>
|
|
1304
|
+
<Ionicons name="image" size={24} color={colors.blue[500]} />
|
|
1305
|
+
</Box>
|
|
1306
|
+
)}
|
|
1307
|
+
containerStyle={{
|
|
1308
|
+
alignItems: 'center',
|
|
1309
|
+
justifyContent: 'center',
|
|
1310
|
+
marginLeft: 8,
|
|
1311
|
+
marginBottom: 0,
|
|
1312
|
+
}}
|
|
1313
|
+
/>
|
|
1314
|
+
);
|
|
1315
|
+
},
|
|
1316
|
+
[onSelectImages],
|
|
1317
|
+
);
|
|
1552
1318
|
|
|
1553
|
-
const renderAccessory = (
|
|
1554
|
-
|
|
1319
|
+
const renderAccessory = useCallback(
|
|
1320
|
+
(props) => {
|
|
1321
|
+
const selectedImage = safeContextProperty('selectedImage', '');
|
|
1555
1322
|
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1323
|
+
if (!selectedImage) {
|
|
1324
|
+
return null;
|
|
1325
|
+
}
|
|
1559
1326
|
|
|
1560
|
-
|
|
1561
|
-
<View
|
|
1562
|
-
style={{
|
|
1563
|
-
height: 80,
|
|
1564
|
-
padding: 10,
|
|
1565
|
-
backgroundColor: 'white',
|
|
1566
|
-
borderTopWidth: 1,
|
|
1567
|
-
borderTopColor: '#e0e0e0',
|
|
1568
|
-
flexDirection: 'row',
|
|
1569
|
-
alignItems: 'center',
|
|
1570
|
-
}}
|
|
1571
|
-
>
|
|
1327
|
+
return (
|
|
1572
1328
|
<View
|
|
1573
1329
|
style={{
|
|
1574
|
-
|
|
1330
|
+
height: 80,
|
|
1331
|
+
padding: 10,
|
|
1332
|
+
backgroundColor: 'white',
|
|
1333
|
+
borderTopWidth: 1,
|
|
1334
|
+
borderTopColor: '#e0e0e0',
|
|
1575
1335
|
flexDirection: 'row',
|
|
1576
1336
|
alignItems: 'center',
|
|
1577
|
-
// justifyContent: 'space-between',
|
|
1578
|
-
paddingHorizontal: 20,
|
|
1579
1337
|
}}
|
|
1580
1338
|
>
|
|
1581
|
-
<
|
|
1582
|
-
key={state?.context?.selectedImage}
|
|
1583
|
-
alt={'selected image'}
|
|
1584
|
-
source={{ uri: state?.context?.selectedImage }}
|
|
1585
|
-
size={'xs'}
|
|
1586
|
-
style={{
|
|
1587
|
-
width: 5,
|
|
1588
|
-
height: 5,
|
|
1589
|
-
borderRadius: 5,
|
|
1590
|
-
marginRight: 20,
|
|
1591
|
-
}}
|
|
1592
|
-
/>
|
|
1593
|
-
|
|
1594
|
-
<TouchableHighlight
|
|
1595
|
-
underlayColor="#dddddd"
|
|
1596
|
-
onPress={() => safeSend({ type: ThreadActions.CLEAR_IMAGE })}
|
|
1339
|
+
<View
|
|
1597
1340
|
style={{
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
marginLeft: 10,
|
|
1603
|
-
elevation: 3,
|
|
1604
|
-
shadowColor: '#000',
|
|
1605
|
-
shadowOffset: { width: 0, height: 1 },
|
|
1606
|
-
shadowOpacity: 0.3,
|
|
1607
|
-
shadowRadius: 2,
|
|
1341
|
+
flex: 1,
|
|
1342
|
+
flexDirection: 'row',
|
|
1343
|
+
alignItems: 'center',
|
|
1344
|
+
paddingHorizontal: 20,
|
|
1608
1345
|
}}
|
|
1609
1346
|
>
|
|
1610
|
-
<
|
|
1611
|
-
|
|
1347
|
+
<Image
|
|
1348
|
+
key={state?.context?.selectedImage}
|
|
1349
|
+
alt={'selected image'}
|
|
1350
|
+
source={{ uri: state?.context?.selectedImage }}
|
|
1351
|
+
size={'xs'}
|
|
1352
|
+
style={{
|
|
1353
|
+
width: 5,
|
|
1354
|
+
height: 5,
|
|
1355
|
+
borderRadius: 5,
|
|
1356
|
+
marginRight: 20,
|
|
1357
|
+
}}
|
|
1358
|
+
/>
|
|
1359
|
+
|
|
1360
|
+
<TouchableHighlight
|
|
1361
|
+
underlayColor="#dddddd"
|
|
1362
|
+
onPress={() => safeSend({ type: ThreadActions.CLEAR_IMAGE })}
|
|
1363
|
+
style={{
|
|
1364
|
+
backgroundColor: '#f44336',
|
|
1365
|
+
paddingVertical: 2,
|
|
1366
|
+
paddingHorizontal: 5,
|
|
1367
|
+
borderRadius: 5,
|
|
1368
|
+
marginLeft: 10,
|
|
1369
|
+
elevation: 3,
|
|
1370
|
+
shadowColor: '#000',
|
|
1371
|
+
shadowOffset: { width: 0, height: 1 },
|
|
1372
|
+
shadowOpacity: 0.3,
|
|
1373
|
+
shadowRadius: 2,
|
|
1374
|
+
}}
|
|
1375
|
+
>
|
|
1376
|
+
<Text style={{ color: 'white', fontWeight: 'bold' }}>X</Text>
|
|
1377
|
+
</TouchableHighlight>
|
|
1378
|
+
</View>
|
|
1612
1379
|
</View>
|
|
1613
|
-
|
|
1380
|
+
);
|
|
1381
|
+
},
|
|
1382
|
+
[state?.context?.selectedImage, safeSend],
|
|
1383
|
+
);
|
|
1384
|
+
|
|
1385
|
+
const renderInputToolbar = useCallback((props) => {
|
|
1386
|
+
return (
|
|
1387
|
+
<InputToolbar
|
|
1388
|
+
{...props}
|
|
1389
|
+
containerStyle={{
|
|
1390
|
+
backgroundColor: 'white',
|
|
1391
|
+
borderTopWidth: 1,
|
|
1392
|
+
borderTopColor: colors.gray[200],
|
|
1393
|
+
paddingHorizontal: 4,
|
|
1394
|
+
paddingVertical: 4,
|
|
1395
|
+
}}
|
|
1396
|
+
primaryStyle={{
|
|
1397
|
+
alignItems: 'center',
|
|
1398
|
+
}}
|
|
1399
|
+
/>
|
|
1614
1400
|
);
|
|
1615
|
-
};
|
|
1401
|
+
}, []);
|
|
1616
1402
|
|
|
1617
1403
|
const setImageViewerObject = (obj: any, v: boolean) => {
|
|
1618
1404
|
setImageObject(obj);
|
|
1619
1405
|
setImageViewer(v);
|
|
1620
1406
|
};
|
|
1621
1407
|
|
|
1408
|
+
// Add back the renderMessageText function (memoized)
|
|
1409
|
+
const renderMessageText = useCallback(
|
|
1410
|
+
(props: any) => {
|
|
1411
|
+
const { currentMessage } = props;
|
|
1412
|
+
|
|
1413
|
+
// For ALERT type messages with call to action
|
|
1414
|
+
if (currentMessage.type === 'ALERT') {
|
|
1415
|
+
const attachment = currentMessage?.propsConfiguration?.contents?.attachment;
|
|
1416
|
+
let action: string = '';
|
|
1417
|
+
let actionId: any = '';
|
|
1418
|
+
let params: any = {};
|
|
1419
|
+
if (attachment?.callToAction?.extraParams) {
|
|
1420
|
+
const extraParams: any = attachment?.callToAction?.extraParams;
|
|
1421
|
+
const route: any = extraParams?.route ?? null;
|
|
1422
|
+
let path: any = null;
|
|
1423
|
+
let param: any = null;
|
|
1424
|
+
if (role && role == PreDefinedRole.Guest) {
|
|
1425
|
+
path = route?.guest?.name ? route?.guest?.name ?? null : null;
|
|
1426
|
+
param = route?.guest?.params ? route?.guest?.params ?? null : null;
|
|
1427
|
+
} else if (role && role == PreDefinedRole.Owner) {
|
|
1428
|
+
path = route?.host?.name ? route?.host?.name ?? null : null;
|
|
1429
|
+
param = route?.host?.params ? route?.host?.params ?? null : null;
|
|
1430
|
+
} else {
|
|
1431
|
+
path = route?.host?.name ? route?.host?.name ?? null : null;
|
|
1432
|
+
param = route?.host?.params ? route?.host?.params ?? null : null;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
action = path;
|
|
1436
|
+
params = { ...param };
|
|
1437
|
+
} else if (attachment?.callToAction?.link) {
|
|
1438
|
+
action = CALL_TO_ACTION_PATH;
|
|
1439
|
+
actionId = attachment?.callToAction?.link.split('/').pop();
|
|
1440
|
+
params = { reservationId: actionId };
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
return (
|
|
1444
|
+
<>
|
|
1445
|
+
{attachment?.callToAction && action ? (
|
|
1446
|
+
<Box className={`bg-[${CALL_TO_ACTION_BOX_BGCOLOR}] rounded-[15] pb-2`}>
|
|
1447
|
+
<Button
|
|
1448
|
+
variant={'outline'}
|
|
1449
|
+
size={'sm'}
|
|
1450
|
+
className={`border-[${CALL_TO_ACTION_BUTTON_BORDERCOLOR}]`}
|
|
1451
|
+
onPress={() => action && params && navigation.navigate(action, params)}
|
|
1452
|
+
>
|
|
1453
|
+
<ButtonText className={`color-[${CALL_TO_ACTION_TEXT_COLOR}]`}>
|
|
1454
|
+
{attachment.callToAction.title}
|
|
1455
|
+
</ButtonText>
|
|
1456
|
+
</Button>
|
|
1457
|
+
<MessageText
|
|
1458
|
+
{...props}
|
|
1459
|
+
textStyle={{
|
|
1460
|
+
left: { marginLeft: 5, color: CALL_TO_ACTION_TEXT_COLOR, paddingHorizontal: 2 },
|
|
1461
|
+
}}
|
|
1462
|
+
/>
|
|
1463
|
+
</Box>
|
|
1464
|
+
) : (
|
|
1465
|
+
<MessageText {...props} textStyle={{ left: { marginLeft: 5 } }} />
|
|
1466
|
+
)}
|
|
1467
|
+
</>
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1470
|
+
// For file attachment messages, don't show the "File attachment" text
|
|
1471
|
+
else if (currentMessage.text === '📎 File attachment') {
|
|
1472
|
+
// Return null to not render any text for these messages
|
|
1473
|
+
return null;
|
|
1474
|
+
}
|
|
1475
|
+
// Default text rendering
|
|
1476
|
+
else {
|
|
1477
|
+
return <MessageText {...props} textStyle={{ left: { marginLeft: 5 } }} />;
|
|
1478
|
+
}
|
|
1479
|
+
},
|
|
1480
|
+
[role, navigation],
|
|
1481
|
+
);
|
|
1482
|
+
|
|
1483
|
+
const renderMessage = useCallback(
|
|
1484
|
+
(props: any) => {
|
|
1485
|
+
return (
|
|
1486
|
+
<SlackMessage {...props} isShowImageViewer={isShowImageViewer} setImageViewer={setImageViewerObject} />
|
|
1487
|
+
);
|
|
1488
|
+
},
|
|
1489
|
+
[isShowImageViewer, setImageViewerObject],
|
|
1490
|
+
);
|
|
1491
|
+
|
|
1622
1492
|
const modalContent = React.useMemo(() => {
|
|
1623
1493
|
if (!imageObject) return <></>;
|
|
1624
1494
|
const { image, _id } = imageObject;
|
|
@@ -1636,35 +1506,12 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1636
1506
|
);
|
|
1637
1507
|
}, [imageObject]);
|
|
1638
1508
|
|
|
1639
|
-
const renderMessage = (props: any) => {
|
|
1640
|
-
return <SlackMessage {...props} isShowImageViewer={isShowImageViewer} setImageViewer={setImageViewerObject} />;
|
|
1641
|
-
};
|
|
1642
|
-
|
|
1643
1509
|
// Define a memo that provides the current message text from state
|
|
1644
1510
|
const currentMessageText = useMemo(() => {
|
|
1645
1511
|
const text = safeContextProperty('messageText', '') || ' ';
|
|
1646
1512
|
return text;
|
|
1647
1513
|
}, [safeContextProperty('messageText')]);
|
|
1648
1514
|
|
|
1649
|
-
// Define a custom renderInputToolbar function
|
|
1650
|
-
const renderInputToolbar = (props) => {
|
|
1651
|
-
return (
|
|
1652
|
-
<InputToolbar
|
|
1653
|
-
{...props}
|
|
1654
|
-
containerStyle={{
|
|
1655
|
-
backgroundColor: 'white',
|
|
1656
|
-
borderTopWidth: 1,
|
|
1657
|
-
borderTopColor: colors.gray[200],
|
|
1658
|
-
paddingHorizontal: 4,
|
|
1659
|
-
paddingVertical: 4,
|
|
1660
|
-
}}
|
|
1661
|
-
primaryStyle={{
|
|
1662
|
-
alignItems: 'center',
|
|
1663
|
-
}}
|
|
1664
|
-
/>
|
|
1665
|
-
);
|
|
1666
|
-
};
|
|
1667
|
-
|
|
1668
1515
|
// Add a function to load messages with specific skip value for debugging
|
|
1669
1516
|
const forceLoadMessages = useCallback(
|
|
1670
1517
|
(skipValue: number) => {
|
|
@@ -1721,6 +1568,144 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1721
1568
|
[channelId, parentId, getThreadMessages, safeSend],
|
|
1722
1569
|
);
|
|
1723
1570
|
|
|
1571
|
+
// Optimize the onFetchOld function to be more efficient
|
|
1572
|
+
const onFetchOld = useCallback(() => {
|
|
1573
|
+
const totalCount = safeContextProperty('totalCount', 0);
|
|
1574
|
+
const threadMessages = safeContextProperty('threadMessages', []);
|
|
1575
|
+
const isLoading = safeContextProperty('loadingOldMessages', false);
|
|
1576
|
+
|
|
1577
|
+
if (totalCount <= threadMessages.length || isLoading) {
|
|
1578
|
+
// Make sure we're not stuck in loading state
|
|
1579
|
+
if (isLoading) {
|
|
1580
|
+
safeSend({
|
|
1581
|
+
type: ThreadActions.STOP_LOADING,
|
|
1582
|
+
data: { loadingOldMessages: false },
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
if (__DEV__) console.log('No more messages to load or already loading');
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
if (__DEV__) console.log('Loading more messages - current count:', threadMessages.length, 'of', totalCount);
|
|
1590
|
+
|
|
1591
|
+
// Set the loading state specifically for old messages
|
|
1592
|
+
safeSend({
|
|
1593
|
+
type: ThreadActions.FETCH_MORE_MESSAGES,
|
|
1594
|
+
data: { loadingOldMessages: true },
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
// Use simple, consistent approach: Skip=0, Limit=50
|
|
1598
|
+
if (__DEV__) console.log('Using proven approach: Skip=0, Limit=50');
|
|
1599
|
+
|
|
1600
|
+
// Create query variables once
|
|
1601
|
+
const queryVariables = {
|
|
1602
|
+
channelId: channelId?.toString(),
|
|
1603
|
+
role: role?.toString(),
|
|
1604
|
+
postParentId: !parentId || parentId == 0 ? null : parentId?.toString(),
|
|
1605
|
+
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
1606
|
+
limit: 50,
|
|
1607
|
+
skip: 0,
|
|
1608
|
+
};
|
|
1609
|
+
|
|
1610
|
+
if (__DEV__) console.log('Query variables:', JSON.stringify(queryVariables));
|
|
1611
|
+
|
|
1612
|
+
fetchMoreMessages({
|
|
1613
|
+
variables: queryVariables,
|
|
1614
|
+
})
|
|
1615
|
+
.then((res: any) => {
|
|
1616
|
+
if (__DEV__) console.log('API response received with status:', res ? 'success' : 'empty');
|
|
1617
|
+
|
|
1618
|
+
if (res?.data?.getPostThread) {
|
|
1619
|
+
const threads: any = res?.data?.getPostThread;
|
|
1620
|
+
const threadReplies = threads?.replies ?? [];
|
|
1621
|
+
const actualTotalCount = threads?.replyCount ?? 0;
|
|
1622
|
+
|
|
1623
|
+
if (__DEV__) {
|
|
1624
|
+
console.log('API response details:');
|
|
1625
|
+
console.log('- replyCount:', threads?.replyCount);
|
|
1626
|
+
console.log('- replies array length:', threadReplies.length);
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
if (threadReplies.length > 0) {
|
|
1630
|
+
// Compare with our existing messages to find the ones we're missing
|
|
1631
|
+
const existingIds = new Set(threadMessages.map((msg) => msg.id));
|
|
1632
|
+
const newUniqueMessages = threadReplies.filter((msg) => !existingIds.has(msg.id));
|
|
1633
|
+
|
|
1634
|
+
if (__DEV__)
|
|
1635
|
+
console.log(
|
|
1636
|
+
`Found ${newUniqueMessages.length} unique new messages out of ${threadReplies.length} received`,
|
|
1637
|
+
);
|
|
1638
|
+
|
|
1639
|
+
// If no new unique messages, it means we already have everything
|
|
1640
|
+
if (newUniqueMessages.length === 0) {
|
|
1641
|
+
if (__DEV__) console.log('No new unique messages found, adjusting total count');
|
|
1642
|
+
|
|
1643
|
+
// Register this as a failed load attempt
|
|
1644
|
+
registerLoadAttemptResult(false);
|
|
1645
|
+
|
|
1646
|
+
// Adjust total count to match what we have
|
|
1647
|
+
safeSend({
|
|
1648
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1649
|
+
data: {
|
|
1650
|
+
messages: threadMessages,
|
|
1651
|
+
totalCount: threadMessages.length,
|
|
1652
|
+
threadPost: safeContextProperty('threadPost', []),
|
|
1653
|
+
postThread: safeContextProperty('postThread', null),
|
|
1654
|
+
},
|
|
1655
|
+
});
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
// Register success since we found new messages
|
|
1660
|
+
registerLoadAttemptResult(true);
|
|
1661
|
+
|
|
1662
|
+
if (__DEV__) console.log(`Adding ${newUniqueMessages.length} new messages to thread`);
|
|
1663
|
+
|
|
1664
|
+
safeSend({
|
|
1665
|
+
type: 'FETCH_MORE_MESSAGES_SUCCESS',
|
|
1666
|
+
data: {
|
|
1667
|
+
messages: newUniqueMessages,
|
|
1668
|
+
totalCount: actualTotalCount,
|
|
1669
|
+
loadingOldMessages: false,
|
|
1670
|
+
},
|
|
1671
|
+
});
|
|
1672
|
+
} else {
|
|
1673
|
+
if (__DEV__) console.log('No thread replies returned when loading more messages');
|
|
1674
|
+
registerLoadAttemptResult(false);
|
|
1675
|
+
|
|
1676
|
+
// Adjust total count to match what we have, since server says there are no more messages
|
|
1677
|
+
safeSend({
|
|
1678
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1679
|
+
data: {
|
|
1680
|
+
messages: threadMessages,
|
|
1681
|
+
totalCount: threadMessages.length,
|
|
1682
|
+
threadPost: safeContextProperty('threadPost', []),
|
|
1683
|
+
postThread: safeContextProperty('postThread', null),
|
|
1684
|
+
},
|
|
1685
|
+
});
|
|
1686
|
+
}
|
|
1687
|
+
} else {
|
|
1688
|
+
if (__DEV__) console.log('No thread data returned when loading more messages');
|
|
1689
|
+
registerLoadAttemptResult(false);
|
|
1690
|
+
safeSend({
|
|
1691
|
+
type: ThreadActions.STOP_LOADING,
|
|
1692
|
+
data: { loadingOldMessages: false },
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
})
|
|
1696
|
+
.catch((error: any) => {
|
|
1697
|
+
console.error('Error fetching more messages:', error);
|
|
1698
|
+
registerLoadAttemptResult(false);
|
|
1699
|
+
safeSend({
|
|
1700
|
+
type: 'ERROR',
|
|
1701
|
+
data: {
|
|
1702
|
+
message: error.message,
|
|
1703
|
+
loadingOldMessages: false,
|
|
1704
|
+
},
|
|
1705
|
+
});
|
|
1706
|
+
});
|
|
1707
|
+
}, [parentId, channelId, role, safeContextProperty, safeSend, fetchMoreMessages, registerLoadAttemptResult]);
|
|
1708
|
+
|
|
1724
1709
|
return (
|
|
1725
1710
|
<SafeAreaView style={{ flex: 1 }}>
|
|
1726
1711
|
{safeContextProperty('loadingOldMessages', false) === true && (
|
|
@@ -2104,6 +2089,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
2104
2089
|
scrollEventThrottle: 16,
|
|
2105
2090
|
keyboardDismissMode: 'on-drag',
|
|
2106
2091
|
keyboardShouldPersistTaps: 'handled',
|
|
2092
|
+
// removeClippedSubviews={true}
|
|
2107
2093
|
}}
|
|
2108
2094
|
onSend={(messages) => {
|
|
2109
2095
|
if (!messages || messages.length === 0) {
|
|
@@ -2116,7 +2102,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
2116
2102
|
const currentInputText = currentMessageText;
|
|
2117
2103
|
const messageToSend = currentInputText?.trim() || messages[0]?.text?.trim() || ' ';
|
|
2118
2104
|
|
|
2119
|
-
console.log('GiftedChat onSend triggered with text from state:', messageToSend);
|
|
2105
|
+
if (__DEV__) console.log('GiftedChat onSend triggered with text from state:', messageToSend);
|
|
2120
2106
|
|
|
2121
2107
|
// Make sure we update the message text in state
|
|
2122
2108
|
safeSend({
|
|
@@ -2126,18 +2112,19 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
2126
2112
|
|
|
2127
2113
|
// Then send the message
|
|
2128
2114
|
if (safeContextProperty('images', []).length > 0) {
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2115
|
+
if (__DEV__)
|
|
2116
|
+
console.log(
|
|
2117
|
+
'Sending message with file:',
|
|
2118
|
+
messageToSend,
|
|
2119
|
+
'Images:',
|
|
2120
|
+
safeContextProperty('images', []).length,
|
|
2121
|
+
);
|
|
2135
2122
|
safeSend({
|
|
2136
2123
|
type: ThreadActions.SEND_THREAD_MESSAGE_WITH_FILE,
|
|
2137
2124
|
data: { messageText: messageToSend },
|
|
2138
2125
|
});
|
|
2139
2126
|
} else {
|
|
2140
|
-
console.log('Sending text message:', messageToSend);
|
|
2127
|
+
if (__DEV__) console.log('Sending text message:', messageToSend);
|
|
2141
2128
|
safeSend({
|
|
2142
2129
|
type: ThreadActions.SEND_THREAD_MESSAGE,
|
|
2143
2130
|
data: { messageText: messageToSend },
|
|
@@ -2146,12 +2133,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
2146
2133
|
}}
|
|
2147
2134
|
text={currentMessageText}
|
|
2148
2135
|
onInputTextChanged={(text) => {
|
|
2149
|
-
//
|
|
2150
|
-
if (text.length % 5 === 0 || text.length < 5) {
|
|
2151
|
-
console.log('Input text changed:', text);
|
|
2152
|
-
}
|
|
2153
|
-
|
|
2154
|
-
// Set the text in the state
|
|
2136
|
+
// Set the text in the state without excessive logging
|
|
2155
2137
|
safeSend({
|
|
2156
2138
|
type: ThreadActions.SET_MESSAGE_TEXT,
|
|
2157
2139
|
data: { messageText: text },
|
|
@@ -2176,7 +2158,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
2176
2158
|
user={{
|
|
2177
2159
|
_id: auth?.id || '',
|
|
2178
2160
|
}}
|
|
2179
|
-
isTyping={
|
|
2161
|
+
isTyping={safeContextProperty('loading', false)}
|
|
2180
2162
|
alwaysShowSend={safeContextProperty('loading', false) ? false : true}
|
|
2181
2163
|
infiniteScroll={true}
|
|
2182
2164
|
renderSend={renderSend}
|
|
@@ -2185,6 +2167,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
2185
2167
|
renderActions={renderActions}
|
|
2186
2168
|
renderAccessory={!!state?.context?.selectedImage ? renderAccessory : undefined}
|
|
2187
2169
|
renderMessage={renderMessage}
|
|
2170
|
+
renderMessageText={renderMessageText}
|
|
2188
2171
|
maxInputLength={1000}
|
|
2189
2172
|
placeholder="Type a message..."
|
|
2190
2173
|
showUserAvatar={true}
|
|
@@ -2249,7 +2232,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
2249
2232
|
if (!subscriptionData.data) return prev;
|
|
2250
2233
|
const newMessage: any = subscriptionData?.data?.threadChatMessageAdded;
|
|
2251
2234
|
const prevReplyCount: any = prev?.getPostThread?.replyCount;
|
|
2252
|
-
const newReplyCount = prevReplyCount || 0 + 1;
|
|
2235
|
+
const newReplyCount = (prevReplyCount || 0) + 1;
|
|
2253
2236
|
const replies = prev?.getPostThread?.replies || [];
|
|
2254
2237
|
|
|
2255
2238
|
safeSend({
|
|
@@ -2280,7 +2263,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
2280
2263
|
/>
|
|
2281
2264
|
</>
|
|
2282
2265
|
)}
|
|
2283
|
-
messagesContainerStyle={messageList?.length == 0
|
|
2266
|
+
messagesContainerStyle={messageList?.length == 0 ? { transform: [{ scaleY: -1 }] } : undefined}
|
|
2284
2267
|
renderChatEmpty={() => (
|
|
2285
2268
|
<>
|
|
2286
2269
|
{!threadLoading && messageList && messageList?.length == 0 && (
|