Skip to content
Draft
46 changes: 22 additions & 24 deletions apps/meteor/app/ui-utils/client/lib/RoomHistoryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Emitter } from '@rocket.chat/emitter';
import { differenceInMilliseconds } from 'date-fns';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import type { MutableRefObject } from 'react';

import { onClientMessageReceived } from '../../../../client/lib/onClientMessageReceived';
import { getUserId } from '../../../../client/lib/user';
Expand Down Expand Up @@ -119,7 +118,13 @@ class RoomHistoryManagerClass extends Emitter {
this.run(() => this.emit(requestId));
}

public async getMore(rid: IRoom['_id'], { limit = defaultLimit }: { limit?: number } = {}): Promise<void> {
public async getMore(
rid: IRoom['_id'],
{
limit = defaultLimit,
scrollPositionCallback,
}: { limit?: number; scrollPositionCallback?: () => { scrollHeight: number; scrollTop: number } } = {},
): Promise<void> {
const room = this.getRoom(rid);

if (Tracker.nonreactive(() => room.hasMore.get()) !== true) {
Expand Down Expand Up @@ -162,12 +167,9 @@ class RoomHistoryManagerClass extends Emitter {
room.oldestTs = messages[messages.length - 1].ts;
}

const wrapper = await waitForElement('.messages-box .wrapper [data-overlayscrollbars-viewport]');

room.scroll = {
scrollHeight: wrapper.scrollHeight,
scrollTop: wrapper.scrollTop,
};
if (scrollPositionCallback) {
room.scroll = scrollPositionCallback();
}

await upsertMessageBulk({
msgs: messages.filter((msg) => msg.t !== 'command'),
Expand Down Expand Up @@ -199,31 +201,19 @@ class RoomHistoryManagerClass extends Emitter {
}
}

public restoreScroll(rid: IRoom['_id']) {
public getStoredScrollPosition(rid: IRoom['_id']) {
const room = this.getRoom(rid);
const wrapper = document.querySelector('.messages-box .wrapper [data-overlayscrollbars-viewport]');

if (room.scroll === undefined) {
return;
}

if (!wrapper) {
return;
}

const heightDiff = wrapper.scrollHeight - (room.scroll.scrollHeight ?? NaN);
wrapper.scrollTop = room.scroll.scrollTop + heightDiff;
room.scroll = undefined;
return room.scroll;
}

public async getMoreNext(rid: IRoom['_id'], atBottomRef: MutableRefObject<boolean>) {
public async getMoreNext(rid: IRoom['_id']) {
const room = this.getRoom(rid);
if (Tracker.nonreactive(() => room.hasMoreNext.get()) !== true) {
return;
}

await this.queue();
atBottomRef.current = false;

room.isLoading.set(true);

Expand Down Expand Up @@ -296,6 +286,14 @@ class RoomHistoryManagerClass extends Emitter {
}

public async getSurroundingMessages(message?: Pick<IMessage, '_id' | 'rid'> & { ts?: Date }) {
return this.loadSurroundingMessages(message, true);
}

public async getSurroundingChannelMessages(message?: Pick<IMessage, '_id' | 'rid'> & { ts?: Date }) {
return this.loadSurroundingMessages(message, false);
}

private async loadSurroundingMessages(message: (Pick<IMessage, '_id' | 'rid'> & { ts?: Date }) | undefined, showThreadMessages: boolean) {
if (!message?.rid) {
return;
}
Expand All @@ -309,7 +307,7 @@ class RoomHistoryManagerClass extends Emitter {
const room = this.getRoom(message.rid);

const subscription = Subscriptions.state.find((record) => record.rid === message.rid);
const result = await callWithErrorHandling('loadSurroundingMessages', message, defaultLimit);
const result = await callWithErrorHandling('loadSurroundingMessages', message, defaultLimit, showThreadMessages);

this.clear(message.rid);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export type MessageListContextValue = {
};
autoTranslateLanguage?: string;
showColors: boolean;
jumpToMessageParam?: string;
username: string | undefined;
apiEmbedEnabled: boolean;
readReceipts: {
Expand Down Expand Up @@ -90,9 +89,6 @@ export const useMessageListShowRoles = (): MessageListContextValue['showRoles']
export const useMessageListShowRealName = (): MessageListContextValue['showRealName'] => useContext(MessageListContext).showRealName;
export const useMessageListShowUsername = (): MessageListContextValue['showUsername'] => useContext(MessageListContext).showUsername;
export const useMessageListHighlights = (): MessageListContextValue['highlights'] => useContext(MessageListContext).highlights;
export const useMessageListJumpToMessageParam = (): MessageListContextValue['jumpToMessageParam'] =>
useContext(MessageListContext).jumpToMessageParam;

export const useUserHasReacted: MessageListContextValue['useUserHasReacted'] = (message: IMessage) =>
useContext(MessageListContext).useUserHasReacted(message);
export const useOpenEmojiPicker: MessageListContextValue['useOpenEmojiPicker'] = (...args) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
useIsSelectedMessage,
useCountSelected,
} from '../../../views/room/MessageList/contexts/SelectedMessagesContext';
import { useJumpToMessage } from '../../../views/room/MessageList/hooks/useJumpToMessage';
import Emoji from '../../Emoji';
import IgnoredContent from '../IgnoredContent';
import MessageHeader from '../MessageHeader';
Expand Down Expand Up @@ -86,11 +85,9 @@ const RoomMessage = ({
const { enabled: readReceiptEnabled } = useMessageListReadReceipts();

useCountSelected();
const messageRef = useJumpToMessage(message._id);

return (
<Message
ref={messageRef}
id={message._id}
role='listitem'
aria-roledescription={t('message')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { memo } from 'react';

import type { MessageActionContext } from '../../../../app/ui-utils/client/lib/MessageAction';
import { useIsMessageHighlight } from '../../../views/room/MessageList/contexts/MessageHighlightContext';
import { useJumpToMessage } from '../../../views/room/MessageList/hooks/useJumpToMessage';
import Emoji from '../../Emoji';
import IgnoredContent from '../IgnoredContent';
import MessageHeader from '../MessageHeader';
Expand All @@ -32,16 +31,12 @@ const ThreadMessage = ({ message, sequential, unread, showUserAvatar }: ThreadMe

// Checks if is videoconf message to limit toolbox actions
const messageContext: MessageActionContext = isVideoConfMessage(message) ? 'videoconf-threads' : 'threads';

const messageRef = useJumpToMessage(message._id);

return (
<Message
role='listitem'
aria-roledescription={t('thread_message')}
tabIndex={0}
id={message._id}
ref={messageRef}
isEditing={editing}
isPending={message.temp}
sequential={sequential}
Expand Down
75 changes: 46 additions & 29 deletions apps/meteor/client/views/room/MessageList/MessageList.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { isThreadMessage } from '@rocket.chat/core-typings';
import { MessageTypes } from '@rocket.chat/message-types';
import type { IRoom, IUser } from '@rocket.chat/core-typings';
import { useSetting, useUserPreference } from '@rocket.chat/ui-contexts';
import type { ComponentProps } from 'react';
import { Fragment } from 'react';
import type { ComponentProps, MutableRefObject, Ref, RefObject } from 'react';

import { MessageListItem } from './MessageListItem';
import type { VirtualizerHandle } from './VirtualizedMessageList';
import { VirtualizedMessageList } from './VirtualizedMessageList';
import { useRoomSubscription } from '../contexts/RoomContext';
import { useFirstUnreadMessageId } from '../hooks/useFirstUnreadMessageId';
import { SelectedMessagesProvider } from '../providers/SelectedMessagesProvider';
import { useMessages } from './hooks/useMessages';
import { isMessageSequential } from './lib/isMessageSequential';
import MessageListProvider from './providers/MessageListProvider';

type MessageListProps = {
rid: IRoom['_id'];
messageListRef: ComponentProps<typeof MessageListProvider>['messageListRef'];
scrollContainerRef?: MutableRefObject<HTMLElement | null>;
isLoadingMoreMessages: boolean;
canPreview: boolean;
hasMorePreviousMessages: boolean;
hasMoreNextMessages: boolean;
user: IUser | null;
room: IRoom;
retentionPolicy: RetentionPolicy;
innerRef: Ref<HTMLElement>;
virtualizerHandle: RefObject<VirtualizerHandle>;
};

export const MessageList = function MessageList({ rid, messageListRef }: MessageListProps) {
export const MessageList = function MessageList({
rid,
messageListRef,
scrollContainerRef,
isLoadingMoreMessages,
canPreview,
hasMorePreviousMessages,
hasMoreNextMessages,
user,
room,
retentionPolicy,
innerRef,
virtualizerHandle,
}: MessageListProps) {
const messages = useMessages({ rid });
const subscription = useRoomSubscription();
const showUserAvatar = !!useUserPreference<boolean>('displayAvatars');
Expand All @@ -28,27 +48,24 @@ export const MessageList = function MessageList({ rid, messageListRef }: Message
return (
<MessageListProvider messageListRef={messageListRef}>
<SelectedMessagesProvider>
{messages.map((message, index, { [index - 1]: previous }) => {
const sequential = isMessageSequential(message, previous, messageGroupingPeriod);
const showUnreadDivider = firstUnreadMessageId === message._id;
const system = MessageTypes.isSystemMessage(message);
const visible = !isThreadMessage(message) && !system;

return (
<Fragment key={message._id}>
<MessageListItem
message={message}
previous={previous}
showUnreadDivider={showUnreadDivider}
showUserAvatar={showUserAvatar}
sequential={sequential}
visible={visible}
subscription={subscription}
system={system}
/>
</Fragment>
);
})}
<VirtualizedMessageList
rid={rid}
messages={messages}
scrollContainerRef={scrollContainerRef}
messageGroupingPeriod={messageGroupingPeriod}
firstUnreadMessageId={firstUnreadMessageId}
showUserAvatar={showUserAvatar}
subscription={subscription}
innerRef={innerRef}
isLoadingMoreMessages={isLoadingMoreMessages}
canPreview={canPreview}
hasMorePreviousMessages={hasMorePreviousMessages}
hasMoreNextMessages={hasMoreNextMessages}
user={user}
room={room}
retentionPolicy={retentionPolicy}
virtualizerHandle={virtualizerHandle}
/>
</SelectedMessagesProvider>
</MessageListProvider>
);
Expand Down
Loading
Loading