Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: remove hardcoded position for message date #31866

Merged
merged 1 commit into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions apps/meteor/client/views/room/body/RoomBody.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { IMessage, IUser } from '@rocket.chat/core-typings';
import { isEditedMessage } from '@rocket.chat/core-typings';
import { Box, Bubble } from '@rocket.chat/fuselage';
import { useMergedRefs } from '@rocket.chat/fuselage-hooks';
import {
usePermission,
useRole,
Expand Down Expand Up @@ -57,8 +58,6 @@ import { useRestoreScrollPosition } from './hooks/useRestoreScrollPosition';
import { useRetentionPolicy } from './hooks/useRetentionPolicy';
import { useUnreadMessages } from './hooks/useUnreadMessages';

const BUBBLE_OFFSET = 8;

const RoomBody = (): ReactElement => {
const formatDate = useFormatDate();
const t = useTranslation();
Expand All @@ -70,7 +69,7 @@ const RoomBody = (): ReactElement => {
const subscription = useRoomSubscription();

const { list } = useDateListController();
const { listStyle, bubbleDate, onScroll: handleDateOnScroll, showBubble, style: bubbleDateStyle } = useDateScroll(BUBBLE_OFFSET);
const { callbackRef, listStyle, bubbleDate, showBubble, style: bubbleDateStyle } = useDateScroll();

const [lastMessageDate, setLastMessageDate] = useState<Date | undefined>();
const [hideLeaderHeader, setHideLeaderHeader] = useState(false);
Expand Down Expand Up @@ -390,14 +389,12 @@ const RoomBody = (): ReactElement => {

wrapper.addEventListener('scroll', updateUnreadCount);
wrapper.addEventListener('scroll', handleWrapperScroll);
wrapper.addEventListener('scroll', () => handleDateOnScroll(list));

return () => {
wrapper.removeEventListener('scroll', updateUnreadCount);
wrapper.removeEventListener('scroll', handleWrapperScroll);
wrapper.removeEventListener('scroll', () => handleDateOnScroll(list));
};
}, [_isAtBottom, handleDateOnScroll, list, room._id, setUnreadCount]);
}, [_isAtBottom, list, room._id, setUnreadCount]);

