From c1cef7445afc5b60095b54c48d55047ce995600f Mon Sep 17 00:00:00 2001 From: khizarshah01 Date: Tue, 27 Jan 2026 00:07:51 +0530 Subject: [PATCH 1/2] feat: display a floating date indicator in the chat body when scrolling. --- packages/react/src/views/ChatBody/ChatBody.js | 60 ++++++++++++++++--- .../src/views/ChatBody/ChatBody.styles.js | 18 ++++++ 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js index 34f5c8bf40..c4fc748bc2 100644 --- a/packages/react/src/views/ChatBody/ChatBody.js +++ b/packages/react/src/views/ChatBody/ChatBody.js @@ -6,6 +6,7 @@ import React, { useState, useRef, } from 'react'; +import { format } from 'date-fns'; import PropTypes from 'prop-types'; import { css } from '@emotion/react'; import { @@ -206,14 +207,48 @@ const ChatBody = ({ setPopupVisible(false); }; + const [floatingDate, setFloatingDate] = useState(null); + const floatingDateTimerRef = useRef(null); + const handleScroll = useCallback(async () => { if (messageListRef && messageListRef.current) { setScrollPosition(messageListRef.current.scrollTop); setIsUserScrolledUp( messageListRef.current.scrollTop + messageListRef.current.clientHeight < - messageListRef.current.scrollHeight + messageListRef.current.scrollHeight ); + // floating date logic + const list = messageListRef.current; + const listRect = list.getBoundingClientRect(); + const x = listRect.left + listRect.width / 2; + // sampling point: slightly down from the top padding to catch the first visible message + const y = listRect.top + 10; + + const topElement = document.elementFromPoint(x, y); + + // attempt to find closest message container if we hit a child element + const messageElement = topElement?.closest('.ec-message'); + + if (messageElement) { + const bodyElement = messageElement.querySelector('.ec-message-body'); + if (bodyElement && bodyElement.id) { + const id = bodyElement.id.replace('ec-message-body-', ''); + const msg = messages.find((m) => m._id === id); + if (msg) { + const dateStr = format(new Date(msg.ts), 'MMMM d, yyyy'); + setFloatingDate(dateStr); + + if (floatingDateTimerRef.current) { + clearTimeout(floatingDateTimerRef.current); + } + floatingDateTimerRef.current = setTimeout(() => { + setFloatingDate(null); + }, 1000); + } + } + } + if ( messageListRef.current.scrollTop === 0 && !loadingOlderMessages && @@ -226,13 +261,13 @@ const ChatBody = ({ anonymousMode, ECOptions?.enableThreads ? { - query: { - tmid: { - $exists: false, - }, + query: { + tmid: { + $exists: false, }, - offset, - } + }, + offset, + } : undefined, anonymousMode ? false : isChannelPrivate ); @@ -287,6 +322,7 @@ const ChatBody = ({ setPopupVisible, setOtherUserMessage, firstUnreadMessageId, + messages ]); const showNewMessagesPopup = () => { @@ -302,7 +338,7 @@ const ChatBody = ({ if (announcementRef.current) { setIsOverflowing( announcementRef.current.scrollWidth > - announcementRef.current.clientWidth + announcementRef.current.clientWidth ); } }; @@ -393,6 +429,14 @@ const ChatBody = ({ )} + {floatingDate && ( + + {floatingDate} + + )} { text-overflow: ellipsis; white-space: nowrap; `, + + dateIndicatorStyles: css` + position: absolute; + top: 30px; + left: 50%; + transform: translateX(-50%); + z-index: 1050; + padding: 1px 8px; + border-radius: 2px; + font-size: 0.75rem; + font-weight: 600; + background-color: ${theme.colors.secondary}; + color: ${theme.colors.primary}; + box-shadow: ${theme.shadows[1]}; + opacity: 0.9; + pointer-events: none; + transition: opacity 0.3s ease-in-out; + `, }; return styles; From 239a2634b99164148af93f589b3fbac220c8903c Mon Sep 17 00:00:00 2001 From: khizarshah01 Date: Tue, 27 Jan 2026 01:06:38 +0530 Subject: [PATCH 2/2] fix lint issues --- packages/react/src/views/ChatBody/ChatBody.js | 23 ++++++++----------- .../src/views/ChatBody/ChatBody.styles.js | 4 ++-- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js index c4fc748bc2..66826ba143 100644 --- a/packages/react/src/views/ChatBody/ChatBody.js +++ b/packages/react/src/views/ChatBody/ChatBody.js @@ -215,7 +215,7 @@ const ChatBody = ({ setScrollPosition(messageListRef.current.scrollTop); setIsUserScrolledUp( messageListRef.current.scrollTop + messageListRef.current.clientHeight < - messageListRef.current.scrollHeight + messageListRef.current.scrollHeight ); // floating date logic @@ -261,13 +261,13 @@ const ChatBody = ({ anonymousMode, ECOptions?.enableThreads ? { - query: { - tmid: { - $exists: false, + query: { + tmid: { + $exists: false, + }, }, - }, - offset, - } + offset, + } : undefined, anonymousMode ? false : isChannelPrivate ); @@ -322,7 +322,7 @@ const ChatBody = ({ setPopupVisible, setOtherUserMessage, firstUnreadMessageId, - messages + messages, ]); const showNewMessagesPopup = () => { @@ -338,7 +338,7 @@ const ChatBody = ({ if (announcementRef.current) { setIsOverflowing( announcementRef.current.scrollWidth > - announcementRef.current.clientWidth + announcementRef.current.clientWidth ); } }; @@ -430,10 +430,7 @@ const ChatBody = ({ )} {floatingDate && ( - + {floatingDate} )} diff --git a/packages/react/src/views/ChatBody/ChatBody.styles.js b/packages/react/src/views/ChatBody/ChatBody.styles.js index 02bcb47227..ab510b3604 100644 --- a/packages/react/src/views/ChatBody/ChatBody.styles.js +++ b/packages/react/src/views/ChatBody/ChatBody.styles.js @@ -35,10 +35,10 @@ export const getChatbodyStyles = (theme, mode) => { dateIndicatorStyles: css` position: absolute; - top: 30px; + top: 30px; left: 50%; transform: translateX(-50%); - z-index: 1050; + z-index: 1050; padding: 1px 8px; border-radius: 2px; font-size: 0.75rem;