stream-chat-react-native-core 5.22.2-beta.8 → 5.23.0-beta.2
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/lib/commonjs/components/Channel/Channel.js +587 -384
- package/lib/commonjs/components/Channel/Channel.js.map +1 -1
- package/lib/commonjs/components/MessageList/MessageList.js +170 -179
- package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
- package/lib/commonjs/components/MessageList/hooks/useMessageList.js +6 -1
- package/lib/commonjs/components/MessageList/hooks/useMessageList.js.map +1 -1
- package/lib/commonjs/components/MessageList/hooks/useShouldScrollToRecentOnNewOwnMessage.js +36 -0
- package/lib/commonjs/components/MessageList/hooks/useShouldScrollToRecentOnNewOwnMessage.js.map +1 -0
- package/lib/commonjs/contexts/channelsStateContext/ChannelsStateContext.js +1 -1
- package/lib/commonjs/contexts/channelsStateContext/ChannelsStateContext.js.map +1 -1
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +31 -15
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
- package/lib/commonjs/i18n/fr.json +15 -15
- package/lib/commonjs/i18n/hi.json +15 -15
- package/lib/commonjs/i18n/it.json +15 -15
- package/lib/commonjs/i18n/nl.json +15 -15
- package/lib/commonjs/i18n/ru.json +15 -15
- package/lib/commonjs/i18n/tr.json +15 -15
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Channel/Channel.js +587 -384
- package/lib/module/components/Channel/Channel.js.map +1 -1
- package/lib/module/components/MessageList/MessageList.js +170 -179
- package/lib/module/components/MessageList/MessageList.js.map +1 -1
- package/lib/module/components/MessageList/hooks/useMessageList.js +6 -1
- package/lib/module/components/MessageList/hooks/useMessageList.js.map +1 -1
- package/lib/module/components/MessageList/hooks/useShouldScrollToRecentOnNewOwnMessage.js +36 -0
- package/lib/module/components/MessageList/hooks/useShouldScrollToRecentOnNewOwnMessage.js.map +1 -0
- package/lib/module/contexts/channelsStateContext/ChannelsStateContext.js +1 -1
- package/lib/module/contexts/channelsStateContext/ChannelsStateContext.js.map +1 -1
- package/lib/module/contexts/messageInputContext/MessageInputContext.js +31 -15
- package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
- package/lib/module/i18n/fr.json +15 -15
- package/lib/module/i18n/hi.json +15 -15
- package/lib/module/i18n/it.json +15 -15
- package/lib/module/i18n/nl.json +15 -15
- package/lib/module/i18n/ru.json +15 -15
- package/lib/module/i18n/tr.json +15 -15
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/MessageList/hooks/useMessageList.d.ts +6 -1
- package/lib/typescript/components/MessageList/hooks/useShouldScrollToRecentOnNewOwnMessage.d.ts +4 -0
- package/lib/typescript/i18n/fr.json +15 -15
- package/lib/typescript/i18n/hi.json +15 -15
- package/lib/typescript/i18n/it.json +15 -15
- package/lib/typescript/i18n/nl.json +15 -15
- package/lib/typescript/i18n/ru.json +15 -15
- package/lib/typescript/i18n/tr.json +15 -15
- package/package.json +1 -1
- package/src/components/Channel/Channel.tsx +237 -61
- package/src/components/MessageList/MessageList.tsx +190 -180
- package/src/components/MessageList/__tests__/useMessageList.test.tsx +5 -2
- package/src/components/MessageList/hooks/useMessageList.ts +8 -1
- package/src/components/MessageList/hooks/useShouldScrollToRecentOnNewOwnMessage.ts +44 -0
- package/src/contexts/__tests__/index.test.tsx +1 -1
- package/src/contexts/channelsStateContext/ChannelsStateContext.tsx +1 -1
- package/src/contexts/messageInputContext/MessageInputContext.tsx +7 -1
- package/src/i18n/fr.json +15 -15
- package/src/i18n/hi.json +15 -15
- package/src/i18n/it.json +15 -15
- package/src/i18n/nl.json +15 -15
- package/src/i18n/ru.json +15 -15
- package/src/i18n/tr.json +15 -15
- package/src/version.json +1 -1
|
@@ -588,14 +588,13 @@ const ChannelWithContext = <
|
|
|
588
588
|
*/
|
|
589
589
|
const [hasNoMoreRecentMessagesToLoad, setHasNoMoreRecentMessagesToLoad] = useState(true);
|
|
590
590
|
|
|
591
|
+
const { setTargetedMessage, targetedMessage } = useTargetedMessage();
|
|
592
|
+
|
|
591
593
|
/**
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
+
* If we loaded a channel around message
|
|
595
|
+
* We may have moved latest message to a new message set in that case mark this ref to avoid fetching
|
|
594
596
|
*/
|
|
595
|
-
const
|
|
596
|
-
messagesRef.current = messages;
|
|
597
|
-
|
|
598
|
-
const { setTargetedMessage, targetedMessage } = useTargetedMessage();
|
|
597
|
+
const hasOverlappingRecentMessagesRef = useRef(false);
|
|
599
598
|
|
|
600
599
|
/**
|
|
601
600
|
* This ref will hold the abort controllers for
|
|
@@ -605,6 +604,7 @@ const ChannelWithContext = <
|
|
|
605
604
|
const uploadAbortControllerRef = useRef<Map<string, AbortController>>(new Map());
|
|
606
605
|
|
|
607
606
|
const channelId = channel?.id || '';
|
|
607
|
+
|
|
608
608
|
useEffect(() => {
|
|
609
609
|
const initChannel = () => {
|
|
610
610
|
if (!channel || !shouldSyncChannel || channel.offlineMode) return;
|
|
@@ -707,7 +707,9 @@ const ChannelWithContext = <
|
|
|
707
707
|
throttle(
|
|
708
708
|
() => {
|
|
709
709
|
if (channel) {
|
|
710
|
+
clearInterval(mergeSetsIntervalRef.current);
|
|
710
711
|
setMessages([...channel.state.messages]);
|
|
712
|
+
restartSetsMergeFuncRef.current();
|
|
711
713
|
}
|
|
712
714
|
},
|
|
713
715
|
newMessageStateUpdateThrottleInterval,
|
|
@@ -813,48 +815,69 @@ const ChannelWithContext = <
|
|
|
813
815
|
return unsubscribe;
|
|
814
816
|
}, [channelId]);
|
|
815
817
|
|
|
818
|
+
useEffect(() => {
|
|
819
|
+
const handleEvent: EventHandler<StreamChatGenerics> = (event) => {
|
|
820
|
+
if (channel.cid === event.cid) copyChannelState();
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
const { unsubscribe } = client.on('notification.mark_read', handleEvent);
|
|
824
|
+
return unsubscribe;
|
|
825
|
+
}, []);
|
|
826
|
+
|
|
816
827
|
const channelQueryCallRef = useRef(
|
|
817
828
|
async (
|
|
818
829
|
queryCall: () => Promise<void>,
|
|
819
830
|
onAfterQueryCall: (() => void) | undefined = undefined,
|
|
820
|
-
// if we are
|
|
821
|
-
|
|
831
|
+
// if we are scrolling to a message after the query, pass it here
|
|
832
|
+
scrollToMessageId: string | (() => string | undefined) | undefined = undefined,
|
|
822
833
|
) => {
|
|
823
834
|
setError(false);
|
|
824
835
|
try {
|
|
836
|
+
clearInterval(mergeSetsIntervalRef.current);
|
|
825
837
|
await queryCall();
|
|
826
838
|
setLastRead(new Date());
|
|
827
839
|
setHasMore(true);
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
840
|
+
const currentMessages = channel.state.messages;
|
|
841
|
+
const hadCurrentLatestMessages =
|
|
842
|
+
currentMessages.length > 0 && currentMessages === channel.state.latestMessages;
|
|
843
|
+
if (typeof scrollToMessageId === 'function') {
|
|
844
|
+
scrollToMessageId = scrollToMessageId();
|
|
845
|
+
}
|
|
846
|
+
const scrollToMessageIndex = scrollToMessageId
|
|
847
|
+
? currentMessages.findIndex(({ id }) => id === scrollToMessageId)
|
|
848
|
+
: -1;
|
|
849
|
+
if (channel && scrollToMessageIndex !== -1) {
|
|
850
|
+
// We assume that on average user sees 5 messages on screen
|
|
851
|
+
// We dont want new renders to happen while scrolling to the targeted message
|
|
852
|
+
// hence we limit the number of messages to be rendered after the targeted message to 5 - 1 = 4
|
|
853
|
+
// NOTE: we have one drawback here, if there were already a split latest and current message set
|
|
854
|
+
// the previous latest message set will be thrown away as we cannot merge it with the current message set after the target message is set
|
|
855
|
+
const limitAfter = 4;
|
|
856
|
+
const currentLength = currentMessages.length;
|
|
857
|
+
if (scrollToMessageIndex !== -1) {
|
|
858
|
+
const noOfMessagesAfter = currentLength - scrollToMessageIndex - 1;
|
|
859
|
+
// number of messages are over the limit, limit the length of messages
|
|
860
|
+
if (noOfMessagesAfter > limitAfter) {
|
|
861
|
+
const endIndex = scrollToMessageIndex + limitAfter;
|
|
862
|
+
channel.state.clearMessages();
|
|
863
|
+
channel.state.messages = currentMessages.slice(0, endIndex + 1);
|
|
864
|
+
splitLatestCurrentMessageSetRef.current();
|
|
865
|
+
const restOfMessages = currentMessages.slice(endIndex + 1);
|
|
866
|
+
if (hadCurrentLatestMessages) {
|
|
867
|
+
const latestSet = channel.state.messageSets.find((set) => set.isLatest);
|
|
868
|
+
if (latestSet) {
|
|
869
|
+
latestSet.messages = restOfMessages;
|
|
870
|
+
hasOverlappingRecentMessagesRef.current = true;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
841
873
|
}
|
|
842
|
-
const hadLatestMessages = channel.state.messages === channel.state.latestMessages;
|
|
843
|
-
const recentMessage = currentMessages[currentMessages.length - 1];
|
|
844
|
-
channel.state.clearMessages();
|
|
845
|
-
channel.state.messages = currentMessages.slice(startIndex, endIndex);
|
|
846
|
-
const stillHasLatestMessages =
|
|
847
|
-
hadLatestMessages &&
|
|
848
|
-
channel.state.messages[channel.state.messages.length - 1] === recentMessage;
|
|
849
|
-
setHasNoMoreRecentMessagesToLoad(stillHasLatestMessages);
|
|
850
|
-
channel.state.setIsUpToDate(stillHasLatestMessages);
|
|
851
874
|
}
|
|
852
|
-
} else {
|
|
853
|
-
const areLatestMessages = channel.state.messages === channel.state.latestMessages;
|
|
854
|
-
setHasNoMoreRecentMessagesToLoad(areLatestMessages);
|
|
855
|
-
channel.state.setIsUpToDate(areLatestMessages);
|
|
856
875
|
}
|
|
876
|
+
const hasLatestMessages = channel.state.latestMessages.length > 0;
|
|
877
|
+
channel.state.setIsUpToDate(hasLatestMessages);
|
|
878
|
+
setHasNoMoreRecentMessagesToLoad(hasLatestMessages);
|
|
857
879
|
copyChannelState();
|
|
880
|
+
restartSetsMergeFuncRef.current();
|
|
858
881
|
onAfterQueryCall?.();
|
|
859
882
|
} catch (err) {
|
|
860
883
|
if (err instanceof Error) {
|
|
@@ -877,35 +900,46 @@ const ChannelWithContext = <
|
|
|
877
900
|
// query for messages around the last read date
|
|
878
901
|
return channelQueryCallRef.current(
|
|
879
902
|
async () => {
|
|
880
|
-
|
|
903
|
+
const unreadCount = channel.countUnread();
|
|
904
|
+
if (unreadCount === 0) return;
|
|
905
|
+
const isLatestMessageSetShown = !!channel.state.messageSets.find(
|
|
906
|
+
(set) => set.isCurrent && set.isLatest,
|
|
907
|
+
);
|
|
908
|
+
if (isLatestMessageSetShown && unreadCount <= channel.state.messages.length) {
|
|
909
|
+
unreadMessageIdToScrollTo =
|
|
910
|
+
channel.state.messages[channel.state.messages.length - unreadCount].id;
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
881
913
|
const lastReadDate = channel.lastRead();
|
|
914
|
+
|
|
882
915
|
// if last read date is present we can just fetch messages around that date
|
|
883
916
|
// last read date not being present is an edge case if somewhere the user of SDK deletes the read state (this will usually never happen)
|
|
884
917
|
if (lastReadDate) {
|
|
918
|
+
setLoading(true);
|
|
885
919
|
// get totally 30 messages... max 15 before last read date and max 15 after last read date
|
|
886
920
|
// ref: https://github.com/GetStream/chat/pull/2588
|
|
887
|
-
await channel.query(
|
|
921
|
+
const res = await channel.query(
|
|
888
922
|
{
|
|
889
923
|
messages: {
|
|
890
924
|
created_at_around: lastReadDate,
|
|
891
925
|
limit: 30,
|
|
892
926
|
},
|
|
927
|
+
watch: true,
|
|
893
928
|
},
|
|
894
929
|
'new',
|
|
895
930
|
);
|
|
896
|
-
unreadMessageIdToScrollTo =
|
|
897
|
-
(m) => lastReadDate < m.created_at,
|
|
931
|
+
unreadMessageIdToScrollTo = res.messages.find(
|
|
932
|
+
(m) => lastReadDate < (m.created_at ? new Date(m.created_at) : new Date()),
|
|
898
933
|
)?.id;
|
|
934
|
+
if (unreadMessageIdToScrollTo) {
|
|
935
|
+
channel.state.loadMessageIntoState(unreadMessageIdToScrollTo);
|
|
936
|
+
}
|
|
899
937
|
} else {
|
|
900
|
-
|
|
901
|
-
await channel.state.loadMessageIntoState('latest');
|
|
902
|
-
}
|
|
903
|
-
},
|
|
904
|
-
() => {
|
|
905
|
-
if (unreadMessageIdToScrollTo) {
|
|
906
|
-
setTargetedMessage(unreadMessageIdToScrollTo);
|
|
938
|
+
await loadLatestMessagesRef.current();
|
|
907
939
|
}
|
|
908
940
|
},
|
|
941
|
+
undefined,
|
|
942
|
+
() => unreadMessageIdToScrollTo,
|
|
909
943
|
);
|
|
910
944
|
};
|
|
911
945
|
|
|
@@ -920,9 +954,25 @@ const ChannelWithContext = <
|
|
|
920
954
|
async () => {
|
|
921
955
|
setLoading(true);
|
|
922
956
|
if (messageIdToLoadAround) {
|
|
957
|
+
setMessages([]);
|
|
923
958
|
await channel.state.loadMessageIntoState(messageIdToLoadAround);
|
|
959
|
+
const currentMessageSet = channel.state.messageSets.find((set) => set.isCurrent);
|
|
960
|
+
if (currentMessageSet && !currentMessageSet?.isLatest) {
|
|
961
|
+
// if the current message set is not the latest, we will throw away the latest messages
|
|
962
|
+
// in order to attempt to not throw away, will attempt to merge it by loading 25 more messages
|
|
963
|
+
const recentCurrentSetMsgId =
|
|
964
|
+
currentMessageSet.messages[currentMessageSet.messages.length - 1].id;
|
|
965
|
+
await channel.query({
|
|
966
|
+
messages: {
|
|
967
|
+
id_gte: recentCurrentSetMsgId,
|
|
968
|
+
limit: 25,
|
|
969
|
+
},
|
|
970
|
+
watch: true,
|
|
971
|
+
});
|
|
972
|
+
// if the gap is more than 25, we will unfortunately have to throw away the latest messages
|
|
973
|
+
}
|
|
924
974
|
} else {
|
|
925
|
-
await
|
|
975
|
+
await loadLatestMessagesRef.current();
|
|
926
976
|
}
|
|
927
977
|
},
|
|
928
978
|
() => {
|
|
@@ -955,16 +1005,103 @@ const ChannelWithContext = <
|
|
|
955
1005
|
}
|
|
956
1006
|
});
|
|
957
1007
|
|
|
1008
|
+
/**
|
|
1009
|
+
* Utility method to mark that current set if latest into two.
|
|
1010
|
+
* With an empty latest set
|
|
1011
|
+
* This is useful when we know that we dont know the latest messages anymore
|
|
1012
|
+
* Or if we are loading a channel around a message
|
|
1013
|
+
*/
|
|
1014
|
+
const splitLatestCurrentMessageSetRef = useRef(() => {
|
|
1015
|
+
const currentLatestSet = channel.state.messageSets.find((set) => set.isCurrent && set.isLatest);
|
|
1016
|
+
if (!currentLatestSet) return;
|
|
1017
|
+
// unmark the current latest set
|
|
1018
|
+
currentLatestSet.isLatest = false;
|
|
1019
|
+
// create a new set with empty latest messages
|
|
1020
|
+
channel.state.messageSets.push({
|
|
1021
|
+
isCurrent: false,
|
|
1022
|
+
isLatest: true,
|
|
1023
|
+
messages: [],
|
|
1024
|
+
});
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* Utility method to merge current and latest message set.
|
|
1029
|
+
* Returns true if merge was successful, false otherwise.
|
|
1030
|
+
*/
|
|
1031
|
+
const mergeOverlappingMessageSetsRef = useRef((limitToMaxRenderPerBatch = false) => {
|
|
1032
|
+
if (hasOverlappingRecentMessagesRef.current) {
|
|
1033
|
+
const limit = 30; // 30 is the maxToRenderPerBatch
|
|
1034
|
+
// merge current and latest sets
|
|
1035
|
+
const latestMessageSet = channel.state.messageSets.find((set) => set.isLatest);
|
|
1036
|
+
const currentMessageSet = channel.state.messageSets.find((set) => set.isCurrent);
|
|
1037
|
+
if (latestMessageSet && currentMessageSet && latestMessageSet !== currentMessageSet) {
|
|
1038
|
+
if (limitToMaxRenderPerBatch && latestMessageSet.messages.length > limit) {
|
|
1039
|
+
currentMessageSet.messages = currentMessageSet.messages.concat(
|
|
1040
|
+
latestMessageSet.messages.slice(0, limit),
|
|
1041
|
+
);
|
|
1042
|
+
latestMessageSet.messages = latestMessageSet.messages.slice(limit);
|
|
1043
|
+
} else {
|
|
1044
|
+
channel.state.messageSets = channel.state.messageSets.filter((set) => !set.isLatest);
|
|
1045
|
+
currentMessageSet.messages = currentMessageSet.messages.concat(latestMessageSet.messages);
|
|
1046
|
+
currentMessageSet.isLatest = true;
|
|
1047
|
+
hasOverlappingRecentMessagesRef.current = false;
|
|
1048
|
+
clearInterval(mergeSetsIntervalRef.current);
|
|
1049
|
+
}
|
|
1050
|
+
return true;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
return false;
|
|
1054
|
+
});
|
|
1055
|
+
|
|
1056
|
+
const mergeSetsIntervalRef = useRef<NodeJS.Timeout>();
|
|
1057
|
+
|
|
1058
|
+
// clear the interval on unmount
|
|
1059
|
+
useEffect(
|
|
1060
|
+
() => () => {
|
|
1061
|
+
clearInterval(mergeSetsIntervalRef.current);
|
|
1062
|
+
},
|
|
1063
|
+
[],
|
|
1064
|
+
);
|
|
1065
|
+
|
|
1066
|
+
// if we had split the latest and current message set, we try to merge them back
|
|
1067
|
+
const restartSetsMergeFuncRef = useRef(() => {
|
|
1068
|
+
clearInterval(mergeSetsIntervalRef.current);
|
|
1069
|
+
if (!hasOverlappingRecentMessagesRef.current) return;
|
|
1070
|
+
mergeSetsIntervalRef.current = setInterval(() => {
|
|
1071
|
+
const currentLength = channel.state.messages.length || 0;
|
|
1072
|
+
const didMerge = mergeOverlappingMessageSetsRef.current(true);
|
|
1073
|
+
if (didMerge && channel.state.messages.length !== currentLength) {
|
|
1074
|
+
setMessages([...channel.state.messages]);
|
|
1075
|
+
}
|
|
1076
|
+
}, 1000);
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* Shows the latest messages from the channel state
|
|
1081
|
+
* If recent messages are empty, fetches new
|
|
1082
|
+
* @param clearLatest If true, clears the latest messages before loading (useful for complete refresh)
|
|
1083
|
+
*/
|
|
1084
|
+
const loadLatestMessagesRef = useRef(async (clearLatest = false) => {
|
|
1085
|
+
mergeOverlappingMessageSetsRef.current();
|
|
1086
|
+
if (clearLatest) {
|
|
1087
|
+
const latestSet = channel.state.messageSets.find((set) => set.isLatest);
|
|
1088
|
+
if (latestSet) latestSet.messages = [];
|
|
1089
|
+
}
|
|
1090
|
+
if (channel.state.latestMessages.length === 0) {
|
|
1091
|
+
await channel.query({}, 'latest');
|
|
1092
|
+
}
|
|
1093
|
+
await channel.state.loadMessageIntoState('latest');
|
|
1094
|
+
});
|
|
1095
|
+
|
|
958
1096
|
const loadChannel = () =>
|
|
959
1097
|
channelQueryCallRef.current(async () => {
|
|
960
1098
|
if (!channel?.initialized || !channel.state.isUpToDate) {
|
|
961
1099
|
await channel?.watch();
|
|
962
|
-
setHasNoMoreRecentMessagesToLoad(true);
|
|
963
|
-
channel?.state.setIsUpToDate(true);
|
|
964
1100
|
} else {
|
|
965
|
-
await
|
|
1101
|
+
await loadLatestMessagesRef.current(true);
|
|
966
1102
|
}
|
|
967
|
-
|
|
1103
|
+
channel?.state.setIsUpToDate(true);
|
|
1104
|
+
setHasNoMoreRecentMessagesToLoad(true);
|
|
968
1105
|
});
|
|
969
1106
|
|
|
970
1107
|
const reloadThread = async () => {
|
|
@@ -1002,6 +1139,8 @@ const ChannelWithContext = <
|
|
|
1002
1139
|
|
|
1003
1140
|
const resyncChannel = async () => {
|
|
1004
1141
|
if (!channel || syncingChannel) return;
|
|
1142
|
+
hasOverlappingRecentMessagesRef.current = false;
|
|
1143
|
+
clearInterval(mergeSetsIntervalRef.current);
|
|
1005
1144
|
setSyncingChannel(true);
|
|
1006
1145
|
|
|
1007
1146
|
setError(false);
|
|
@@ -1081,11 +1220,11 @@ const ChannelWithContext = <
|
|
|
1081
1220
|
finalMessages = state.messages;
|
|
1082
1221
|
}
|
|
1083
1222
|
|
|
1084
|
-
setHasNoMoreRecentMessagesToLoad(true);
|
|
1085
1223
|
channel.state.setIsUpToDate(true);
|
|
1086
1224
|
channel.state.clearMessages();
|
|
1087
1225
|
channel.state.addMessagesSorted(finalMessages);
|
|
1088
1226
|
channel.state.addPinnedMessages(state.pinned_messages);
|
|
1227
|
+
setHasNoMoreRecentMessagesToLoad(true);
|
|
1089
1228
|
setHasMore(true);
|
|
1090
1229
|
copyChannelState();
|
|
1091
1230
|
|
|
@@ -1141,10 +1280,10 @@ const ChannelWithContext = <
|
|
|
1141
1280
|
const reloadChannel = () =>
|
|
1142
1281
|
channelQueryCallRef.current(async () => {
|
|
1143
1282
|
setLoading(true);
|
|
1144
|
-
await
|
|
1283
|
+
await loadLatestMessagesRef.current(true);
|
|
1145
1284
|
setLoading(false);
|
|
1146
|
-
setHasNoMoreRecentMessagesToLoad(true);
|
|
1147
1285
|
channel?.state.setIsUpToDate(true);
|
|
1286
|
+
setHasNoMoreRecentMessagesToLoad(true);
|
|
1148
1287
|
});
|
|
1149
1288
|
|
|
1150
1289
|
/**
|
|
@@ -1162,8 +1301,10 @@ const ChannelWithContext = <
|
|
|
1162
1301
|
}: Parameters<ChannelContextValue<StreamChatGenerics>['loadChannelAtMessage']>[0]) => {
|
|
1163
1302
|
if (!channel) return;
|
|
1164
1303
|
channel.state.setIsUpToDate(false);
|
|
1304
|
+
hasOverlappingRecentMessagesRef.current = false;
|
|
1305
|
+
clearInterval(mergeSetsIntervalRef.current);
|
|
1165
1306
|
channel.state.clearMessages();
|
|
1166
|
-
setMessages([
|
|
1307
|
+
setMessages([]);
|
|
1167
1308
|
if (!messageId) {
|
|
1168
1309
|
await channel.query({
|
|
1169
1310
|
messages: {
|
|
@@ -1219,9 +1360,18 @@ const ChannelWithContext = <
|
|
|
1219
1360
|
});
|
|
1220
1361
|
|
|
1221
1362
|
if (state.messages.length < limit) {
|
|
1363
|
+
// make current set as the latest
|
|
1364
|
+
const currentSet = channel.state.messageSets.find((set) => set.isCurrent);
|
|
1365
|
+
if (currentSet && !currentSet.isLatest) {
|
|
1366
|
+
channel.state.messageSets = channel.state.messageSets.filter((set) => !set.isLatest);
|
|
1367
|
+
currentSet.isLatest = true;
|
|
1368
|
+
}
|
|
1222
1369
|
channel.state.setIsUpToDate(true);
|
|
1370
|
+
setHasNoMoreRecentMessagesToLoad(true);
|
|
1223
1371
|
} else {
|
|
1372
|
+
splitLatestCurrentMessageSetRef.current();
|
|
1224
1373
|
channel.state.setIsUpToDate(false);
|
|
1374
|
+
setHasNoMoreRecentMessagesToLoad(false);
|
|
1225
1375
|
}
|
|
1226
1376
|
};
|
|
1227
1377
|
|
|
@@ -1494,6 +1644,8 @@ const ChannelWithContext = <
|
|
|
1494
1644
|
attachments: message.attachments || [],
|
|
1495
1645
|
});
|
|
1496
1646
|
|
|
1647
|
+
mergeOverlappingMessageSetsRef.current();
|
|
1648
|
+
|
|
1497
1649
|
if (!channel?.state.isUpToDate) {
|
|
1498
1650
|
await reloadChannel();
|
|
1499
1651
|
}
|
|
@@ -1533,6 +1685,7 @@ const ChannelWithContext = <
|
|
|
1533
1685
|
const loadMoreFinished = useRef(
|
|
1534
1686
|
debounce(
|
|
1535
1687
|
(updatedHasMore: boolean, newMessages: ChannelState<StreamChatGenerics>['messages']) => {
|
|
1688
|
+
setLoading(false);
|
|
1536
1689
|
setLoadingMore(false);
|
|
1537
1690
|
setError(false);
|
|
1538
1691
|
setHasMore(updatedHasMore);
|
|
@@ -1551,9 +1704,8 @@ const ChannelWithContext = <
|
|
|
1551
1704
|
if (loadingMore || hasMore === false) {
|
|
1552
1705
|
return;
|
|
1553
1706
|
}
|
|
1554
|
-
setLoadingMore(true);
|
|
1555
1707
|
|
|
1556
|
-
const currentMessages =
|
|
1708
|
+
const currentMessages = channel.state.messages;
|
|
1557
1709
|
|
|
1558
1710
|
if (!currentMessages.length) {
|
|
1559
1711
|
return setLoadingMore(false);
|
|
@@ -1565,6 +1717,8 @@ const ChannelWithContext = <
|
|
|
1565
1717
|
return setLoadingMore(false);
|
|
1566
1718
|
}
|
|
1567
1719
|
|
|
1720
|
+
setLoadingMore(true);
|
|
1721
|
+
|
|
1568
1722
|
const oldestID = oldestMessage && oldestMessage.id;
|
|
1569
1723
|
|
|
1570
1724
|
try {
|
|
@@ -1601,18 +1755,31 @@ const ChannelWithContext = <
|
|
|
1601
1755
|
PaginatedMessageListContextValue<StreamChatGenerics>['loadMoreRecent']
|
|
1602
1756
|
>(
|
|
1603
1757
|
async (limit = 5) => {
|
|
1604
|
-
|
|
1758
|
+
const latestMessageSet = channel.state.messageSets.find((set) => set.isLatest);
|
|
1759
|
+
const latestLengthBeforeMerge = latestMessageSet?.messages.length || 0;
|
|
1760
|
+
const didMerge = mergeOverlappingMessageSetsRef.current(true);
|
|
1761
|
+
if (didMerge) {
|
|
1762
|
+
if (latestMessageSet && latestLengthBeforeMerge >= limit) {
|
|
1763
|
+
setLoadingMoreRecent(true);
|
|
1764
|
+
channel.state.setIsUpToDate(true);
|
|
1765
|
+
setHasNoMoreRecentMessagesToLoad(true);
|
|
1766
|
+
loadMoreRecentFinished(channel.state.messages);
|
|
1767
|
+
restartSetsMergeFuncRef.current();
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
if (channel.state.isUpToDate) {
|
|
1772
|
+
setLoadingMoreRecent(false);
|
|
1605
1773
|
return;
|
|
1606
1774
|
}
|
|
1607
|
-
|
|
1608
|
-
const currentMessages = messagesRef.current;
|
|
1775
|
+
const currentMessages = channel.state.messages;
|
|
1609
1776
|
const recentMessage = currentMessages[currentMessages.length - 1];
|
|
1610
1777
|
|
|
1611
1778
|
if (recentMessage?.status !== MessageStatusTypes.RECEIVED) {
|
|
1612
1779
|
setLoadingMoreRecent(false);
|
|
1613
1780
|
return;
|
|
1614
1781
|
}
|
|
1615
|
-
|
|
1782
|
+
setLoadingMoreRecent(true);
|
|
1616
1783
|
try {
|
|
1617
1784
|
if (channel) {
|
|
1618
1785
|
const queryResponse = await channel.query({
|
|
@@ -1622,7 +1789,15 @@ const ChannelWithContext = <
|
|
|
1622
1789
|
},
|
|
1623
1790
|
watch: true,
|
|
1624
1791
|
});
|
|
1625
|
-
|
|
1792
|
+
const gotAllRecentMessages = queryResponse.messages.length < limit;
|
|
1793
|
+
const currentSet = channel.state.messageSets.find((set) => set.isCurrent);
|
|
1794
|
+
if (gotAllRecentMessages && currentSet && !currentSet.isLatest) {
|
|
1795
|
+
channel.state.messageSets = channel.state.messageSets.filter((set) => !set.isLatest);
|
|
1796
|
+
// make current set as the latest
|
|
1797
|
+
currentSet.isLatest = true;
|
|
1798
|
+
}
|
|
1799
|
+
channel.state.setIsUpToDate(gotAllRecentMessages);
|
|
1800
|
+
setHasNoMoreRecentMessagesToLoad(gotAllRecentMessages);
|
|
1626
1801
|
loadMoreRecentFinished(channel.state.messages);
|
|
1627
1802
|
}
|
|
1628
1803
|
} catch (err) {
|
|
@@ -2190,6 +2365,7 @@ export const Channel = <
|
|
|
2190
2365
|
|
|
2191
2366
|
return (
|
|
2192
2367
|
<ChannelWithContext<StreamChatGenerics>
|
|
2368
|
+
key={props.channel?.cid}
|
|
2193
2369
|
{...{
|
|
2194
2370
|
client,
|
|
2195
2371
|
enableOfflineSupport,
|