@messenger-box/platform-mobile 10.0.3-alpha.18 → 10.0.3-alpha.20
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 +8 -0
- package/lib/screens/inbox/components/DialogsListItem.js +423 -50
- package/lib/screens/inbox/components/DialogsListItem.js.map +1 -1
- package/lib/screens/inbox/components/ServiceDialogsListItem.js +375 -51
- package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +1 -1
- package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js +175 -0
- package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js.map +1 -0
- package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js +191 -0
- package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js.map +1 -0
- package/lib/screens/inbox/containers/Dialogs.js +382 -181
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadConversationView.js +536 -48
- package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/workflow/dialogs-xstate.js +1 -25
- package/lib/screens/inbox/containers/workflow/dialogs-xstate.js.map +1 -1
- package/package.json +2 -2
- package/src/screens/inbox/components/DialogsListItem.tsx +624 -107
- package/src/screens/inbox/components/ServiceDialogsListItem.tsx +506 -114
- package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +35 -17
- 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/containers/Dialogs.tsx +531 -281
- package/src/screens/inbox/containers/ThreadConversationView.tsx +812 -37
|
@@ -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';
|
|
@@ -64,10 +64,23 @@ const {
|
|
|
64
64
|
|
|
65
65
|
const createdAtText = (value: string) => {
|
|
66
66
|
if (!value) return '';
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
// Validate the date before processing
|
|
70
|
+
const timestamp = new Date(value).getTime();
|
|
71
|
+
if (isNaN(timestamp)) {
|
|
72
|
+
console.warn(`Invalid date value in createdAtText: ${value}`);
|
|
73
|
+
return 'Unknown date';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let date = new Date(value);
|
|
77
|
+
if (isToday(date)) return 'Today';
|
|
78
|
+
if (isYesterday(date)) return 'Yesterday';
|
|
79
|
+
return format(date, 'MMM dd, yyyy');
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(`Error processing date in createdAtText: ${value}`, error);
|
|
82
|
+
return 'Unknown date';
|
|
83
|
+
}
|
|
71
84
|
};
|
|
72
85
|
|
|
73
86
|
// Create a safer version of useMachine to handle potential errors
|
|
@@ -214,6 +227,8 @@ function useSafeMachine(machine) {
|
|
|
214
227
|
context: {
|
|
215
228
|
...prev.context,
|
|
216
229
|
loading: false,
|
|
230
|
+
loadingOldMessages:
|
|
231
|
+
event.data?.loadingOldMessages === false ? false : prev.context.loadingOldMessages,
|
|
217
232
|
},
|
|
218
233
|
}));
|
|
219
234
|
} else if (event.type === ThreadActions.SEND_THREAD_MESSAGE) {
|
|
@@ -287,12 +302,111 @@ function useSafeMachine(machine) {
|
|
|
287
302
|
} else if (event.type === 'FETCH_MORE_MESSAGES_SUCCESS') {
|
|
288
303
|
setState((prev) => {
|
|
289
304
|
const newMessages = event.data?.messages || [];
|
|
305
|
+
const apiTotalCount = event.data?.totalCount;
|
|
306
|
+
console.log(
|
|
307
|
+
`Merging ${newMessages.length} older messages with ${prev.context.threadMessages.length} existing messages`,
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
// Debug: Log the dates of the messages for troubleshooting
|
|
311
|
+
if (newMessages.length > 0) {
|
|
312
|
+
try {
|
|
313
|
+
console.log(
|
|
314
|
+
'First new message date:',
|
|
315
|
+
!isNaN(new Date(newMessages[0].createdAt).getTime())
|
|
316
|
+
? new Date(newMessages[0].createdAt).toISOString()
|
|
317
|
+
: 'Invalid date',
|
|
318
|
+
);
|
|
319
|
+
console.log(
|
|
320
|
+
'Last new message date:',
|
|
321
|
+
!isNaN(new Date(newMessages[newMessages.length - 1].createdAt).getTime())
|
|
322
|
+
? new Date(newMessages[newMessages.length - 1].createdAt).toISOString()
|
|
323
|
+
: 'Invalid date',
|
|
324
|
+
);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
console.error('Error logging new message dates:', error);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (prev.context.threadMessages.length > 0) {
|
|
331
|
+
try {
|
|
332
|
+
console.log(
|
|
333
|
+
'First existing message date:',
|
|
334
|
+
!isNaN(new Date(prev.context.threadMessages[0].createdAt).getTime())
|
|
335
|
+
? new Date(prev.context.threadMessages[0].createdAt).toISOString()
|
|
336
|
+
: 'Invalid date',
|
|
337
|
+
);
|
|
338
|
+
console.log(
|
|
339
|
+
'Last existing message date:',
|
|
340
|
+
!isNaN(
|
|
341
|
+
new Date(
|
|
342
|
+
prev.context.threadMessages[prev.context.threadMessages.length - 1].createdAt,
|
|
343
|
+
).getTime(),
|
|
344
|
+
)
|
|
345
|
+
? new Date(
|
|
346
|
+
prev.context.threadMessages[prev.context.threadMessages.length - 1].createdAt,
|
|
347
|
+
).toISOString()
|
|
348
|
+
: 'Invalid date',
|
|
349
|
+
);
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.error('Error logging existing message dates:', error);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// If no new messages returned but total count says there should be more
|
|
356
|
+
if (newMessages.length === 0 && prev.context.totalCount > prev.context.threadMessages.length) {
|
|
357
|
+
console.log('No new messages found despite totalCount indicating more should exist');
|
|
358
|
+
|
|
359
|
+
// Adjust totalCount to match reality
|
|
360
|
+
return {
|
|
361
|
+
...prev,
|
|
362
|
+
context: {
|
|
363
|
+
...prev.context,
|
|
364
|
+
loadingOldMessages: false,
|
|
365
|
+
totalCount: prev.context.threadMessages.length,
|
|
366
|
+
},
|
|
367
|
+
value: 'active',
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Make sure we don't add duplicate messages
|
|
372
|
+
const combinedMessages = uniqBy([...prev.context.threadMessages, ...newMessages], 'id');
|
|
373
|
+
|
|
374
|
+
// GiftedChat expects messages sorted by date (newest first)
|
|
375
|
+
const sortedMessages = orderBy(
|
|
376
|
+
combinedMessages,
|
|
377
|
+
[
|
|
378
|
+
(msg) => {
|
|
379
|
+
try {
|
|
380
|
+
// Safely access and convert date
|
|
381
|
+
return !isNaN(new Date(msg.createdAt).getTime())
|
|
382
|
+
? new Date(msg.createdAt).getTime()
|
|
383
|
+
: 0; // Default to oldest if invalid
|
|
384
|
+
} catch (error) {
|
|
385
|
+
console.error(`Error sorting message by date: ${msg.id}`, error);
|
|
386
|
+
return 0; // Default to oldest if error
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
],
|
|
390
|
+
['desc'],
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
// Use the total count from the API response if available, otherwise keep the current count
|
|
394
|
+
const newTotalCount =
|
|
395
|
+
typeof apiTotalCount === 'number'
|
|
396
|
+
? apiTotalCount
|
|
397
|
+
: Math.max(sortedMessages.length, prev.context.totalCount);
|
|
398
|
+
|
|
399
|
+
console.log(
|
|
400
|
+
`Total messages after merge and sort: ${sortedMessages.length}, totalCount: ${newTotalCount}`,
|
|
401
|
+
);
|
|
402
|
+
|
|
290
403
|
return {
|
|
291
404
|
...prev,
|
|
292
405
|
context: {
|
|
293
406
|
...prev.context,
|
|
294
407
|
loadingOldMessages: false,
|
|
295
|
-
threadMessages:
|
|
408
|
+
threadMessages: sortedMessages,
|
|
409
|
+
totalCount: newTotalCount,
|
|
296
410
|
},
|
|
297
411
|
value: 'active',
|
|
298
412
|
};
|
|
@@ -432,6 +546,64 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
432
546
|
{ data, loading: threadLoading, fetchMore: fetchMoreMessages, refetch: refetchThreadMessages, subscribeToMore },
|
|
433
547
|
] = useGetPostThreadLazyQuery({ fetchPolicy: 'cache-and-network' });
|
|
434
548
|
|
|
549
|
+
// Add a function to force refresh all messages
|
|
550
|
+
const forceRefreshMessages = useCallback(() => {
|
|
551
|
+
console.log('Force refreshing all messages');
|
|
552
|
+
|
|
553
|
+
// Clear the current messages first
|
|
554
|
+
safeSend({
|
|
555
|
+
type: ThreadActions.CLEAR_MESSAGES,
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// Then trigger a refetch
|
|
559
|
+
if (channelId && parentId) {
|
|
560
|
+
safeSend({
|
|
561
|
+
type: ThreadActions.START_LOADING,
|
|
562
|
+
data: { loading: true },
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
getThreadMessages({
|
|
566
|
+
variables: {
|
|
567
|
+
channelId: channelId?.toString(),
|
|
568
|
+
role: role?.toString(),
|
|
569
|
+
postParentId: !parentId || parentId == 0 ? null : parentId?.toString(),
|
|
570
|
+
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
571
|
+
limit: 50, // Use larger limit that proved to work
|
|
572
|
+
},
|
|
573
|
+
})
|
|
574
|
+
.then(({ data }) => {
|
|
575
|
+
if (data?.getPostThread) {
|
|
576
|
+
const threads: any = data.getPostThread;
|
|
577
|
+
const threadPost = threads?.post ?? [];
|
|
578
|
+
const threadReplies = threads?.replies ?? [];
|
|
579
|
+
const messageTotalCount = threads?.replyCount ?? 0;
|
|
580
|
+
const messages = [...threadReplies];
|
|
581
|
+
|
|
582
|
+
console.log(
|
|
583
|
+
`Force refresh complete. Got ${messages.length} messages of ${messageTotalCount} total`,
|
|
584
|
+
);
|
|
585
|
+
|
|
586
|
+
safeSend({
|
|
587
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
588
|
+
data: {
|
|
589
|
+
messages,
|
|
590
|
+
totalCount: messageTotalCount,
|
|
591
|
+
threadPost: threadPost,
|
|
592
|
+
postThread: threads,
|
|
593
|
+
},
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
})
|
|
597
|
+
.catch((error) => {
|
|
598
|
+
console.error('Error during force refresh:', error);
|
|
599
|
+
safeSend({
|
|
600
|
+
type: 'ERROR',
|
|
601
|
+
data: { message: error.message },
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
}, [channelId, parentId, getThreadMessages, safeSend]);
|
|
606
|
+
|
|
435
607
|
useFocusEffect(
|
|
436
608
|
React.useCallback(() => {
|
|
437
609
|
// navigation?.setOptions({ title: params?.title ?? 'Thread' });
|
|
@@ -443,6 +615,11 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
443
615
|
<MaterialIcons size={20} name="arrow-back-ios" color={'black'} />
|
|
444
616
|
</Button>
|
|
445
617
|
),
|
|
618
|
+
headerRight: () => (
|
|
619
|
+
<Button className="bg-transparent active:bg-gray-200 mr-2" onPress={forceRefreshMessages}>
|
|
620
|
+
<MaterialIcons size={20} name="refresh" color={'black'} />
|
|
621
|
+
</Button>
|
|
622
|
+
),
|
|
446
623
|
});
|
|
447
624
|
|
|
448
625
|
// Set initial context when focused
|
|
@@ -462,7 +639,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
462
639
|
return () => {
|
|
463
640
|
safeSend({ type: ThreadActions.CLEAR_MESSAGES });
|
|
464
641
|
};
|
|
465
|
-
}, [postParentId]),
|
|
642
|
+
}, [postParentId, forceRefreshMessages]),
|
|
466
643
|
);
|
|
467
644
|
|
|
468
645
|
// Effect for when in FetchThreadMessages state
|
|
@@ -500,13 +677,14 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
500
677
|
// Fetch thread messages function
|
|
501
678
|
const fetchThreadMessages = useCallback(() => {
|
|
502
679
|
if (channelId && parentId) {
|
|
680
|
+
console.log('Initial fetch of thread messages using larger limit (50)');
|
|
503
681
|
getThreadMessages({
|
|
504
682
|
variables: {
|
|
505
683
|
channelId: channelId?.toString(),
|
|
506
684
|
role: role?.toString(),
|
|
507
685
|
postParentId: !parentId || parentId == 0 ? null : parentId?.toString(),
|
|
508
686
|
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
509
|
-
limit:
|
|
687
|
+
limit: 50, // Use larger limit that proved to work
|
|
510
688
|
},
|
|
511
689
|
})
|
|
512
690
|
.then(({ data }) => {
|
|
@@ -517,6 +695,10 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
517
695
|
const messageTotalCount = threads?.replyCount ?? 0;
|
|
518
696
|
const messages = [...threadReplies];
|
|
519
697
|
|
|
698
|
+
console.log(
|
|
699
|
+
`Initial fetch complete. Got ${messages.length} messages of ${messageTotalCount} total`,
|
|
700
|
+
);
|
|
701
|
+
|
|
520
702
|
safeSend({
|
|
521
703
|
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
522
704
|
data: {
|
|
@@ -563,6 +745,74 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
563
745
|
}
|
|
564
746
|
}, [safeContextProperty('selectedImage')]);
|
|
565
747
|
|
|
748
|
+
// Add a safety timeout to clear loading state if it gets stuck
|
|
749
|
+
React.useEffect(() => {
|
|
750
|
+
const isLoading = safeContextProperty('loadingOldMessages', false);
|
|
751
|
+
|
|
752
|
+
if (isLoading) {
|
|
753
|
+
console.log('Message loading timeout safety started');
|
|
754
|
+
const timeoutId = setTimeout(() => {
|
|
755
|
+
// Check if we're still loading after 10 seconds
|
|
756
|
+
if (safeContextProperty('loadingOldMessages', false)) {
|
|
757
|
+
console.log('Message loading timed out - resetting state');
|
|
758
|
+
safeSend({
|
|
759
|
+
type: ThreadActions.STOP_LOADING,
|
|
760
|
+
data: { loadingOldMessages: false },
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
}, 10000); // 10 second timeout
|
|
764
|
+
|
|
765
|
+
return () => clearTimeout(timeoutId);
|
|
766
|
+
}
|
|
767
|
+
}, [safeContextProperty('loadingOldMessages')]);
|
|
768
|
+
|
|
769
|
+
// Add a safety counter to detect and fix incorrect message counts automatically
|
|
770
|
+
const failedLoadAttemptsRef = useRef(0);
|
|
771
|
+
|
|
772
|
+
// Track failed attempts to load more messages
|
|
773
|
+
const registerLoadAttemptResult = useCallback((success: boolean) => {
|
|
774
|
+
if (!success) {
|
|
775
|
+
failedLoadAttemptsRef.current += 1;
|
|
776
|
+
console.log(`Failed load attempt registered, count: ${failedLoadAttemptsRef.current}`);
|
|
777
|
+
} else {
|
|
778
|
+
// Reset counter on successful load
|
|
779
|
+
failedLoadAttemptsRef.current = 0;
|
|
780
|
+
}
|
|
781
|
+
}, []);
|
|
782
|
+
|
|
783
|
+
// Watch for failed load attempts and auto-fix the count after 3 consecutive failures
|
|
784
|
+
React.useEffect(() => {
|
|
785
|
+
const isLoading = safeContextProperty('loadingOldMessages', false);
|
|
786
|
+
const totalCount = safeContextProperty('totalCount', 0);
|
|
787
|
+
const messagesCount = safeContextProperty('threadMessages', []).length;
|
|
788
|
+
|
|
789
|
+
// If we're not loading and there's a discrepancy in message counts
|
|
790
|
+
if (!isLoading && totalCount > messagesCount) {
|
|
791
|
+
// If we've had 3 consecutive failed attempts, fix the count
|
|
792
|
+
if (failedLoadAttemptsRef.current >= 2) {
|
|
793
|
+
console.log(
|
|
794
|
+
`Auto-fixing incorrect message count after ${
|
|
795
|
+
failedLoadAttemptsRef.current + 1
|
|
796
|
+
} failed load attempts`,
|
|
797
|
+
);
|
|
798
|
+
console.log(`Adjusting totalCount from ${totalCount} to ${messagesCount}`);
|
|
799
|
+
|
|
800
|
+
safeSend({
|
|
801
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
802
|
+
data: {
|
|
803
|
+
messages: safeContextProperty('threadMessages', []),
|
|
804
|
+
totalCount: messagesCount,
|
|
805
|
+
threadPost: safeContextProperty('threadPost', []),
|
|
806
|
+
postThread: safeContextProperty('postThread', null),
|
|
807
|
+
},
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
// Reset the counter
|
|
811
|
+
failedLoadAttemptsRef.current = 0;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}, [safeContextProperty('loadingOldMessages'), safeContextProperty('threadMessages')]);
|
|
815
|
+
|
|
566
816
|
const scrollToBottom = React.useCallback(() => {
|
|
567
817
|
if (threadMessageListRef?.current) {
|
|
568
818
|
threadMessageListRef.current.scrollToBottom();
|
|
@@ -578,36 +828,111 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
578
828
|
|
|
579
829
|
// Set the loading state specifically for old messages
|
|
580
830
|
safeSend({
|
|
581
|
-
type: ThreadActions.
|
|
831
|
+
type: ThreadActions.FETCH_MORE_MESSAGES,
|
|
582
832
|
data: { loadingOldMessages: true },
|
|
583
833
|
});
|
|
584
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
|
+
|
|
585
850
|
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
|
-
},
|
|
851
|
+
variables: queryVariables,
|
|
594
852
|
})
|
|
595
853
|
.then((res: any) => {
|
|
854
|
+
console.log('API response received:', JSON.stringify(res?.data, null, 2));
|
|
855
|
+
|
|
596
856
|
if (res?.data?.getPostThread) {
|
|
597
857
|
const threads: any = res?.data?.getPostThread;
|
|
598
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
|
+
}
|
|
599
899
|
|
|
600
|
-
|
|
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`);
|
|
601
924
|
|
|
602
925
|
safeSend({
|
|
603
926
|
type: 'FETCH_MORE_MESSAGES_SUCCESS',
|
|
604
927
|
data: {
|
|
605
|
-
messages:
|
|
928
|
+
messages: newUniqueMessages,
|
|
929
|
+
totalCount: actualTotalCount,
|
|
606
930
|
loadingOldMessages: false,
|
|
607
931
|
},
|
|
608
932
|
});
|
|
609
933
|
} else {
|
|
610
934
|
console.log('No thread data returned when loading more messages');
|
|
935
|
+
registerLoadAttemptResult(false);
|
|
611
936
|
safeSend({
|
|
612
937
|
type: ThreadActions.STOP_LOADING,
|
|
613
938
|
data: { loadingOldMessages: false },
|
|
@@ -616,6 +941,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
616
941
|
})
|
|
617
942
|
.catch((error: any) => {
|
|
618
943
|
console.error('Error fetching more messages:', error);
|
|
944
|
+
registerLoadAttemptResult(false);
|
|
619
945
|
safeSend({
|
|
620
946
|
type: 'ERROR',
|
|
621
947
|
data: {
|
|
@@ -626,18 +952,31 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
626
952
|
});
|
|
627
953
|
} else {
|
|
628
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
|
+
}
|
|
629
962
|
}
|
|
630
|
-
}, [parentId, channelId, state.context]);
|
|
963
|
+
}, [parentId, channelId, state.context, registerLoadAttemptResult]);
|
|
631
964
|
|
|
632
965
|
let onScroll = false;
|
|
633
966
|
|
|
634
967
|
const handleScrollToTop = ({ nativeEvent }: any) => {
|
|
635
968
|
// Check if we're near the top of the list
|
|
636
969
|
if (isCloseToTop(nativeEvent)) {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
970
|
+
const isLoading = safeContextProperty('loadingOldMessages', false);
|
|
971
|
+
const totalCount = safeContextProperty('totalCount', 0);
|
|
972
|
+
const currentCount = safeContextProperty('threadMessages', []).length;
|
|
973
|
+
const hasMoreMessages = totalCount > currentCount;
|
|
974
|
+
|
|
975
|
+
console.log(
|
|
976
|
+
`Scroll near top - Loading state: ${isLoading}, Messages: ${currentCount}/${totalCount}, Has more: ${hasMoreMessages}`,
|
|
977
|
+
);
|
|
978
|
+
|
|
979
|
+
if (!isLoading && hasMoreMessages) {
|
|
641
980
|
console.log('Near top of list - loading older messages');
|
|
642
981
|
safeSend({ type: ThreadActions.FETCH_MORE_MESSAGES });
|
|
643
982
|
}
|
|
@@ -650,8 +989,21 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
650
989
|
};
|
|
651
990
|
|
|
652
991
|
const isCloseToTop = ({ layoutMeasurement, contentOffset, contentSize }) => {
|
|
653
|
-
|
|
654
|
-
|
|
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;
|
|
655
1007
|
};
|
|
656
1008
|
|
|
657
1009
|
const onSelectImages = async () => {
|
|
@@ -971,10 +1323,39 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
971
1323
|
// Generate a unique _id if needed by combining id and createdAt
|
|
972
1324
|
const uniqueId = msg.id || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
973
1325
|
|
|
1326
|
+
// Safely create a Date object with validation
|
|
1327
|
+
let messageDate;
|
|
1328
|
+
try {
|
|
1329
|
+
// Check if createdAt is a valid date string
|
|
1330
|
+
if (msg.createdAt && !isNaN(new Date(msg.createdAt).getTime())) {
|
|
1331
|
+
messageDate = new Date(msg.createdAt);
|
|
1332
|
+
} else {
|
|
1333
|
+
// Use current time as fallback if date is invalid
|
|
1334
|
+
console.warn(`Invalid date value for message ${msg.id}: ${msg.createdAt}`);
|
|
1335
|
+
messageDate = new Date();
|
|
1336
|
+
}
|
|
1337
|
+
} catch (error) {
|
|
1338
|
+
console.error(`Error creating date for message ${msg.id}:`, error);
|
|
1339
|
+
messageDate = new Date(); // Fallback to current time
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// Extract image URL from files data
|
|
1343
|
+
let imageUrl = null;
|
|
1344
|
+
if (msg.files?.data && msg.files.data.length > 0) {
|
|
1345
|
+
const fileData = msg.files.data[0];
|
|
1346
|
+
if (fileData && fileData.url) {
|
|
1347
|
+
imageUrl = fileData.url;
|
|
1348
|
+
console.log('📷 Found image URL for message', msg.id, ':', imageUrl);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Get the message text without adding "File attachment" for image-only messages
|
|
1353
|
+
let messageText = msg.message || '';
|
|
1354
|
+
|
|
974
1355
|
let message: IMessageProps = {
|
|
975
1356
|
_id: uniqueId,
|
|
976
|
-
text:
|
|
977
|
-
createdAt:
|
|
1357
|
+
text: messageText,
|
|
1358
|
+
createdAt: messageDate,
|
|
978
1359
|
user: {
|
|
979
1360
|
_id: msg?.author?.id ?? auth?.profile?.id,
|
|
980
1361
|
name:
|
|
@@ -984,7 +1365,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
984
1365
|
avatar: msg?.author?.picture ?? auth?.profile?.picture,
|
|
985
1366
|
},
|
|
986
1367
|
type: msg?.type || '',
|
|
987
|
-
image:
|
|
1368
|
+
image: imageUrl,
|
|
988
1369
|
sent: msg?.isDelivered || true,
|
|
989
1370
|
received: msg?.isRead || false,
|
|
990
1371
|
propsConfiguration: msg?.propsConfiguration,
|
|
@@ -994,7 +1375,39 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
994
1375
|
}
|
|
995
1376
|
|
|
996
1377
|
// Sort messages by date (newest first as required by GiftedChat)
|
|
997
|
-
|
|
1378
|
+
// Use a safer getTime() approach with error handling
|
|
1379
|
+
const sortedMessages = orderBy(
|
|
1380
|
+
res,
|
|
1381
|
+
[
|
|
1382
|
+
(msg) => {
|
|
1383
|
+
try {
|
|
1384
|
+
return msg.createdAt instanceof Date ? msg.createdAt.getTime() : new Date().getTime();
|
|
1385
|
+
} catch (error) {
|
|
1386
|
+
console.error('Error sorting message by date:', error);
|
|
1387
|
+
return 0; // Fallback to a default value
|
|
1388
|
+
}
|
|
1389
|
+
},
|
|
1390
|
+
],
|
|
1391
|
+
['desc'],
|
|
1392
|
+
);
|
|
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
|
+
|
|
998
1411
|
return sortedMessages;
|
|
999
1412
|
}, [safeContextProperty('threadMessages'), auth]);
|
|
1000
1413
|
|
|
@@ -1036,6 +1449,8 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1036
1449
|
|
|
1037
1450
|
const renderMessageText = (props: any) => {
|
|
1038
1451
|
const { currentMessage } = props;
|
|
1452
|
+
|
|
1453
|
+
// For ALERT type messages with call to action
|
|
1039
1454
|
if (currentMessage.type === 'ALERT') {
|
|
1040
1455
|
const attachment = currentMessage?.propsConfiguration?.contents?.attachment;
|
|
1041
1456
|
let action: string = '';
|
|
@@ -1091,7 +1506,14 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1091
1506
|
)}
|
|
1092
1507
|
</>
|
|
1093
1508
|
);
|
|
1094
|
-
}
|
|
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 {
|
|
1095
1517
|
return <MessageText {...props} textStyle={{ left: { marginLeft: 5 } }} />;
|
|
1096
1518
|
}
|
|
1097
1519
|
};
|
|
@@ -1243,9 +1665,65 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1243
1665
|
);
|
|
1244
1666
|
};
|
|
1245
1667
|
|
|
1668
|
+
// Add a function to load messages with specific skip value for debugging
|
|
1669
|
+
const forceLoadMessages = useCallback(
|
|
1670
|
+
(skipValue: number) => {
|
|
1671
|
+
console.log(`Force loading messages with explicit skip=${skipValue}, limit=50`);
|
|
1672
|
+
|
|
1673
|
+
if (channelId && parentId) {
|
|
1674
|
+
safeSend({
|
|
1675
|
+
type: ThreadActions.START_LOADING,
|
|
1676
|
+
data: { loading: true },
|
|
1677
|
+
});
|
|
1678
|
+
|
|
1679
|
+
getThreadMessages({
|
|
1680
|
+
variables: {
|
|
1681
|
+
channelId: channelId?.toString(),
|
|
1682
|
+
role: role?.toString(),
|
|
1683
|
+
postParentId: !parentId || parentId == 0 ? null : parentId?.toString(),
|
|
1684
|
+
selectedFields: 'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
1685
|
+
skip: skipValue,
|
|
1686
|
+
limit: 50, // Use larger limit that proved to work
|
|
1687
|
+
},
|
|
1688
|
+
})
|
|
1689
|
+
.then(({ data }) => {
|
|
1690
|
+
if (data?.getPostThread) {
|
|
1691
|
+
const threads: any = data.getPostThread;
|
|
1692
|
+
const threadPost = threads?.post ?? [];
|
|
1693
|
+
const threadReplies = threads?.replies ?? [];
|
|
1694
|
+
const messageTotalCount = threads?.replyCount ?? 0;
|
|
1695
|
+
const messages = [...threadReplies];
|
|
1696
|
+
|
|
1697
|
+
console.log(
|
|
1698
|
+
`Force load with skip=${skipValue} complete. Got ${messages.length} messages of ${messageTotalCount} total`,
|
|
1699
|
+
);
|
|
1700
|
+
|
|
1701
|
+
safeSend({
|
|
1702
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1703
|
+
data: {
|
|
1704
|
+
messages,
|
|
1705
|
+
totalCount: messageTotalCount,
|
|
1706
|
+
threadPost: threadPost,
|
|
1707
|
+
postThread: threads,
|
|
1708
|
+
},
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
})
|
|
1712
|
+
.catch((error) => {
|
|
1713
|
+
console.error('Error during force load:', error);
|
|
1714
|
+
safeSend({
|
|
1715
|
+
type: 'ERROR',
|
|
1716
|
+
data: { message: error.message },
|
|
1717
|
+
});
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
},
|
|
1721
|
+
[channelId, parentId, getThreadMessages, safeSend],
|
|
1722
|
+
);
|
|
1723
|
+
|
|
1246
1724
|
return (
|
|
1247
1725
|
<SafeAreaView style={{ flex: 1 }}>
|
|
1248
|
-
{safeContextProperty('loadingOldMessages', false) && (
|
|
1726
|
+
{safeContextProperty('loadingOldMessages', false) === true && (
|
|
1249
1727
|
<Box className="absolute top-10 left-0 right-0 z-10 items-center">
|
|
1250
1728
|
<Box className="bg-blue-500/20 rounded-full px-4 py-2 flex-row items-center">
|
|
1251
1729
|
<Spinner color={colors.blue[500]} size="small" />
|
|
@@ -1253,6 +1731,294 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1253
1731
|
</Box>
|
|
1254
1732
|
</Box>
|
|
1255
1733
|
)}
|
|
1734
|
+
{!safeContextProperty('loadingOldMessages', false) &&
|
|
1735
|
+
safeContextProperty('totalCount', 0) > safeContextProperty('threadMessages', []).length && (
|
|
1736
|
+
<Box className="absolute top-10 left-0 right-0 z-10 items-center">
|
|
1737
|
+
<HStack space={2} className="px-2">
|
|
1738
|
+
<TouchableHighlight
|
|
1739
|
+
onPress={() => {
|
|
1740
|
+
console.log('Manual load more pressed');
|
|
1741
|
+
Alert.alert('Load Options', 'Choose loading method', [
|
|
1742
|
+
{
|
|
1743
|
+
text: 'Normal Load',
|
|
1744
|
+
onPress: () => safeSend({ type: ThreadActions.FETCH_MORE_MESSAGES }),
|
|
1745
|
+
},
|
|
1746
|
+
{
|
|
1747
|
+
text: 'Try Skip=0',
|
|
1748
|
+
onPress: () => forceLoadMessages(0),
|
|
1749
|
+
},
|
|
1750
|
+
{
|
|
1751
|
+
text: 'Try Skip=0, Limit=50',
|
|
1752
|
+
onPress: () => {
|
|
1753
|
+
// Try with a larger limit
|
|
1754
|
+
console.log('Force loading with explicit skip=0, limit=50');
|
|
1755
|
+
|
|
1756
|
+
safeSend({
|
|
1757
|
+
type: ThreadActions.START_LOADING,
|
|
1758
|
+
data: { loadingOldMessages: true },
|
|
1759
|
+
});
|
|
1760
|
+
|
|
1761
|
+
fetchMoreMessages({
|
|
1762
|
+
variables: {
|
|
1763
|
+
channelId: channelId?.toString(),
|
|
1764
|
+
role: role?.toString(),
|
|
1765
|
+
postParentId:
|
|
1766
|
+
!parentId || parentId == 0 ? null : parentId?.toString(),
|
|
1767
|
+
selectedFields:
|
|
1768
|
+
'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
1769
|
+
limit: 50, // Try a larger limit
|
|
1770
|
+
skip: 0,
|
|
1771
|
+
},
|
|
1772
|
+
})
|
|
1773
|
+
.then((res: any) => {
|
|
1774
|
+
console.log(
|
|
1775
|
+
'LARGE LIMIT response:',
|
|
1776
|
+
JSON.stringify(res?.data, null, 2),
|
|
1777
|
+
);
|
|
1778
|
+
|
|
1779
|
+
if (res?.data?.getPostThread) {
|
|
1780
|
+
const threads: any = res?.data?.getPostThread;
|
|
1781
|
+
const threadReplies = threads?.replies ?? [];
|
|
1782
|
+
const actualTotalCount = threads?.replyCount ?? 0;
|
|
1783
|
+
|
|
1784
|
+
console.log(
|
|
1785
|
+
`Large limit load complete. Got ${threadReplies.length} messages of ${actualTotalCount} total`,
|
|
1786
|
+
);
|
|
1787
|
+
|
|
1788
|
+
if (threadReplies.length > 0) {
|
|
1789
|
+
// Reset our message list with all available messages
|
|
1790
|
+
safeSend({
|
|
1791
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1792
|
+
data: {
|
|
1793
|
+
messages: threadReplies,
|
|
1794
|
+
totalCount: actualTotalCount,
|
|
1795
|
+
threadPost: safeContextProperty(
|
|
1796
|
+
'threadPost',
|
|
1797
|
+
[],
|
|
1798
|
+
),
|
|
1799
|
+
postThread: threads,
|
|
1800
|
+
},
|
|
1801
|
+
});
|
|
1802
|
+
} else {
|
|
1803
|
+
// Reset count if no messages found
|
|
1804
|
+
safeSend({
|
|
1805
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1806
|
+
data: {
|
|
1807
|
+
messages: safeContextProperty(
|
|
1808
|
+
'threadMessages',
|
|
1809
|
+
[],
|
|
1810
|
+
),
|
|
1811
|
+
totalCount: safeContextProperty(
|
|
1812
|
+
'threadMessages',
|
|
1813
|
+
[],
|
|
1814
|
+
).length,
|
|
1815
|
+
threadPost: safeContextProperty(
|
|
1816
|
+
'threadPost',
|
|
1817
|
+
[],
|
|
1818
|
+
),
|
|
1819
|
+
postThread: safeContextProperty(
|
|
1820
|
+
'postThread',
|
|
1821
|
+
null,
|
|
1822
|
+
),
|
|
1823
|
+
},
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
} else {
|
|
1827
|
+
safeSend({
|
|
1828
|
+
type: ThreadActions.STOP_LOADING,
|
|
1829
|
+
data: { loadingOldMessages: false },
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
})
|
|
1833
|
+
.catch((error) => {
|
|
1834
|
+
console.error('Error in large limit load:', error);
|
|
1835
|
+
safeSend({
|
|
1836
|
+
type: ThreadActions.STOP_LOADING,
|
|
1837
|
+
data: { loadingOldMessages: false },
|
|
1838
|
+
});
|
|
1839
|
+
});
|
|
1840
|
+
},
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
text: 'Try Direct Fetch',
|
|
1844
|
+
onPress: () => {
|
|
1845
|
+
// Get current info
|
|
1846
|
+
const currentCount = safeContextProperty('threadMessages', []).length;
|
|
1847
|
+
const totalCount = safeContextProperty('totalCount', 0);
|
|
1848
|
+
const missingCount = totalCount - currentCount;
|
|
1849
|
+
|
|
1850
|
+
if (missingCount <= 0) {
|
|
1851
|
+
Alert.alert('Info', 'No missing messages to fetch');
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
console.log(
|
|
1856
|
+
`Attempting direct fetch of missing ${missingCount} messages`,
|
|
1857
|
+
);
|
|
1858
|
+
|
|
1859
|
+
// Try explicit query with exact parameters
|
|
1860
|
+
safeSend({
|
|
1861
|
+
type: ThreadActions.START_LOADING,
|
|
1862
|
+
data: { loadingOldMessages: true },
|
|
1863
|
+
});
|
|
1864
|
+
|
|
1865
|
+
// Special query directly for the missing messages
|
|
1866
|
+
getThreadMessages({
|
|
1867
|
+
variables: {
|
|
1868
|
+
channelId: channelId?.toString(),
|
|
1869
|
+
role: role?.toString(),
|
|
1870
|
+
postParentId:
|
|
1871
|
+
!parentId || parentId == 0 ? null : parentId?.toString(),
|
|
1872
|
+
selectedFields:
|
|
1873
|
+
'id channel post replies replyCount lastReplyAt createdAt updatedAt',
|
|
1874
|
+
limit: missingCount, // Only get the exact number we need
|
|
1875
|
+
skip: 0, // Start from the beginning
|
|
1876
|
+
},
|
|
1877
|
+
})
|
|
1878
|
+
.then(({ data }) => {
|
|
1879
|
+
console.log(
|
|
1880
|
+
'DIRECT FETCH response:',
|
|
1881
|
+
JSON.stringify(data, null, 2),
|
|
1882
|
+
);
|
|
1883
|
+
|
|
1884
|
+
if (data?.getPostThread) {
|
|
1885
|
+
const threads: any = data.getPostThread;
|
|
1886
|
+
const threadReplies = threads?.replies ?? [];
|
|
1887
|
+
const actualTotalCount = threads?.replyCount ?? 0;
|
|
1888
|
+
|
|
1889
|
+
console.log(
|
|
1890
|
+
`Direct fetch complete. Got ${threadReplies.length} messages of ${actualTotalCount} total`,
|
|
1891
|
+
);
|
|
1892
|
+
console.log(
|
|
1893
|
+
'Message IDs:',
|
|
1894
|
+
threadReplies.map((msg) => msg.id).join(', '),
|
|
1895
|
+
);
|
|
1896
|
+
|
|
1897
|
+
// Compare with our existing messages to find the ones we're missing
|
|
1898
|
+
const existingIds = new Set(
|
|
1899
|
+
safeContextProperty('threadMessages', []).map(
|
|
1900
|
+
(msg) => msg.id,
|
|
1901
|
+
),
|
|
1902
|
+
);
|
|
1903
|
+
const newMessages = threadReplies.filter(
|
|
1904
|
+
(msg) => !existingIds.has(msg.id),
|
|
1905
|
+
);
|
|
1906
|
+
|
|
1907
|
+
console.log(
|
|
1908
|
+
`Found ${newMessages.length} new messages that we didn't have before`,
|
|
1909
|
+
);
|
|
1910
|
+
|
|
1911
|
+
if (newMessages.length > 0) {
|
|
1912
|
+
safeSend({
|
|
1913
|
+
type: 'FETCH_MORE_MESSAGES_SUCCESS',
|
|
1914
|
+
data: {
|
|
1915
|
+
messages: newMessages,
|
|
1916
|
+
totalCount: actualTotalCount,
|
|
1917
|
+
loadingOldMessages: false,
|
|
1918
|
+
},
|
|
1919
|
+
});
|
|
1920
|
+
|
|
1921
|
+
// Show the results
|
|
1922
|
+
Alert.alert(
|
|
1923
|
+
'Success',
|
|
1924
|
+
`Found ${newMessages.length} new messages`,
|
|
1925
|
+
);
|
|
1926
|
+
} else {
|
|
1927
|
+
// If we didn't find any new messages, adjust the total count
|
|
1928
|
+
console.log('No new messages found, adjusting count');
|
|
1929
|
+
safeSend({
|
|
1930
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1931
|
+
data: {
|
|
1932
|
+
messages: safeContextProperty(
|
|
1933
|
+
'threadMessages',
|
|
1934
|
+
[],
|
|
1935
|
+
),
|
|
1936
|
+
totalCount: safeContextProperty(
|
|
1937
|
+
'threadMessages',
|
|
1938
|
+
[],
|
|
1939
|
+
).length,
|
|
1940
|
+
threadPost: safeContextProperty(
|
|
1941
|
+
'threadPost',
|
|
1942
|
+
[],
|
|
1943
|
+
),
|
|
1944
|
+
postThread: safeContextProperty(
|
|
1945
|
+
'postThread',
|
|
1946
|
+
null,
|
|
1947
|
+
),
|
|
1948
|
+
},
|
|
1949
|
+
});
|
|
1950
|
+
|
|
1951
|
+
// Notify the user
|
|
1952
|
+
Alert.alert(
|
|
1953
|
+
'Info',
|
|
1954
|
+
'No new messages found. Count has been adjusted.',
|
|
1955
|
+
);
|
|
1956
|
+
}
|
|
1957
|
+
} else {
|
|
1958
|
+
Alert.alert('Error', 'Could not fetch thread messages');
|
|
1959
|
+
safeSend({
|
|
1960
|
+
type: ThreadActions.STOP_LOADING,
|
|
1961
|
+
data: { loadingOldMessages: false },
|
|
1962
|
+
});
|
|
1963
|
+
}
|
|
1964
|
+
})
|
|
1965
|
+
.catch((error) => {
|
|
1966
|
+
console.error('Error in direct fetch:', error);
|
|
1967
|
+
Alert.alert(
|
|
1968
|
+
'Error',
|
|
1969
|
+
'Failed to fetch messages: ' + error.message,
|
|
1970
|
+
);
|
|
1971
|
+
safeSend({
|
|
1972
|
+
type: ThreadActions.STOP_LOADING,
|
|
1973
|
+
data: { loadingOldMessages: false },
|
|
1974
|
+
});
|
|
1975
|
+
});
|
|
1976
|
+
},
|
|
1977
|
+
},
|
|
1978
|
+
{
|
|
1979
|
+
text: 'Reset Count',
|
|
1980
|
+
style: 'destructive',
|
|
1981
|
+
onPress: () => {
|
|
1982
|
+
console.log('Resetting message count to match reality');
|
|
1983
|
+
safeSend({
|
|
1984
|
+
type: ThreadActions.SET_THREAD_MESSAGES,
|
|
1985
|
+
data: {
|
|
1986
|
+
messages: safeContextProperty('threadMessages', []),
|
|
1987
|
+
totalCount: safeContextProperty('threadMessages', []).length,
|
|
1988
|
+
threadPost: safeContextProperty('threadPost', []),
|
|
1989
|
+
postThread: safeContextProperty('postThread', null),
|
|
1990
|
+
},
|
|
1991
|
+
});
|
|
1992
|
+
},
|
|
1993
|
+
},
|
|
1994
|
+
{
|
|
1995
|
+
text: 'Cancel',
|
|
1996
|
+
style: 'cancel',
|
|
1997
|
+
},
|
|
1998
|
+
]);
|
|
1999
|
+
}}
|
|
2000
|
+
underlayColor="#e6e6e6"
|
|
2001
|
+
>
|
|
2002
|
+
<Box className="bg-gray-200 rounded-full px-4 py-2 flex-row items-center">
|
|
2003
|
+
<MaterialIcons name="arrow-upward" size={16} color={colors.blue[500]} />
|
|
2004
|
+
<Text className="text-sm font-medium color-blue-600 ml-2">
|
|
2005
|
+
Load More (
|
|
2006
|
+
{safeContextProperty('totalCount', 0) -
|
|
2007
|
+
safeContextProperty('threadMessages', []).length}
|
|
2008
|
+
)
|
|
2009
|
+
</Text>
|
|
2010
|
+
</Box>
|
|
2011
|
+
</TouchableHighlight>
|
|
2012
|
+
|
|
2013
|
+
<TouchableHighlight onPress={forceRefreshMessages} underlayColor="#e6e6e6">
|
|
2014
|
+
<Box className="bg-gray-200 rounded-full px-4 py-2 flex-row items-center">
|
|
2015
|
+
<MaterialIcons name="refresh" size={16} color={colors.blue[500]} />
|
|
2016
|
+
<Text className="text-sm font-medium color-blue-600 ml-2">Refresh All</Text>
|
|
2017
|
+
</Box>
|
|
2018
|
+
</TouchableHighlight>
|
|
2019
|
+
</HStack>
|
|
2020
|
+
</Box>
|
|
2021
|
+
)}
|
|
1256
2022
|
{isPostParentIdThread && (
|
|
1257
2023
|
<>
|
|
1258
2024
|
{safeContextProperty('threadPost', [])?.length > 0 && (
|
|
@@ -1284,10 +2050,19 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1284
2050
|
</Text>
|
|
1285
2051
|
<Text className="pl-0 color-gray-500">
|
|
1286
2052
|
{createdAtText(safeContextProperty('threadPost')[0]?.createdAt)} at{' '}
|
|
1287
|
-
{
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
2053
|
+
{(() => {
|
|
2054
|
+
try {
|
|
2055
|
+
const createdAt = safeContextProperty('threadPost')[0]?.createdAt;
|
|
2056
|
+
if (createdAt && !isNaN(new Date(createdAt).getTime())) {
|
|
2057
|
+
return format(new Date(createdAt), 'hh:mm:a');
|
|
2058
|
+
} else {
|
|
2059
|
+
return 'unknown time';
|
|
2060
|
+
}
|
|
2061
|
+
} catch (error) {
|
|
2062
|
+
console.error('Error formatting thread post time:', error);
|
|
2063
|
+
return 'unknown time';
|
|
2064
|
+
}
|
|
2065
|
+
})()}
|
|
1291
2066
|
</Text>
|
|
1292
2067
|
</Box>
|
|
1293
2068
|
</HStack>
|
|
@@ -1326,7 +2101,7 @@ const ThreadConversationViewComponent = ({ channelId, postParentId, isPostParent
|
|
|
1326
2101
|
minIndexForVisible: 0,
|
|
1327
2102
|
autoscrollToTopThreshold: 100,
|
|
1328
2103
|
},
|
|
1329
|
-
scrollEventThrottle:
|
|
2104
|
+
scrollEventThrottle: 16,
|
|
1330
2105
|
keyboardDismissMode: 'on-drag',
|
|
1331
2106
|
keyboardShouldPersistTaps: 'handled',
|
|
1332
2107
|
}}
|