@messenger-box/platform-mobile 10.0.3-alpha.18 → 10.0.3-alpha.19
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/containers/Dialogs.js +21 -290
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadConversationView.js +448 -32
- package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
- package/package.json +2 -2
- package/src/screens/inbox/containers/Dialogs.tsx +123 -415
- package/src/screens/inbox/containers/ThreadConversationView.tsx +684 -25
- package/lib/screens/inbox/containers/workflow/dialogs-xstate.js +0 -235
- package/lib/screens/inbox/containers/workflow/dialogs-xstate.js.map +0 -1
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
Spinner,
|
|
15
15
|
Text,
|
|
16
16
|
} from '@admin-layout/gluestack-ui-mobile';
|
|
17
|
-
import { Platform, Linking, SafeAreaView, View, TouchableHighlight } from 'react-native';
|
|
17
|
+
import { Platform, Linking, SafeAreaView, View, TouchableHighlight, Alert } from 'react-native';
|
|
18
18
|
import { useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
|
|
19
19
|
import { useSelector } from 'react-redux';
|
|
20
20
|
import { orderBy, startCase, uniqBy } from 'lodash-es';
|
|
@@ -214,6 +214,8 @@ function useSafeMachine(machine) {
|
|
|
214
214
|
context: {
|
|
215
215
|
...prev.context,
|
|
216
216
|
loading: false,
|
|
217
|
+
loadingOldMessages:
|
|
218
|
+
event.data?.loadingOldMessages === false ? false : prev.context.loadingOldMessages,
|
|
217
219
|
},
|
|
218
220
|
}));
|
|
219
221
|
} else if (event.type === ThreadActions.SEND_THREAD_MESSAGE) {
|
|
@@ -287,12 +289,76 @@ function useSafeMachine(machine) {
|
|
|
287
289
|
} else if (event.type === 'FETCH_MORE_MESSAGES_SUCCESS') {
|
|
288
290
|
setState((prev) => {
|
|
289
291
|
const newMessages = event.data?.messages || [];
|
|
292
|
+
const apiTotalCount = event.data?.totalCount;
|
|
293
|
+
console.log(
|
|
294
|
+
`Merging ${newMessages.length} older messages with ${prev.context.threadMessages.length} existing messages`,
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// Debug: Log the dates of the messages for troubleshooting
|
|
298
|
+
if (newMessages.length > 0) {
|
|
299
|
+
console.log('First new message date:', new Date(newMessages[0].createdAt).toISOString());
|
|
300
|
+
console.log(
|
|
301
|
+
'Last new message date:',
|
|
302
|
+
new Date(newMessages[newMessages.length - 1].createdAt).toISOString(),
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (prev.context.threadMessages.length > 0) {
|
|
307
|
+
console.log(
|
|
308
|
+
'First existing message date:',
|
|
309
|
+
new Date(prev.context.threadMessages[0].createdAt).toISOString(),
|
|
310
|
+
);
|
|
311
|
+
console.log(
|
|
312
|
+
'Last existing message date:',
|
|
313
|
+
new Date(
|
|
314
|
+
prev.context.threadMessages[prev.context.threadMessages.length - 1].createdAt,
|
|
315
|
+
).toISOString(),
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// If no new messages returned but total count says there should be more
|
|
320
|
+
if (newMessages.length === 0 && prev.context.totalCount > prev.context.threadMessages.length) {
|
|
321
|
+
console.log('No new messages found despite totalCount indicating more should exist');
|
|
322
|
+
|
|
323
|
+
// Adjust totalCount to match reality
|
|
324
|
+
return {
|
|
325
|
+
...prev,
|
|
326
|
+
context: {
|
|
327
|
+
...prev.context,
|
|
328
|
+
loadingOldMessages: false,
|
|
329
|
+
totalCount: prev.context.threadMessages.length,
|
|
330
|
+
},
|
|
331
|
+
value: 'active',
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Make sure we don't add duplicate messages
|
|
336
|
+
const combinedMessages = uniqBy([...prev.context.threadMessages, ...newMessages], 'id');
|
|
337
|
+
|
|
338
|
+
// GiftedChat expects messages sorted by date (newest first)
|
|
339
|
+
const sortedMessages = orderBy(
|
|
340
|
+
combinedMessages,
|
|
341
|
+
[(msg) => new Date(msg.createdAt).getTime()],
|
|
342
|
+
['desc'],
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
// Use the total count from the API response if available, otherwise keep the current count
|
|
346
|
+
const newTotalCount =
|
|
347
|
+
typeof apiTotalCount === 'number'
|
|
348
|
+
? apiTotalCount
|
|
349
|
+
: Math.max(sortedMessages.length, prev.context.totalCount);
|
|
350
|
+
|
|
351
|
+
console.log(
|
|
352
|
+
`Total messages after merge and sort: ${sortedMessages.length}, totalCount: ${newTotalCount}`,
|
|
353
|
+
);
|
|
354
|
+
|
|
290
355
|
return {
|
|
291
356
|
...prev,
|
|
292
357
|
context: {
|
|
293
358
|
...prev.context,
|
|
294
359
|
loadingOldMessages: false,
|
|
295
|
-
threadMessages:
|
|
360
|
+
threadMessages: sortedMessages,
|
|
361
|
+
totalCount: newTotalCount,
|
|
296
362
|
},
|
|
297
363
|
value: 'active',
|
|
298
364
|
};
|
|
@@ -432,6 +498,64 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
432
498
|
{ data, loading: threadLoading, fetchMore: fetchMoreMessages, refetch: refetchThreadMessages, subscribeToMore },
|
|
433
499
|
] = useGetPostThreadLazyQuery({ fetchPolicy: 'cache-and-network' });
|
|
434
500
|
|
|
501
|
+
// Add a function to force refresh all messages
|
|
502
|
+
const forceRefreshMessages = useCallback(() => {
|
|
503
|
+
console.log('Force refreshing all messages');
|
|
504
|
+
|
|
505
|
+
// Clear the current messages first
|
|
506
|
+
safeSend({
|
|
507
|
+
type: ThreadActions.CLEAR_MESSAGES,
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
// Then trigger a refetch
|
|
511
|
+
if (channelId && parentId) {
|
|
512
|
+
safeSend({
|
|
513
|
+
type: ThreadActions.START_LOADING,
|
|
514
|
+
data: { loading: true },
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
getThreadMessages({
|
|
518
|
+
variables: {
|
|
519
|
+
channelId: channelId?.toString(),
|
|
520
|
+
role: role?.toString(),
|
|
521
|
+
postParentId: !parentId || parentId == 0 ? null : parentId?.toString(),
|
|
522
|
+
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
523
|
+
limit: 50, // Use larger limit that proved to work
|
|
524
|
+
},
|
|
525
|
+
})
|
|
526
|
+
.then(({ data }) => {
|
|
527
|
+
if (data?.getPostThread) {
|
|
528
|
+
const threads: any = data.getPostThread;
|
|
529
|
+
const threadPost = threads?.post ?? [];
|
|
530
|
+
const threadReplies = threads?.replies ?? [];
|
|
531
|
+
const messageTotalCount = threads?.replyCount ?? 0;
|
|
532
|
+
const messages = [...threadReplies];
|
|
533
|
+
|
|
534
|
+
console.log(
|
|
535
|
+
`Force refresh complete. Got ${messages.length} messages of ${messageTotalCount} total`,
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
safeSend({
|
|
539
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
540
|
+
data: {
|
|
541
|
+
messages,
|
|
542
|
+
totalCount: messageTotalCount,
|
|
543
|
+
threadPost: threadPost,
|
|
544
|
+
postThread: threads,
|
|
545
|
+
},
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
})
|
|
549
|
+
.catch((error) => {
|
|
550
|
+
console.error('Error during force refresh:', error);
|
|
551
|
+
safeSend({
|
|
552
|
+
type: 'ERROR',
|
|
553
|
+
data: { message: error.message },
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
}, [channelId, parentId, getThreadMessages, safeSend]);
|
|
558
|
+
|
|
435
559
|
useFocusEffect(
|
|
436
560
|
React.useCallback(() => {
|
|
437
561
|
// navigation?.setOptions({ title: params?.title ?? 'Thread' });
|
|
@@ -443,6 +567,11 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
443
567
|
<MaterialIcons size={20} name="arrow-back-ios" color={'black'} />
|
|
444
568
|
</Button>
|
|
445
569
|
),
|
|
570
|
+
headerRight: () => (
|
|
571
|
+
<Button className="bg-transparent active:bg-gray-200 mr-2" onPress={forceRefreshMessages}>
|
|
572
|
+
<MaterialIcons size={20} name="refresh" color={'black'} />
|
|
573
|
+
</Button>
|
|
574
|
+
),
|
|
446
575
|
});
|
|
447
576
|
|
|
448
577
|
// Set initial context when focused
|
|
@@ -462,7 +591,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
462
591
|
return () => {
|
|
463
592
|
safeSend({ type: ThreadActions.CLEAR_MESSAGES });
|
|
464
593
|
};
|
|
465
|
-
}, [postParentId]),
|
|
594
|
+
}, [postParentId, forceRefreshMessages]),
|
|
466
595
|
);
|
|
467
596
|
|
|
468
597
|
// Effect for when in FetchThreadMessages state
|
|
@@ -500,13 +629,14 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
500
629
|
// Fetch thread messages function
|
|
501
630
|
const fetchThreadMessages = useCallback(() => {
|
|
502
631
|
if (channelId && parentId) {
|
|
632
|
+
console.log('Initial fetch of thread messages using larger limit (50)');
|
|
503
633
|
getThreadMessages({
|
|
504
634
|
variables: {
|
|
505
635
|
channelId: channelId?.toString(),
|
|
506
636
|
role: role?.toString(),
|
|
507
637
|
postParentId: !parentId || parentId == 0 ? null : parentId?.toString(),
|
|
508
638
|
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
509
|
-
limit:
|
|
639
|
+
limit: 50, // Use larger limit that proved to work
|
|
510
640
|
},
|
|
511
641
|
})
|
|
512
642
|
.then(({ data }) => {
|
|
@@ -517,6 +647,10 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
517
647
|
const messageTotalCount = threads?.replyCount ?? 0;
|
|
518
648
|
const messages = [...threadReplies];
|
|
519
649
|
|
|
650
|
+
console.log(
|
|
651
|
+
`Initial fetch complete. Got ${messages.length} messages of ${messageTotalCount} total`,
|
|
652
|
+
);
|
|
653
|
+
|
|
520
654
|
safeSend({
|
|
521
655
|
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
522
656
|
data: {
|
|
@@ -563,6 +697,74 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
563
697
|
}
|
|
564
698
|
}, [safeContextProperty('selectedImage')]);
|
|
565
699
|
|
|
700
|
+
// Add a safety timeout to clear loading state if it gets stuck
|
|
701
|
+
React.useEffect(() => {
|
|
702
|
+
const isLoading = safeContextProperty('loadingOldMessages', false);
|
|
703
|
+
|
|
704
|
+
if (isLoading) {
|
|
705
|
+
console.log('Message loading timeout safety started');
|
|
706
|
+
const timeoutId = setTimeout(() => {
|
|
707
|
+
// Check if we're still loading after 10 seconds
|
|
708
|
+
if (safeContextProperty('loadingOldMessages', false)) {
|
|
709
|
+
console.log('Message loading timed out - resetting state');
|
|
710
|
+
safeSend({
|
|
711
|
+
type: ThreadActions.STOP_LOADING,
|
|
712
|
+
data: { loadingOldMessages: false },
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
}, 10000); // 10 second timeout
|
|
716
|
+
|
|
717
|
+
return () => clearTimeout(timeoutId);
|
|
718
|
+
}
|
|
719
|
+
}, [safeContextProperty('loadingOldMessages')]);
|
|
720
|
+
|
|
721
|
+
// Add a safety counter to detect and fix incorrect message counts automatically
|
|
722
|
+
const failedLoadAttemptsRef = useRef(0);
|
|
723
|
+
|
|
724
|
+
// Track failed attempts to load more messages
|
|
725
|
+
const registerLoadAttemptResult = useCallback((success: boolean) => {
|
|
726
|
+
if (!success) {
|
|
727
|
+
failedLoadAttemptsRef.current += 1;
|
|
728
|
+
console.log(`Failed load attempt registered, count: ${failedLoadAttemptsRef.current}`);
|
|
729
|
+
} else {
|
|
730
|
+
// Reset counter on successful load
|
|
731
|
+
failedLoadAttemptsRef.current = 0;
|
|
732
|
+
}
|
|
733
|
+
}, []);
|
|
734
|
+
|
|
735
|
+
// Watch for failed load attempts and auto-fix the count after 3 consecutive failures
|
|
736
|
+
React.useEffect(() => {
|
|
737
|
+
const isLoading = safeContextProperty('loadingOldMessages', false);
|
|
738
|
+
const totalCount = safeContextProperty('totalCount', 0);
|
|
739
|
+
const messagesCount = safeContextProperty('threadMessages', []).length;
|
|
740
|
+
|
|
741
|
+
// If we're not loading and there's a discrepancy in message counts
|
|
742
|
+
if (!isLoading && totalCount > messagesCount) {
|
|
743
|
+
// If we've had 3 consecutive failed attempts, fix the count
|
|
744
|
+
if (failedLoadAttemptsRef.current >= 2) {
|
|
745
|
+
console.log(
|
|
746
|
+
`Auto-fixing incorrect message count after ${
|
|
747
|
+
failedLoadAttemptsRef.current + 1
|
|
748
|
+
} failed load attempts`,
|
|
749
|
+
);
|
|
750
|
+
console.log(`Adjusting totalCount from ${totalCount} to ${messagesCount}`);
|
|
751
|
+
|
|
752
|
+
safeSend({
|
|
753
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
754
|
+
data: {
|
|
755
|
+
messages: safeContextProperty('threadMessages', []),
|
|
756
|
+
totalCount: messagesCount,
|
|
757
|
+
threadPost: safeContextProperty('threadPost', []),
|
|
758
|
+
postThread: safeContextProperty('postThread', null),
|
|
759
|
+
},
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
// Reset the counter
|
|
763
|
+
failedLoadAttemptsRef.current = 0;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}, [safeContextProperty('loadingOldMessages'), safeContextProperty('threadMessages')]);
|
|
767
|
+
|
|
566
768
|
const scrollToBottom = React.useCallback(() => {
|
|
567
769
|
if (threadMessageListRef?.current) {
|
|
568
770
|
threadMessageListRef.current.scrollToBottom();
|
|
@@ -578,36 +780,111 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
578
780
|
|
|
579
781
|
// Set the loading state specifically for old messages
|
|
580
782
|
safeSend({
|
|
581
|
-
type: ThreadActions.
|
|
783
|
+
type: ThreadActions.FETCH_MORE_MESSAGES,
|
|
582
784
|
data: { loadingOldMessages: true },
|
|
583
785
|
});
|
|
584
786
|
|
|
787
|
+
// Since Skip=0, Limit=50 worked well, let's use that approach
|
|
788
|
+
console.log('Using proven approach: Skip=0, Limit=50');
|
|
789
|
+
|
|
790
|
+
// Try with a larger limit and skip=0, which we know works
|
|
791
|
+
const queryVariables = {
|
|
792
|
+
channelId: channelId?.toString(),
|
|
793
|
+
role: role?.toString(),
|
|
794
|
+
postParentId: !parentId || parentId == 0 ? null : parentId?.toString(),
|
|
795
|
+
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
796
|
+
limit: 50, // Use larger limit that proved to work
|
|
797
|
+
skip: 0, // Start from the beginning
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
console.log('Query variables:', JSON.stringify(queryVariables));
|
|
801
|
+
|
|
585
802
|
fetchMoreMessages({
|
|
586
|
-
variables:
|
|
587
|
-
channelId: channelId?.toString(),
|
|
588
|
-
role: role?.toString(),
|
|
589
|
-
postParentId: parentId?.toString(),
|
|
590
|
-
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
591
|
-
limit: MESSAGES_PER_PAGE,
|
|
592
|
-
skip: threadMessages.length,
|
|
593
|
-
},
|
|
803
|
+
variables: queryVariables,
|
|
594
804
|
})
|
|
595
805
|
.then((res: any) => {
|
|
806
|
+
console.log('API response received:', JSON.stringify(res?.data, null, 2));
|
|
807
|
+
|
|
596
808
|
if (res?.data?.getPostThread) {
|
|
597
809
|
const threads: any = res?.data?.getPostThread;
|
|
598
810
|
const threadReplies = threads?.replies ?? [];
|
|
811
|
+
// Get the actual total count from the response
|
|
812
|
+
const actualTotalCount = threads?.replyCount ?? 0;
|
|
813
|
+
|
|
814
|
+
console.log('API response details:');
|
|
815
|
+
console.log('- replyCount:', threads?.replyCount);
|
|
816
|
+
console.log('- replies array length:', threadReplies.length);
|
|
817
|
+
console.log(
|
|
818
|
+
'- replies structure:',
|
|
819
|
+
threadReplies.length > 0
|
|
820
|
+
? `First item has fields: ${Object.keys(threadReplies[0]).join(', ')}`
|
|
821
|
+
: 'No items',
|
|
822
|
+
);
|
|
823
|
+
|
|
824
|
+
if (threadReplies.length > 0) {
|
|
825
|
+
console.log('- Sample message:', JSON.stringify(threadReplies[0], null, 2));
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
console.log(
|
|
829
|
+
'Successfully loaded more messages:',
|
|
830
|
+
threadReplies.length,
|
|
831
|
+
'of total:',
|
|
832
|
+
actualTotalCount,
|
|
833
|
+
);
|
|
834
|
+
console.log('Thread reply IDs:', threadReplies.map((msg) => msg.id).join(', '));
|
|
835
|
+
|
|
836
|
+
// Compare with our existing messages to find the ones we're missing
|
|
837
|
+
const existingIds = new Set(threadMessages.map((msg) => msg.id));
|
|
838
|
+
const newUniqueMessages = threadReplies.filter((msg) => !existingIds.has(msg.id));
|
|
839
|
+
|
|
840
|
+
console.log(
|
|
841
|
+
`Found ${newUniqueMessages.length} unique new messages out of ${threadReplies.length} received`,
|
|
842
|
+
);
|
|
843
|
+
|
|
844
|
+
// If we've received all messages but our count doesn't match, update the total count
|
|
845
|
+
if (actualTotalCount !== totalCount) {
|
|
846
|
+
console.log(
|
|
847
|
+
`Updating totalCount from ${totalCount} to ${actualTotalCount} based on API response`,
|
|
848
|
+
);
|
|
849
|
+
// This will be applied below when we process the messages
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// If no new unique messages, it means we already have everything
|
|
853
|
+
if (newUniqueMessages.length === 0) {
|
|
854
|
+
console.log('No new unique messages found, adjusting total count');
|
|
855
|
+
|
|
856
|
+
// Register this as a failed load attempt
|
|
857
|
+
registerLoadAttemptResult(false);
|
|
858
|
+
|
|
859
|
+
// Adjust total count to match what we have
|
|
860
|
+
safeSend({
|
|
861
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
862
|
+
data: {
|
|
863
|
+
messages: threadMessages,
|
|
864
|
+
totalCount: threadMessages.length,
|
|
865
|
+
threadPost: safeContextProperty('threadPost', []),
|
|
866
|
+
postThread: safeContextProperty('postThread', null),
|
|
867
|
+
},
|
|
868
|
+
});
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// Register success since we found new messages
|
|
873
|
+
registerLoadAttemptResult(true);
|
|
599
874
|
|
|
600
|
-
console.log(
|
|
875
|
+
console.log(`Adding ${newUniqueMessages.length} new messages to thread`);
|
|
601
876
|
|
|
602
877
|
safeSend({
|
|
603
878
|
type: 'FETCH_MORE_MESSAGES_SUCCESS',
|
|
604
879
|
data: {
|
|
605
|
-
messages:
|
|
880
|
+
messages: newUniqueMessages,
|
|
881
|
+
totalCount: actualTotalCount,
|
|
606
882
|
loadingOldMessages: false,
|
|
607
883
|
},
|
|
608
884
|
});
|
|
609
885
|
} else {
|
|
610
886
|
console.log('No thread data returned when loading more messages');
|
|
887
|
+
registerLoadAttemptResult(false);
|
|
611
888
|
safeSend({
|
|
612
889
|
type: ThreadActions.STOP_LOADING,
|
|
613
890
|
data: { loadingOldMessages: false },
|
|
@@ -616,6 +893,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
616
893
|
})
|
|
617
894
|
.catch((error: any) => {
|
|
618
895
|
console.error('Error fetching more messages:', error);
|
|
896
|
+
registerLoadAttemptResult(false);
|
|
619
897
|
safeSend({
|
|
620
898
|
type: 'ERROR',
|
|
621
899
|
data: {
|
|
@@ -626,18 +904,31 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
626
904
|
});
|
|
627
905
|
} else {
|
|
628
906
|
console.log('No more messages to load or already loading');
|
|
907
|
+
// Make sure we're not stuck in loading state
|
|
908
|
+
if (safeContextProperty('loadingOldMessages', false)) {
|
|
909
|
+
safeSend({
|
|
910
|
+
type: ThreadActions.STOP_LOADING,
|
|
911
|
+
data: { loadingOldMessages: false },
|
|
912
|
+
});
|
|
913
|
+
}
|
|
629
914
|
}
|
|
630
|
-
}, [parentId, channelId, state.context]);
|
|
915
|
+
}, [parentId, channelId, state.context, registerLoadAttemptResult]);
|
|
631
916
|
|
|
632
917
|
let onScroll = false;
|
|
633
918
|
|
|
634
919
|
const handleScrollToTop = ({ nativeEvent }: any) => {
|
|
635
920
|
// Check if we're near the top of the list
|
|
636
921
|
if (isCloseToTop(nativeEvent)) {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
922
|
+
const isLoading = safeContextProperty('loadingOldMessages', false);
|
|
923
|
+
const totalCount = safeContextProperty('totalCount', 0);
|
|
924
|
+
const currentCount = safeContextProperty('threadMessages', []).length;
|
|
925
|
+
const hasMoreMessages = totalCount > currentCount;
|
|
926
|
+
|
|
927
|
+
console.log(
|
|
928
|
+
`Scroll near top - Loading state: ${isLoading}, Messages: ${currentCount}/${totalCount}, Has more: ${hasMoreMessages}`,
|
|
929
|
+
);
|
|
930
|
+
|
|
931
|
+
if (!isLoading && hasMoreMessages) {
|
|
641
932
|
console.log('Near top of list - loading older messages');
|
|
642
933
|
safeSend({ type: ThreadActions.FETCH_MORE_MESSAGES });
|
|
643
934
|
}
|
|
@@ -650,8 +941,21 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
650
941
|
};
|
|
651
942
|
|
|
652
943
|
const isCloseToTop = ({ layoutMeasurement, contentOffset, contentSize }) => {
|
|
653
|
-
|
|
654
|
-
|
|
944
|
+
// We consider being "close to top" when scrolled to top 15% of visible area
|
|
945
|
+
const visibleHeight = layoutMeasurement.height;
|
|
946
|
+
const topThreshold = Math.min(80, visibleHeight * 0.15);
|
|
947
|
+
|
|
948
|
+
// For debugging
|
|
949
|
+
const distanceFromTop = contentOffset.y;
|
|
950
|
+
const totalContentHeight = contentSize.height;
|
|
951
|
+
|
|
952
|
+
console.log(
|
|
953
|
+
`Scroll position: ${distanceFromTop.toFixed(0)}px from top, threshold: ${topThreshold.toFixed(
|
|
954
|
+
0,
|
|
955
|
+
)}px, content height: ${totalContentHeight.toFixed(0)}px`,
|
|
956
|
+
);
|
|
957
|
+
|
|
958
|
+
return contentOffset.y <= topThreshold;
|
|
655
959
|
};
|
|
656
960
|
|
|
657
961
|
const onSelectImages = async () => {
|
|
@@ -994,7 +1298,18 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
994
1298
|
}
|
|
995
1299
|
|
|
996
1300
|
// Sort messages by date (newest first as required by GiftedChat)
|
|
997
|
-
const sortedMessages = res
|
|
1301
|
+
const sortedMessages = orderBy(res, [(msg) => new Date(msg.createdAt).getTime()], ['desc']);
|
|
1302
|
+
|
|
1303
|
+
// Log message dates to help with debugging
|
|
1304
|
+
if (sortedMessages.length > 0) {
|
|
1305
|
+
console.log(
|
|
1306
|
+
'Message date range:',
|
|
1307
|
+
new Date(sortedMessages[sortedMessages.length - 1].createdAt).toISOString(),
|
|
1308
|
+
'to',
|
|
1309
|
+
new Date(sortedMessages[0].createdAt).toISOString(),
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
998
1313
|
return sortedMessages;
|
|
999
1314
|
}, [safeContextProperty('threadMessages'), auth]);
|
|
1000
1315
|
|
|
@@ -1243,9 +1558,65 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1243
1558
|
);
|
|
1244
1559
|
};
|
|
1245
1560
|
|
|
1561
|
+
// Add a function to load messages with specific skip value for debugging
|
|
1562
|
+
const forceLoadMessages = useCallback(
|
|
1563
|
+
(skipValue: number) => {
|
|
1564
|
+
console.log(`Force loading messages with explicit skip=${skipValue}, limit=50`);
|
|
1565
|
+
|
|
1566
|
+
if (channelId && parentId) {
|
|
1567
|
+
safeSend({
|
|
1568
|
+
type: ThreadActions.START_LOADING,
|
|
1569
|
+
data: { loading: true },
|
|
1570
|
+
});
|
|
1571
|
+
|
|
1572
|
+
getThreadMessages({
|
|
1573
|
+
variables: {
|
|
1574
|
+
channelId: channelId?.toString(),
|
|
1575
|
+
role: role?.toString(),
|
|
1576
|
+
postParentId: !parentId || parentId == 0 ? null : parentId?.toString(),
|
|
1577
|
+
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
1578
|
+
skip: skipValue,
|
|
1579
|
+
limit: 50, // Use larger limit that proved to work
|
|
1580
|
+
},
|
|
1581
|
+
})
|
|
1582
|
+
.then(({ data }) => {
|
|
1583
|
+
if (data?.getPostThread) {
|
|
1584
|
+
const threads: any = data.getPostThread;
|
|
1585
|
+
const threadPost = threads?.post ?? [];
|
|
1586
|
+
const threadReplies = threads?.replies ?? [];
|
|
1587
|
+
const messageTotalCount = threads?.replyCount ?? 0;
|
|
1588
|
+
const messages = [...threadReplies];
|
|
1589
|
+
|
|
1590
|
+
console.log(
|
|
1591
|
+
`Force load with skip=${skipValue} complete. Got ${messages.length} messages of ${messageTotalCount} total`,
|
|
1592
|
+
);
|
|
1593
|
+
|
|
1594
|
+
safeSend({
|
|
1595
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1596
|
+
data: {
|
|
1597
|
+
messages,
|
|
1598
|
+
totalCount: messageTotalCount,
|
|
1599
|
+
threadPost: threadPost,
|
|
1600
|
+
postThread: threads,
|
|
1601
|
+
},
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
})
|
|
1605
|
+
.catch((error) => {
|
|
1606
|
+
console.error('Error during force load:', error);
|
|
1607
|
+
safeSend({
|
|
1608
|
+
type: 'ERROR',
|
|
1609
|
+
data: { message: error.message },
|
|
1610
|
+
});
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
},
|
|
1614
|
+
[channelId, parentId, getThreadMessages, safeSend],
|
|
1615
|
+
);
|
|
1616
|
+
|
|
1246
1617
|
return (
|
|
1247
1618
|
<SafeAreaView style={{ flex: 1 }}>
|
|
1248
|
-
{safeContextProperty('loadingOldMessages', false) && (
|
|
1619
|
+
{safeContextProperty('loadingOldMessages', false) === true && (
|
|
1249
1620
|
<Box className="absolute top-10 left-0 right-0 z-10 items-center">
|
|
1250
1621
|
<Box className="bg-blue-500/20 rounded-full px-4 py-2 flex-row items-center">
|
|
1251
1622
|
<Spinner color={colors.blue[500]} size="small" />
|
|
@@ -1253,6 +1624,294 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1253
1624
|
</Box>
|
|
1254
1625
|
</Box>
|
|
1255
1626
|
)}
|
|
1627
|
+
{!safeContextProperty('loadingOldMessages', false) &&
|
|
1628
|
+
safeContextProperty('totalCount', 0) > safeContextProperty('threadMessages', []).length && (
|
|
1629
|
+
<Box className="absolute top-10 left-0 right-0 z-10 items-center">
|
|
1630
|
+
<HStack space={2} className="px-2">
|
|
1631
|
+
<TouchableHighlight
|
|
1632
|
+
onPress={() => {
|
|
1633
|
+
console.log('Manual load more pressed');
|
|
1634
|
+
Alert.alert('Load Options', 'Choose loading method', [
|
|
1635
|
+
{
|
|
1636
|
+
text: 'Normal Load',
|
|
1637
|
+
onPress: () => safeSend({ type: ThreadActions.FETCH_MORE_MESSAGES }),
|
|
1638
|
+
},
|
|
1639
|
+
{
|
|
1640
|
+
text: 'Try Skip=0',
|
|
1641
|
+
onPress: () => forceLoadMessages(0),
|
|
1642
|
+
},
|
|
1643
|
+
{
|
|
1644
|
+
text: 'Try Skip=0, Limit=50',
|
|
1645
|
+
onPress: () => {
|
|
1646
|
+
// Try with a larger limit
|
|
1647
|
+
console.log('Force loading with explicit skip=0, limit=50');
|
|
1648
|
+
|
|
1649
|
+
safeSend({
|
|
1650
|
+
type: ThreadActions.START_LOADING,
|
|
1651
|
+
data: { loadingOldMessages: true },
|
|
1652
|
+
});
|
|
1653
|
+
|
|
1654
|
+
fetchMoreMessages({
|
|
1655
|
+
variables: {
|
|
1656
|
+
channelId: channelId?.toString(),
|
|
1657
|
+
role: role?.toString(),
|
|
1658
|
+
postParentId:
|
|
1659
|
+
!parentId || parentId == 0 ? null : parentId?.toString(),
|
|
1660
|
+
selectedFields:
|
|
1661
|
+
'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
1662
|
+
limit: 50, // Try a larger limit
|
|
1663
|
+
skip: 0,
|
|
1664
|
+
},
|
|
1665
|
+
})
|
|
1666
|
+
.then((res: any) => {
|
|
1667
|
+
console.log(
|
|
1668
|
+
'LARGE LIMIT response:',
|
|
1669
|
+
JSON.stringify(res?.data, null, 2),
|
|
1670
|
+
);
|
|
1671
|
+
|
|
1672
|
+
if (res?.data?.getPostThread) {
|
|
1673
|
+
const threads: any = res?.data?.getPostThread;
|
|
1674
|
+
const threadReplies = threads?.replies ?? [];
|
|
1675
|
+
const actualTotalCount = threads?.replyCount ?? 0;
|
|
1676
|
+
|
|
1677
|
+
console.log(
|
|
1678
|
+
`Large limit load complete. Got ${threadReplies.length} messages of ${actualTotalCount} total`,
|
|
1679
|
+
);
|
|
1680
|
+
|
|
1681
|
+
if (threadReplies.length > 0) {
|
|
1682
|
+
// Reset our message list with all available messages
|
|
1683
|
+
safeSend({
|
|
1684
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1685
|
+
data: {
|
|
1686
|
+
messages: threadReplies,
|
|
1687
|
+
totalCount: actualTotalCount,
|
|
1688
|
+
threadPost: safeContextProperty(
|
|
1689
|
+
'threadPost',
|
|
1690
|
+
[],
|
|
1691
|
+
),
|
|
1692
|
+
postThread: threads,
|
|
1693
|
+
},
|
|
1694
|
+
});
|
|
1695
|
+
} else {
|
|
1696
|
+
// Reset count if no messages found
|
|
1697
|
+
safeSend({
|
|
1698
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1699
|
+
data: {
|
|
1700
|
+
messages: safeContextProperty(
|
|
1701
|
+
'threadMessages',
|
|
1702
|
+
[],
|
|
1703
|
+
),
|
|
1704
|
+
totalCount: safeContextProperty(
|
|
1705
|
+
'threadMessages',
|
|
1706
|
+
[],
|
|
1707
|
+
).length,
|
|
1708
|
+
threadPost: safeContextProperty(
|
|
1709
|
+
'threadPost',
|
|
1710
|
+
[],
|
|
1711
|
+
),
|
|
1712
|
+
postThread: safeContextProperty(
|
|
1713
|
+
'postThread',
|
|
1714
|
+
null,
|
|
1715
|
+
),
|
|
1716
|
+
},
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
} else {
|
|
1720
|
+
safeSend({
|
|
1721
|
+
type: ThreadActions.STOP_LOADING,
|
|
1722
|
+
data: { loadingOldMessages: false },
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
})
|
|
1726
|
+
.catch((error) => {
|
|
1727
|
+
console.error('Error in large limit load:', error);
|
|
1728
|
+
safeSend({
|
|
1729
|
+
type: ThreadActions.STOP_LOADING,
|
|
1730
|
+
data: { loadingOldMessages: false },
|
|
1731
|
+
});
|
|
1732
|
+
});
|
|
1733
|
+
},
|
|
1734
|
+
},
|
|
1735
|
+
{
|
|
1736
|
+
text: 'Try Direct Fetch',
|
|
1737
|
+
onPress: () => {
|
|
1738
|
+
// Get current info
|
|
1739
|
+
const currentCount = safeContextProperty('threadMessages', []).length;
|
|
1740
|
+
const totalCount = safeContextProperty('totalCount', 0);
|
|
1741
|
+
const missingCount = totalCount - currentCount;
|
|
1742
|
+
|
|
1743
|
+
if (missingCount <= 0) {
|
|
1744
|
+
Alert.alert('Info', 'No missing messages to fetch');
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
console.log(
|
|
1749
|
+
`Attempting direct fetch of missing ${missingCount} messages`,
|
|
1750
|
+
);
|
|
1751
|
+
|
|
1752
|
+
// Try explicit query with exact parameters
|
|
1753
|
+
safeSend({
|
|
1754
|
+
type: ThreadActions.START_LOADING,
|
|
1755
|
+
data: { loadingOldMessages: true },
|
|
1756
|
+
});
|
|
1757
|
+
|
|
1758
|
+
// Special query directly for the missing messages
|
|
1759
|
+
getThreadMessages({
|
|
1760
|
+
variables: {
|
|
1761
|
+
channelId: channelId?.toString(),
|
|
1762
|
+
role: role?.toString(),
|
|
1763
|
+
postParentId:
|
|
1764
|
+
!parentId || parentId == 0 ? null : parentId?.toString(),
|
|
1765
|
+
selectedFields:
|
|
1766
|
+
'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
1767
|
+
limit: missingCount, // Only get the exact number we need
|
|
1768
|
+
skip: 0, // Start from the beginning
|
|
1769
|
+
},
|
|
1770
|
+
})
|
|
1771
|
+
.then(({ data }) => {
|
|
1772
|
+
console.log(
|
|
1773
|
+
'DIRECT FETCH response:',
|
|
1774
|
+
JSON.stringify(data, null, 2),
|
|
1775
|
+
);
|
|
1776
|
+
|
|
1777
|
+
if (data?.getPostThread) {
|
|
1778
|
+
const threads: any = data.getPostThread;
|
|
1779
|
+
const threadReplies = threads?.replies ?? [];
|
|
1780
|
+
const actualTotalCount = threads?.replyCount ?? 0;
|
|
1781
|
+
|
|
1782
|
+
console.log(
|
|
1783
|
+
`Direct fetch complete. Got ${threadReplies.length} messages of ${actualTotalCount} total`,
|
|
1784
|
+
);
|
|
1785
|
+
console.log(
|
|
1786
|
+
'Message IDs:',
|
|
1787
|
+
threadReplies.map((msg) => msg.id).join(', '),
|
|
1788
|
+
);
|
|
1789
|
+
|
|
1790
|
+
// Compare with our existing messages to find the ones we're missing
|
|
1791
|
+
const existingIds = new Set(
|
|
1792
|
+
safeContextProperty('threadMessages', []).map(
|
|
1793
|
+
(msg) => msg.id,
|
|
1794
|
+
),
|
|
1795
|
+
);
|
|
1796
|
+
const newMessages = threadReplies.filter(
|
|
1797
|
+
(msg) => !existingIds.has(msg.id),
|
|
1798
|
+
);
|
|
1799
|
+
|
|
1800
|
+
console.log(
|
|
1801
|
+
`Found ${newMessages.length} new messages that we didn't have before`,
|
|
1802
|
+
);
|
|
1803
|
+
|
|
1804
|
+
if (newMessages.length > 0) {
|
|
1805
|
+
safeSend({
|
|
1806
|
+
type: 'FETCH_MORE_MESSAGES_SUCCESS',
|
|
1807
|
+
data: {
|
|
1808
|
+
messages: newMessages,
|
|
1809
|
+
totalCount: actualTotalCount,
|
|
1810
|
+
loadingOldMessages: false,
|
|
1811
|
+
},
|
|
1812
|
+
});
|
|
1813
|
+
|
|
1814
|
+
// Show the results
|
|
1815
|
+
Alert.alert(
|
|
1816
|
+
'Success',
|
|
1817
|
+
`Found ${newMessages.length} new messages`,
|
|
1818
|
+
);
|
|
1819
|
+
} else {
|
|
1820
|
+
// If we didn't find any new messages, adjust the total count
|
|
1821
|
+
console.log('No new messages found, adjusting count');
|
|
1822
|
+
safeSend({
|
|
1823
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1824
|
+
data: {
|
|
1825
|
+
messages: safeContextProperty(
|
|
1826
|
+
'threadMessages',
|
|
1827
|
+
[],
|
|
1828
|
+
),
|
|
1829
|
+
totalCount: safeContextProperty(
|
|
1830
|
+
'threadMessages',
|
|
1831
|
+
[],
|
|
1832
|
+
).length,
|
|
1833
|
+
threadPost: safeContextProperty(
|
|
1834
|
+
'threadPost',
|
|
1835
|
+
[],
|
|
1836
|
+
),
|
|
1837
|
+
postThread: safeContextProperty(
|
|
1838
|
+
'postThread',
|
|
1839
|
+
null,
|
|
1840
|
+
),
|
|
1841
|
+
},
|
|
1842
|
+
});
|
|
1843
|
+
|
|
1844
|
+
// Notify the user
|
|
1845
|
+
Alert.alert(
|
|
1846
|
+
'Info',
|
|
1847
|
+
'No new messages found. Count has been adjusted.',
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
} else {
|
|
1851
|
+
Alert.alert('Error', 'Could not fetch thread messages');
|
|
1852
|
+
safeSend({
|
|
1853
|
+
type: ThreadActions.STOP_LOADING,
|
|
1854
|
+
data: { loadingOldMessages: false },
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
})
|
|
1858
|
+
.catch((error) => {
|
|
1859
|
+
console.error('Error in direct fetch:', error);
|
|
1860
|
+
Alert.alert(
|
|
1861
|
+
'Error',
|
|
1862
|
+
'Failed to fetch messages: ' + error.message,
|
|
1863
|
+
);
|
|
1864
|
+
safeSend({
|
|
1865
|
+
type: ThreadActions.STOP_LOADING,
|
|
1866
|
+
data: { loadingOldMessages: false },
|
|
1867
|
+
});
|
|
1868
|
+
});
|
|
1869
|
+
},
|
|
1870
|
+
},
|
|
1871
|
+
{
|
|
1872
|
+
text: 'Reset Count',
|
|
1873
|
+
style: 'destructive',
|
|
1874
|
+
onPress: () => {
|
|
1875
|
+
console.log('Resetting message count to match reality');
|
|
1876
|
+
safeSend({
|
|
1877
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1878
|
+
data: {
|
|
1879
|
+
messages: safeContextProperty('threadMessages', []),
|
|
1880
|
+
totalCount: safeContextProperty('threadMessages', []).length,
|
|
1881
|
+
threadPost: safeContextProperty('threadPost', []),
|
|
1882
|
+
postThread: safeContextProperty('postThread', null),
|
|
1883
|
+
},
|
|
1884
|
+
});
|
|
1885
|
+
},
|
|
1886
|
+
},
|
|
1887
|
+
{
|
|
1888
|
+
text: 'Cancel',
|
|
1889
|
+
style: 'cancel',
|
|
1890
|
+
},
|
|
1891
|
+
]);
|
|
1892
|
+
}}
|
|
1893
|
+
underlayColor="#e6e6e6"
|
|
1894
|
+
>
|
|
1895
|
+
<Box className="bg-gray-200 rounded-full px-4 py-2 flex-row items-center">
|
|
1896
|
+
<MaterialIcons name="arrow-upward" size={16} color={colors.blue[500]} />
|
|
1897
|
+
<Text className="text-sm font-medium color-blue-600 ml-2">
|
|
1898
|
+
Load More (
|
|
1899
|
+
{safeContextProperty('totalCount', 0) -
|
|
1900
|
+
safeContextProperty('threadMessages', []).length}
|
|
1901
|
+
)
|
|
1902
|
+
</Text>
|
|
1903
|
+
</Box>
|
|
1904
|
+
</TouchableHighlight>
|
|
1905
|
+
|
|
1906
|
+
<TouchableHighlight onPress={forceRefreshMessages} underlayColor="#e6e6e6">
|
|
1907
|
+
<Box className="bg-gray-200 rounded-full px-4 py-2 flex-row items-center">
|
|
1908
|
+
<MaterialIcons name="refresh" size={16} color={colors.blue[500]} />
|
|
1909
|
+
<Text className="text-sm font-medium color-blue-600 ml-2">Refresh All</Text>
|
|
1910
|
+
</Box>
|
|
1911
|
+
</TouchableHighlight>
|
|
1912
|
+
</HStack>
|
|
1913
|
+
</Box>
|
|
1914
|
+
)}
|
|
1256
1915
|
{isPostParentIdThread && (
|
|
1257
1916
|
<>
|
|
1258
1917
|
{safeContextProperty('threadPost', [])?.length > 0 && (
|
|
@@ -1326,7 +1985,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1326
1985
|
minIndexForVisible: 0,
|
|
1327
1986
|
autoscrollToTopThreshold: 100,
|
|
1328
1987
|
},
|
|
1329
|
-
scrollEventThrottle:
|
|
1988
|
+
scrollEventThrottle: 16,
|
|
1330
1989
|
keyboardDismissMode: 'on-drag',
|
|
1331
1990
|
keyboardShouldPersistTaps: 'handled',
|
|
1332
1991
|
}}
|