split up load more messages from top or bottom

also split up just fetching the last messages from fetching based on
unread/ lastTopMessageId
This commit is contained in:
audric 2022-01-19 12:35:32 +11:00
parent 381cb77ad9
commit 12b00720f4
13 changed files with 247 additions and 127 deletions

View File

@ -71,6 +71,7 @@ module.exports = {
getOutgoingWithoutExpiresAt,
getNextExpiringMessage,
getMessagesByConversation,
getLastMessagesByConversation,
getFirstUnreadMessageIdInConversation,
hasConversationOutgoingMessage,
trimMessages,
@ -2230,27 +2231,83 @@ function getUnreadCountByConversation(conversationId) {
// Note: Sorting here is necessary for getting the last message (with limit 1)
// be sure to update the sorting order to sort messages on redux too (sortMessages)
const orderByClause =
'ORDER BY serverTimestamp DESC, serverId DESC, sent_at DESC, received_at DESC';
function getMessagesByConversation(conversationId, { messageId = null } = {}) {
const absLimit = 30;
// If messageId is given it means we are opening the conversation to that specific messageId,
// or that we just scrolled to it by a quote click and needs to load around it.
// If messageId is null, it means we are just opening the convo to the last unread message, or at the bottom
const firstUnread = getFirstUnreadMessageIdInConversation(conversationId);
if (messageId || firstUnread) {
const messageFound = getMessageById(messageId || firstUnread);
if (messageFound && messageFound.conversationId === conversationId) {
console.warn('firstUnread', messageId, firstUnread, messageFound);
const rows = globalInstance
.prepare(
`WITH cte AS (
SELECT id, json, row_number() OVER (${orderByClause}) as row_number
FROM messages
), current AS (
SELECT row_number
FROM cte
WHERE id = $messageId
)
SELECT cte.*
FROM cte, current
WHERE ABS(cte.row_number - current.row_number) <= $limit
ORDER BY cte.row_number;
`
)
.all({
conversationId,
messageId: messageId || firstUnread,
limit: absLimit,
});
console.warn('rows', rows);
return map(rows, row => jsonToObject(row.json));
}
console.warn(
`getMessagesByConversation: Could not find messageId ${messageId} in db with conversationId: ${conversationId}. Just fetching the convo as usual.`
);
}
function getMessagesByConversation(
conversationId,
{ limit = 100, receivedAt = Number.MAX_VALUE, type = '%' } = {}
) {
const rows = globalInstance
.prepare(
`
SELECT json FROM ${MESSAGES_TABLE} WHERE
conversationId = $conversationId AND
received_at < $received_at AND
type LIKE $type
ORDER BY serverTimestamp DESC, serverId DESC, sent_at DESC, received_at DESC
conversationId = $conversationId
${orderByClause}
LIMIT $limit;
`
)
.all({
conversationId,
limit: 2 * absLimit,
});
return map(rows, row => jsonToObject(row.json));
}
function getLastMessagesByConversation(conversationId, limit) {
if (!isNumber(limit)) {
throw new Error('limit must be a number');
}
const rows = globalInstance
.prepare(
`
SELECT json FROM ${MESSAGES_TABLE} WHERE
conversationId = $conversationId
${orderByClause}
LIMIT $limit;
`
)
.all({
conversationId,
received_at: receivedAt,
limit,
type,
});
return map(rows, row => jsonToObject(row.json));
}

View File

@ -87,7 +87,7 @@ export class SessionConversation extends React.Component<Props, State> {
};
this.messageContainerRef = React.createRef();
this.dragCounter = 0;
this.updateMemberList = _.debounce(this.updateMemberListBouncy.bind(this), 1000);
this.updateMemberList = _.debounce(this.updateMemberListBouncy.bind(this), 10000);
autoBind(this);
}

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useLayoutEffect } from 'react';
import { useSelector } from 'react-redux';
// tslint:disable-next-line: no-submodule-imports
import useKey from 'react-use/lib/useKey';
@ -9,7 +9,10 @@ import {
PropsForGroupInvitation,
PropsForGroupUpdate,
} from '../../state/ducks/conversations';
import { getSortedMessagesTypesOfSelectedConversation } from '../../state/selectors/conversations';
import {
getOldTopMessageId,
getSortedMessagesTypesOfSelectedConversation,
} from '../../state/selectors/conversations';
import { GroupUpdateMessage } from './message/message-item/GroupUpdateMessage';
import { DataExtractionNotification } from './message/message-item/DataExtractionNotification';
import { MessageDateBreak } from './message/message-item/DateBreak';
@ -26,12 +29,32 @@ function isNotTextboxEvent(e: KeyboardEvent) {
export const SessionMessagesList = (props: {
scrollToQuoteMessage: (options: QuoteClickOptions) => Promise<void>;
scrollAfterLoadMore: (
messageIdToScrollTo: string,
block: ScrollLogicalPosition | undefined
) => void;
onPageUpPressed: () => void;
onPageDownPressed: () => void;
onHomePressed: () => void;
onEndPressed: () => void;
}) => {
const messagesProps = useSelector(getSortedMessagesTypesOfSelectedConversation);
const oldTopMessageId = useSelector(getOldTopMessageId);
useLayoutEffect(() => {
const newTopMessageId = messagesProps.length
? messagesProps[messagesProps.length - 1].message.props.messageId
: undefined;
console.warn('useLayoutEffect ', {
oldTopMessageId,
newTopMessageId,
length: messagesProps.length,
});
if (oldTopMessageId !== newTopMessageId && oldTopMessageId && newTopMessageId) {
props.scrollAfterLoadMore(oldTopMessageId, 'center');
}
});
useKey('PageUp', () => {
props.onPageUpPressed();

View File

@ -95,56 +95,59 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
public componentDidUpdate(
prevProps: Props,
_prevState: any,
snapShot: { fakeScrollTop: number; realScrollTop: number; scrollHeight: number }
_prevState: any
// snapShot: {
// fakeScrollTop: number;
// realScrollTop: number;
// scrollHeight: number;
// oldTopMessageId?: string;
// }
) {
// this was hard to write, it should be hard to read
// just make sure you don't remove that as a bug in chrome makes the column-reverse do bad things
// https://bugs.chromium.org/p/chromium/issues/detail?id=1189195&q=column-reverse&can=2#makechanges
const currentRef = this.props.messageContainerRef.current;
// const { oldTopMessageId } = snapShot;
// console.warn('didupdate with oldTopMessageId', oldTopMessageId);
// // If you want to mess with this, be my guest.
// // just make sure you don't remove that as a bug in chrome makes the column-reverse do bad things
// // https://bugs.chromium.org/p/chromium/issues/detail?id=1189195&q=column-reverse&can=2#makechanges
const isSameConvo = prevProps.conversationKey === this.props.conversationKey;
const prevMsgLength = prevProps.messagesProps.length;
const newMsgLength = this.props.messagesProps.length;
const prevFirstMesssageId = prevProps.messagesProps[0]?.propsForMessage.id;
const newFirstMesssageId = this.props.messagesProps[0]?.propsForMessage.id;
const messageAddedWasMoreRecentOne = prevFirstMesssageId !== newFirstMesssageId;
if (isSameConvo && snapShot?.realScrollTop && prevMsgLength !== newMsgLength && currentRef) {
if (messageAddedWasMoreRecentOne) {
if (snapShot.scrollHeight - snapShot.realScrollTop < 50) {
// consider that we were scrolled to bottom
currentRef.scrollTop = 0;
} else {
currentRef.scrollTop = -(currentRef.scrollHeight - snapShot.realScrollTop);
}
} else {
currentRef.scrollTop = snapShot.fakeScrollTop;
}
}
if (!isSameConvo || (prevMsgLength === 0 && newMsgLength !== 0)) {
// if (isSameConvo && oldTopMessageId) {
// this.scrollToMessage(oldTopMessageId, 'center');
// // if (messageAddedWasMoreRecentOne) {
// // if (snapShot.scrollHeight - snapShot.realScrollTop < 50) {
// // // consider that we were scrolled to bottom
// // currentRef.scrollTop = 0;
// // } else {
// // currentRef.scrollTop = -(currentRef.scrollHeight - snapShot.realScrollTop);
// // }
// // } else {
// // currentRef.scrollTop = snapShot.fakeScrollTop;
// // }
// }
if (!isSameConvo) {
console.info('Not same convo, resetting scrolling posiiton');
this.setupTimeoutResetQuotedHighlightedMessage(this.props.animateQuotedMessageId);
// displayed conversation changed. We have a bit of cleaning to do here
this.initialMessageLoadingPosition();
}
}
public getSnapshotBeforeUpdate() {
const messageContainer = this.props.messageContainerRef.current;
const scrollTop = messageContainer?.scrollTop || undefined;
const scrollHeight = messageContainer?.scrollHeight || undefined;
// as we use column-reverse for displaying message list
// the top is < 0
// tslint:disable-next-line: restrict-plus-operands
const realScrollTop = scrollHeight && scrollTop ? scrollHeight + scrollTop : undefined;
return {
realScrollTop,
fakeScrollTop: scrollTop,
scrollHeight: scrollHeight,
};
// const messagePropsBeforeUpdate = this.props.messagesProps;
// const oldTopMessageId = messagePropsBeforeUpdate.length
// ? messagePropsBeforeUpdate[messagePropsBeforeUpdate.length - 1].propsForMessage.id
// : undefined;
// console.warn('oldTopMessageId', oldTopMessageId);
// const messageContainer = this.props.messageContainerRef.current;
// const scrollTop = messageContainer?.scrollTop || undefined;
// const scrollHeight = messageContainer?.scrollHeight || undefined;
// // as we use column-reverse for displaying message list
// // the top is < 0
// const realScrollTop = scrollHeight && scrollTop ? scrollHeight + scrollTop : undefined;
// return {
// realScrollTop,
// fakeScrollTop: scrollTop,
// scrollHeight: scrollHeight,
// oldTopMessageId,
// };
}
public render() {
@ -180,6 +183,7 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
<SessionMessagesList
scrollToQuoteMessage={this.scrollToQuoteMessage}
scrollAfterLoadMore={this.scrollToMessage}
onPageDownPressed={this.scrollPgDown}
onPageUpPressed={this.scrollPgUp}
onHomePressed={this.scrollTop}
@ -207,6 +211,8 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
return;
}
console.warn('firstUnreadOnOpen', firstUnreadOnOpen);
if (
(conversation.unreadCount && conversation.unreadCount <= 0) ||
firstUnreadOnOpen === undefined
@ -218,6 +224,7 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
const firstUnreadIndex = messagesProps.findIndex(
m => m.propsForMessage.id === firstUnreadOnOpen
);
console.warn('firstUnreadIndex', firstUnreadIndex);
if (firstUnreadIndex === -1) {
// the first unread message is not in the 30 most recent messages
@ -260,8 +267,10 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
}
}
private scrollToMessage(messageId: string, block: 'center' | 'end' | 'nearest' | 'start') {
private scrollToMessage(messageId: string, block: ScrollLogicalPosition | undefined) {
const messageElementDom = document.getElementById(`msg-${messageId}`);
console.warn('scrollToMessage', messageElementDom);
debugger;
messageElementDom?.scrollIntoView({
behavior: 'auto',
block,

View File

@ -37,6 +37,7 @@ async function getMediaGalleryProps(
documents: Array<MediaItemType>;
media: Array<MediaItemType>;
}> {
console.warn('getMediaGalleryProps');
// We fetch more documents than media as they dont require to be loaded
// into memory right away. Revisit this once we have infinite scrolling:
const rawMedia = await getMessagesWithVisualMediaAttachments(conversationId, {

View File

@ -1,6 +1,6 @@
import React from 'react';
import styled from 'styled-components';
import { getMessageById, getMessagesByConversation } from '../../../../data/data';
import { getLastMessagesByConversation, getMessageById } from '../../../../data/data';
import { getConversationController } from '../../../../session/conversations';
import { AttachmentDownloads } from '../../../../session/utils';
import { updateConfirmModal } from '../../../../state/ducks/modalDialog';
@ -42,9 +42,7 @@ export const ClickToTrustSender = (props: { messageId: string }) => {
onClickOk: async () => {
convo.set({ isTrustedForAttachmentDownload: true });
await convo.commit();
const messagesInConvo = await getMessagesByConversation(convo.id, {
limit: 100,
});
const messagesInConvo = await getLastMessagesByConversation(convo.id, 100, false);
await Promise.all(
messagesInConvo.map(async message => {

View File

@ -12,7 +12,6 @@ import { messageExpired } from '../../../../state/ducks/conversations';
import {
getGenericReadableMessageSelectorProps,
getIsMessageSelected,
getQuotedMessageToAnimate,
isMessageSelectionMode,
} from '../../../../state/selectors/conversations';
import { getIncrement } from '../../../../util/timer';

View File

@ -3,15 +3,14 @@ import React, { useCallback } from 'react';
import { InView } from 'react-intersection-observer';
import { useDispatch, useSelector } from 'react-redux';
import { getMessageById } from '../../../../data/data';
import { Constants } from '../../../../session';
import { getConversationController } from '../../../../session/conversations';
import {
fetchMessagesForConversation,
fetchTopMessagesForConversation,
markConversationFullyRead,
showScrollToBottomButton,
} from '../../../../state/ducks/conversations';
import {
areMoreMessagesBeingFetched,
areMoreTopMessagesBeingFetched,
getHaveDoneFirstScroll,
getLoadedMessagesLength,
getMostRecentMessageId,
@ -29,13 +28,12 @@ type ReadableMessageProps = {
onContextMenu?: (e: React.MouseEvent<HTMLElement>) => void;
};
const debouncedTriggerLoadMore = _.debounce(
(loadedMessagesLength: number, selectedConversationKey: string | undefined) => {
const numMessages = loadedMessagesLength + Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT;
const debouncedTriggerLoadMoreTop = _.debounce(
(selectedConversationKey: string, oldestMessageId: string) => {
(window.inboxStore?.dispatch as any)(
fetchMessagesForConversation({
conversationKey: selectedConversationKey as string,
count: numMessages,
fetchTopMessagesForConversation({
conversationKey: selectedConversationKey,
oldTopMessageId: oldestMessageId,
})
);
},
@ -53,7 +51,7 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
const haveDoneFirstScroll = useSelector(getHaveDoneFirstScroll);
const mostRecentMessageId = useSelector(getMostRecentMessageId);
const oldestMessageId = useSelector(getOldestMessageId);
const fetchingMore = useSelector(areMoreMessagesBeingFetched);
const fetchingMore = useSelector(areMoreTopMessagesBeingFetched);
const shouldMarkReadWhenVisible = isUnread;
const onVisible = useCallback(
@ -83,8 +81,14 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
}
}
if (inView === true && isAppFocused && oldestMessageId === messageId && !fetchingMore) {
debouncedTriggerLoadMore(loadedMessagesLength, selectedConversationKey);
if (
inView === true &&
isAppFocused &&
oldestMessageId === messageId &&
!fetchingMore &&
selectedConversationKey
) {
debouncedTriggerLoadMoreTop(selectedConversationKey, oldestMessageId);
}
// this part is just handling the marking of the message as read if needed
@ -115,7 +119,6 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
receivedAt,
shouldMarkReadWhenVisible,
messageId,
debouncedTriggerLoadMore,
]
);

View File

@ -3,11 +3,7 @@ import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
// tslint:disable-next-line: no-submodule-imports
import useUpdate from 'react-use/lib/useUpdate';
import {
createOrUpdateItem,
fillWithTestData,
hasLinkPreviewPopupBeenDisplayed,
} from '../../../data/data';
import { createOrUpdateItem, hasLinkPreviewPopupBeenDisplayed } from '../../../data/data';
import { ToastUtils } from '../../../session/utils';
import { updateConfirmModal } from '../../../state/ducks/modalDialog';
import { toggleAudioAutoplay } from '../../../state/ducks/userConfig';

View File

@ -125,6 +125,7 @@ const channelsToMake = {
getOutgoingWithoutExpiresAt,
getNextExpiringMessage,
getMessagesByConversation,
getLastMessagesByConversation,
getFirstUnreadMessageIdInConversation,
hasConversationOutgoingMessage,
getSeenMessagesByHashList,
@ -753,18 +754,45 @@ export async function getUnreadCountByConversation(conversationId: string): Prom
export async function getMessagesByConversation(
conversationId: string,
{ limit = 100, receivedAt = Number.MAX_VALUE, type = '%', skipTimerInit = false }
{
skipTimerInit = false,
messageId = null,
}: { limit?: number; skipTimerInit?: false; messageId: string | null }
): Promise<MessageCollection> {
const messages = await channels.getMessagesByConversation(conversationId, {
limit,
receivedAt,
type,
messageId,
});
if (skipTimerInit) {
for (const message of messages) {
message.skipTimerInit = skipTimerInit;
}
}
console.warn('messages length got: ', messages.length);
return new MessageCollection(messages);
}
/**
* This function should only be used when you don't want to render the messages.
* It just grabs the last messages of a conversation.
*
* To be used when you want for instance to remove messages from a conversations, in order.
* Or to trigger downloads of a attachments from a just approved contact (clicktotrustSender)
* @param conversationId the conversationId to fetch messages from
* @param limit the maximum number of messages to return
* @param skipTimerInit see MessageModel.skipTimerInit
* @returns the fetched messageModels
*/
export async function getLastMessagesByConversation(
conversationId: string,
limit: number,
skipTimerInit: boolean
): Promise<MessageCollection> {
const messages = await channels.getLastMessagesByConversation(conversationId, limit);
if (skipTimerInit) {
for (const message of messages) {
message.skipTimerInit = skipTimerInit;
}
}
return new MessageCollection(messages);
}
@ -795,12 +823,10 @@ export async function getSeenMessagesByHashList(hashes: Array<string>): Promise<
export async function removeAllMessagesInConversation(conversationId: string): Promise<void> {
let messages;
do {
// Yes, we really want the await in the loop. We're deleting 100 at a
// Yes, we really want the await in the loop. We're deleting 500 at a
// time so we don't use too much memory.
// eslint-disable-next-line no-await-in-loop
messages = await getMessagesByConversation(conversationId, {
limit: 500,
});
messages = await getLastMessagesByConversation(conversationId, 500, false);
if (!messages.length) {
return;
}

View File

@ -12,7 +12,7 @@ import { MessageModel } from './message';
import { MessageAttributesOptionals, MessageModelType } from './messageType';
import autoBind from 'auto-bind';
import {
getMessagesByConversation,
getLastMessagesByConversation,
getUnreadByConversation,
getUnreadCountByConversation,
removeMessage as dataRemoveMessage,
@ -787,10 +787,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
if (!this.get('active_at')) {
return;
}
const messages = await getMessagesByConversation(this.id, {
limit: 1,
skipTimerInit: true,
});
const messages = await getLastMessagesByConversation(this.id, 1, true);
const lastMessageModel = messages.at(0);
const lastMessageJSON = lastMessageModel ? lastMessageModel.toJSON() : null;
const lastMessageStatusModel = lastMessageModel

View File

@ -1,4 +1,3 @@
import { Constants } from '../../session';
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { getConversationController } from '../../session/conversations';
import { getFirstUnreadMessageIdInConversation, getMessagesByConversation } from '../../data/data';
@ -273,7 +272,8 @@ export type ConversationsStateType = {
selectedMessageIds: Array<string>;
lightBox?: LightBoxOptions;
quotedMessage?: ReplyingToMessageProps;
areMoreMessagesBeingFetched: boolean;
areMoreTopMessagesBeingFetched: boolean;
oldTopMessageId: string | null;
haveDoneFirstScroll: boolean;
showScrollButton: boolean;
@ -287,28 +287,23 @@ export type MentionsMembersType = Array<{
authorProfileName: string;
}>;
async function getMessages(
conversationKey: string,
numMessagesToFetch: number
): Promise<Array<MessageModelPropsWithoutConvoProps>> {
async function getMessages({
conversationKey,
messageId,
}: {
conversationKey: string;
messageId: string | null;
}): Promise<Array<MessageModelPropsWithoutConvoProps>> {
const conversation = getConversationController().get(conversationKey);
if (!conversation) {
// no valid conversation, early return
window?.log?.error('Failed to get convo on reducer.');
return [];
}
let msgCount = numMessagesToFetch;
msgCount =
msgCount > Constants.CONVERSATION.MAX_MESSAGE_FETCH_COUNT
? Constants.CONVERSATION.MAX_MESSAGE_FETCH_COUNT
: msgCount;
if (msgCount < Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT) {
msgCount = Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT;
}
console.warn('getMessages with messageId', messageId);
const messageSet = await getMessagesByConversation(conversationKey, {
limit: msgCount,
messageId,
});
const messageProps: Array<MessageModelPropsWithoutConvoProps> = messageSet.models.map(m =>
@ -325,24 +320,27 @@ export type SortedMessageModelProps = MessageModelPropsWithoutConvoProps & {
type FetchedMessageResults = {
conversationKey: string;
messagesProps: Array<MessageModelPropsWithoutConvoProps>;
oldTopMessageId: string | null;
};
export const fetchMessagesForConversation = createAsyncThunk(
export const fetchTopMessagesForConversation = createAsyncThunk(
'messages/fetchByConversationKey',
async ({
conversationKey,
count,
oldTopMessageId,
}: {
conversationKey: string;
count: number;
oldTopMessageId: string | null;
}): Promise<FetchedMessageResults> => {
console.warn('fetchTopMessagesForConversation oldTop:', oldTopMessageId);
const beforeTimestamp = Date.now();
// tslint:disable-next-line: no-console
perfStart('fetchMessagesForConversation');
const messagesProps = await getMessages(conversationKey, count);
perfStart('fetchTopMessagesForConversation');
const messagesProps = await getMessages({
conversationKey,
messageId: oldTopMessageId,
});
const afterTimestamp = Date.now();
// tslint:disable-next-line: no-console
perfEnd('fetchMessagesForConversation', 'fetchMessagesForConversation');
perfEnd('fetchTopMessagesForConversation', 'fetchTopMessagesForConversation');
const time = afterTimestamp - beforeTimestamp;
window?.log?.info(`Loading ${messagesProps.length} messages took ${time}ms to load.`);
@ -350,6 +348,7 @@ export const fetchMessagesForConversation = createAsyncThunk(
return {
conversationKey,
messagesProps,
oldTopMessageId,
};
}
);
@ -363,11 +362,12 @@ export function getEmptyConversationState(): ConversationsStateType {
messageDetailProps: undefined,
showRightPanel: false,
selectedMessageIds: [],
areMoreMessagesBeingFetched: false,
areMoreTopMessagesBeingFetched: false,
showScrollButton: false,
mentionMembers: [],
firstUnreadMessageId: undefined,
haveDoneFirstScroll: false,
oldTopMessageId: null,
};
}
@ -697,7 +697,7 @@ const conversationsSlice = createSlice({
conversationLookup: state.conversationLookup,
selectedConversation: action.payload.id,
areMoreMessagesBeingFetched: false,
areMoreTopMessagesBeingFetched: false,
messages: action.payload.initialMessages,
showRightPanel: false,
selectedMessageIds: [],
@ -708,6 +708,7 @@ const conversationsSlice = createSlice({
nextMessageToPlay: undefined,
showScrollButton: false,
animateQuotedMessageId: undefined,
oldTopMessageId: null,
mentionMembers: [],
firstUnreadMessageId: action.payload.firstUnreadIdOnOpen,
@ -762,26 +763,28 @@ const conversationsSlice = createSlice({
extraReducers: (builder: any) => {
// Add reducers for additional action types here, and handle loading state as needed
builder.addCase(
fetchMessagesForConversation.fulfilled,
fetchTopMessagesForConversation.fulfilled,
(state: ConversationsStateType, action: PayloadAction<FetchedMessageResults>) => {
// this is called once the messages are loaded from the db for the currently selected conversation
const { messagesProps, conversationKey } = action.payload;
const { messagesProps, conversationKey, oldTopMessageId } = action.payload;
// double check that this update is for the shown convo
if (conversationKey === state.selectedConversation) {
console.warn('fullfilled', oldTopMessageId);
return {
...state,
oldTopMessageId,
messages: messagesProps,
areMoreMessagesBeingFetched: false,
areMoreTopMessagesBeingFetched: false,
};
}
return state;
}
);
builder.addCase(fetchMessagesForConversation.pending, (state: ConversationsStateType) => {
state.areMoreMessagesBeingFetched = true;
builder.addCase(fetchTopMessagesForConversation.pending, (state: ConversationsStateType) => {
state.areMoreTopMessagesBeingFetched = true;
});
builder.addCase(fetchMessagesForConversation.rejected, (state: ConversationsStateType) => {
state.areMoreMessagesBeingFetched = false;
builder.addCase(fetchTopMessagesForConversation.rejected, (state: ConversationsStateType) => {
state.areMoreTopMessagesBeingFetched = false;
});
},
});
@ -855,7 +858,10 @@ export async function openConversationWithMessages(args: {
// preload 30 messages
perfStart('getMessages');
const initialMessages = await getMessages(conversationKey, 30);
const initialMessages = await getMessages({
conversationKey,
messageId: null,
});
perfEnd('getMessages', 'getMessages');
window.inboxStore?.dispatch(

View File

@ -590,9 +590,9 @@ export const getQuotedMessage = createSelector(
(state: ConversationsStateType): ReplyingToMessageProps | undefined => state.quotedMessage
);
export const areMoreMessagesBeingFetched = createSelector(
export const areMoreTopMessagesBeingFetched = createSelector(
getConversations,
(state: ConversationsStateType): boolean => state.areMoreMessagesBeingFetched || false
(state: ConversationsStateType): boolean => state.areMoreTopMessagesBeingFetched || false
);
export const getHaveDoneFirstScroll = createSelector(
@ -1116,3 +1116,8 @@ export const getGenericReadableMessageSelectorProps = createSelector(
return msgProps;
}
);
export const getOldTopMessageId = createSelector(
getConversations,
(state: ConversationsStateType): string | null => state.oldTopMessageId || null
);