useEffect(() => {
const wrapper = wrapperRef.current;
Expand Down Expand Up @@ -549,6 +546,8 @@ const RoomBody = (): ReactElement => {

const { messageListRef, messageListProps } = useMessageListNavigation();

const ref = useMergedRefs(callbackRef, wrapperRef);

return (
<>
{!isLayoutEmbedded && room.announcement && <Announcement announcement={room.announcement} announcementDetails={undefined} />}
Expand All @@ -559,7 +558,7 @@ const RoomBody = (): ReactElement => {
onClick={hideFlexTab && handleCloseFlexTab}
>
<div className='messages-container-wrapper'>
<div className='messages-container-main' {...fileUploadTriggerProps}>
<div className='messages-container-main' ref={callbackRef} {...fileUploadTriggerProps}>
<DropTargetOverlay {...fileUploadOverlayProps} />
<div className={['container-bars', uploads.length && 'show'].filter(isTruthy).join(' ')}>
{uploads.map((upload) => (
Expand Down Expand Up @@ -623,7 +622,7 @@ const RoomBody = (): ReactElement => {
.join(' ')}
>
<MessageListErrorBoundary>
<CustomScrollbars ref={wrapperRef}>
<CustomScrollbars ref={ref}>
<ul
ref={messageListRef}
className='messages-list'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,16 @@ const ThreadChat = ({ mainMessage }: ThreadChatProps) => {
<ContextualbarContent flexShrink={1} flexGrow={1} paddingInline={0} {...fileUploadTriggerProps}>
<DateListProvider>
<DropTargetOverlay {...fileUploadOverlayProps} />
<Box is='section' display='flex' flexDirection='column' flexGrow={1} flexShrink={1} flexBasis='auto' height='full'>
<Box
is='section'
position='relative'
display='flex'
flexDirection='column'
flexGrow={1}
flexShrink={1}
flexBasis='auto'
height='full'
>
<MessageListErrorBoundary>
<ThreadMessageList mainMessage={mainMessage} />
</MessageListErrorBoundary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,11 @@ import { useDateScroll } from '../../../hooks/useDateScroll';
import { useFirstUnreadMessageId } from '../../../hooks/useFirstUnreadMessageId';
import { useMessageListNavigation } from '../../../hooks/useMessageListNavigation';
import { useScrollMessageList } from '../../../hooks/useScrollMessageList';
import { useDateListController } from '../../../providers/DateListProvider';
import { useLegacyThreadMessageJump } from '../hooks/useLegacyThreadMessageJump';
import { useLegacyThreadMessageListScrolling } from '../hooks/useLegacyThreadMessageListScrolling';
import { useLegacyThreadMessages } from '../hooks/useLegacyThreadMessages';
import { ThreadMessageItem } from './ThreadMessageItem';

const BUBBLE_OFFSET = 64;

const isMessageSequential = (current: IMessage, previous: IMessage | undefined, groupingRange: number): boolean => {
if (!previous) {
return false;
Expand Down Expand Up @@ -54,8 +51,7 @@ type ThreadMessageListProps = {

const ThreadMessageList = ({ mainMessage }: ThreadMessageListProps): ReactElement => {
const formatDate = useFormatDate();
const { list } = useDateListController();
const { listStyle, bubbleDate, onScroll: handleDateOnScroll, showBubble, style: bubbleDateStyle } = useDateScroll(BUBBLE_OFFSET);
const { callbackRef, listStyle, bubbleDate, showBubble, style: bubbleDateStyle } = useDateScroll();

const { messages, loading } = useLegacyThreadMessages(mainMessage._id);
const {
Expand All @@ -74,6 +70,8 @@ const ThreadMessageList = ({ mainMessage }: ThreadMessageListProps): ReactElemen
const { messageListRef, messageListProps } = useMessageListNavigation();
const listRef = useMergedRefs<HTMLElement | null>(listScrollRef, listJumpRef, messageListRef);

const scrollRef = useMergedRefs<HTMLElement | null>(callbackRef, listWrapperScrollRef);

return (
<div className={['thread-list js-scroll-thread', hideUsernames && 'hide-usernames'].filter(isTruthy).join(' ')}>
{bubbleDate && (
Expand All @@ -84,10 +82,9 @@ const ThreadMessageList = ({ mainMessage }: ThreadMessageListProps): ReactElemen
</Box>
)}
<CustomScrollbars
ref={listWrapperScrollRef}
ref={scrollRef}
onScroll={(args) => {
handleScroll(args);
handleDateOnScroll(list);
}}
style={{ scrollBehavior: 'smooth', overflowX: 'hidden' }}
>
Expand Down
73 changes: 44 additions & 29 deletions apps/meteor/client/views/room/hooks/useDateScroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,43 @@ import { useSafely } from '@rocket.chat/fuselage-hooks';
import { useCallback, useState } from 'react';

import { withThrottling } from '../../../../lib/utils/highOrderFunctions';
import { useDateListController } from '../providers/DateListProvider';

type useDateScrollReturn = {
bubbleDate: string | undefined;
onScroll: (list: Set<HTMLElement>) => void;
style: ReturnType<typeof css>;
callbackRef: (node: HTMLElement | null) => void;
style?: ReturnType<typeof css>;
showBubble: boolean;
listStyle?: ReturnType<typeof css>;
};

export const useDateScroll = (offset = 0): useDateScrollReturn => {
export const useDateScroll = (margin = 8): useDateScrollReturn => {
const [bubbleDate, setBubbleDate] = useSafely(
useState<{
date: string;
show: boolean;
style?: ReturnType<typeof css>;
}>({
date: '',
show: false,
style: undefined,
}),
);

const onScroll = useCallback(
withThrottling({ wait: 30 })(
(() => {
const { list } = useDateListController();

const callbackRef = useCallback(
(node: HTMLElement | null) => {
if (!node) {
return;
}
const onScroll = (() => {
let timeout: ReturnType<typeof setTimeout>;
return (elements: Set<HTMLElement>) => {
return (elements: Set<HTMLElement>, offset: number) => {
clearTimeout(timeout);

const bubbleOffset = offset + 56;
const bubbleOffset = offset;

// Gets the first non visible message date and sets the bubble date to it
const [date, message] = [...elements].reduce((ret, message) => {
// Sanitize elements
Expand All @@ -49,16 +58,30 @@ export const useDateScroll = (offset = 0): useDateScrollReturn => {
}, [] as [string, HTMLElement] | []);

// We always keep the previous date if we don't have a new one, so when the bubble disappears it doesn't flicker

setBubbleDate(() => ({
date: '',
...(date && { date }),
show: Boolean(date),
style: css`
position: absolute;
top: ${margin}px;
left: 50%;
translate: -50%;
z-index: 1;

opacity: 0;
transition: opacity 0.6s;

&.bubble-visible {
opacity: 1;
}
`,
}));

if (message) {
const { top } = message.getBoundingClientRect();

if (top - offset > 0) {
if (top < offset && top > 0) {
return;
}
}
Expand All @@ -72,34 +95,26 @@ export const useDateScroll = (offset = 0): useDateScrollReturn => {
1000,
);
};
})(),
),
[offset],
})();
const fn = withThrottling({ wait: 30 })(() => {
const offset = node.getBoundingClientRect().top;
onScroll(list, offset);
});

node.addEventListener('scroll', fn, { passive: true });
},
[list, margin, setBubbleDate],
);

const dateBubbleStyle = css`
position: absolute;
top: ${offset}px;
left: 50%;
translate: -50%;
z-index: 1;

opacity: 0;
transition: opacity 0.6s;

&.bubble-visible {
opacity: 1;
}
`;

const listStyle =
bubbleDate.show && bubbleDate.date
? css`
position: relative;
& [data-time='${bubbleDate.date.replaceAll(/[-T:.]/g, '').substring(0, 8)}'] {
opacity: 0;
}
`
: undefined;

return { listStyle, bubbleDate: bubbleDate.date, onScroll, style: dateBubbleStyle, showBubble: Boolean(bubbleDate.show) };
return { callbackRef, listStyle, bubbleDate: bubbleDate.date, style: bubbleDate.style, showBubble: Boolean(bubbleDate.show) };
};
Loading