From 455345efd14b63b10d34fa4fc5d166a2191c1294 Mon Sep 17 00:00:00 2001 From: Varsha Menon <46579265+varshamenon4@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:44:31 -0500 Subject: [PATCH] feat: add message divider between old and new messages (#67) --- src/components/ChatBox/index.jsx | 21 +++- src/components/ChatBox/index.test.jsx | 102 ++++++++++++++++++ .../MessageDivider/MessageDivider.scss | 20 ++++ src/components/MessageDivider/index.jsx | 15 +++ 4 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 src/components/ChatBox/index.test.jsx create mode 100644 src/components/MessageDivider/MessageDivider.scss create mode 100644 src/components/MessageDivider/index.jsx diff --git a/src/components/ChatBox/index.jsx b/src/components/ChatBox/index.jsx index 69c434c1..df2eec73 100644 --- a/src/components/ChatBox/index.jsx +++ b/src/components/ChatBox/index.jsx @@ -3,15 +3,32 @@ import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import Message from '../Message'; import './ChatBox.scss'; +import MessageDivider from '../MessageDivider'; + +function isToday(date) { + const today = new Date(); + return ( + date.getDate() === today.getDate() + && date.getMonth() === today.getMonth() + && date.getFullYear() === today.getFullYear() + ); +} // container for all of the messages const ChatBox = ({ chatboxContainerRef }) => { const { messageList, apiIsLoading } = useSelector(state => state.learningAssistant); + const messagesBeforeToday = messageList.filter((m) => (!isToday(new Date(m.timestamp)))); + const messagesToday = messageList.filter((m) => (isToday(new Date(m.timestamp)))); + // message divider should not display if no messages or if all messages sent today. return (
- {messageList.map(({ role, content, timestamp }) => ( - + {messagesBeforeToday.map(({ role, content, timestamp }) => ( + + ))} + {(messageList.length !== 0 && messagesBeforeToday.length !== 0) && ()} + {messagesToday.map(({ role, content, timestamp }) => ( + ))} {apiIsLoading && (
Xpert is thinking
diff --git a/src/components/ChatBox/index.test.jsx b/src/components/ChatBox/index.test.jsx new file mode 100644 index 00000000..889ac6de --- /dev/null +++ b/src/components/ChatBox/index.test.jsx @@ -0,0 +1,102 @@ +import React from 'react'; +import { screen, act } from '@testing-library/react'; + +import { render as renderComponent } from '../../utils/utils.test'; +import { initialState } from '../../data/slice'; + +import ChatBox from '.'; + +const mockDispatch = jest.fn(); +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useDispatch: () => mockDispatch, +})); + +const defaultProps = { + chatboxContainerRef: jest.fn(), +}; + +const render = async (props = {}, sliceState = {}) => { + const componentProps = { + ...defaultProps, + ...props, + }; + + const initState = { + preloadedState: { + learningAssistant: { + ...initialState, + ...sliceState, + }, + }, + }; + return act(async () => renderComponent( + , + initState, + )); +}; + +describe('', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + it('message divider does not appear when no messages', () => { + const messageList = []; + const sliceState = { + messageList, + }; + render(undefined, sliceState); + + expect(screen.queryByText('Today')).not.toBeInTheDocument(); + }); + + it('message divider does not appear when all messages from today', () => { + const date = new Date(); + const messageList = [ + { role: 'user', content: 'hi', timestamp: date - 60 }, + { role: 'user', content: 'hello', timestamp: date }, + ]; + const sliceState = { + messageList, + }; + render(undefined, sliceState); + + expect(screen.queryByText('hi')).toBeInTheDocument(); + expect(screen.queryByText('hello')).toBeInTheDocument(); + expect(screen.queryByText('Today')).not.toBeInTheDocument(); + }); + + it('message divider shows when all messages from before today', () => { + const date = new Date(); + const messageList = [ + { role: 'user', content: 'hi', timestamp: date.setDate(date.getDate() - 1) }, + { role: 'user', content: 'hello', timestamp: date + 1 }, + ]; + const sliceState = { + messageList, + }; + render(undefined, sliceState); + + expect(screen.queryByText('hi')).toBeInTheDocument(); + expect(screen.queryByText('hello')).toBeInTheDocument(); + expect(screen.queryByText('Today')).toBeInTheDocument(); + }); + + it('correctly divides old and new messages', () => { + const today = new Date(); + const messageList = [ + { role: 'user', content: 'Today yesterday', timestamp: today.setDate(today.getDate() - 1) }, + { role: 'user', content: 'Today today', timestamp: +Date.now() }, + ]; + const sliceState = { + messageList, + }; + render(undefined, sliceState); + + const results = screen.getAllByText('Today', { exact: false }); + expect(results.length).toBe(3); + expect(results[0]).toHaveTextContent('Today yesterday'); + expect(results[1]).toHaveTextContent('Today'); + expect(results[2]).toHaveTextContent('Today today'); + }); +}); diff --git a/src/components/MessageDivider/MessageDivider.scss b/src/components/MessageDivider/MessageDivider.scss new file mode 100644 index 00000000..bb3ee7a0 --- /dev/null +++ b/src/components/MessageDivider/MessageDivider.scss @@ -0,0 +1,20 @@ +@use '../../utils/variables'; + +.message-divider { + display: flex; + font-size: 15px; +} +.message-divider:before, .message-divider:after{ + content: ""; + flex: 1 1; + border-bottom: 1px solid; + margin: auto; +} +.message-divider:before { + margin-right: 10px; + margin-left: 10px; +} +.message-divider:after { + margin-right: 10px; + margin-left: 10px; +} diff --git a/src/components/MessageDivider/index.jsx b/src/components/MessageDivider/index.jsx new file mode 100644 index 00000000..dc783d8d --- /dev/null +++ b/src/components/MessageDivider/index.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import './MessageDivider.scss'; +import PropTypes from 'prop-types'; + +const MessageDivider = ({ text }) => ( +
+ {text} +
+); + +MessageDivider.propTypes = { + text: PropTypes.string.isRequired, +}; + +export default MessageDivider;