Skip to content

Commit

Permalink
feat: add message divider between old and new messages (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
varshamenon4 authored Nov 22, 2024
1 parent 55e4b80 commit 455345e
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 2 deletions.
21 changes: 19 additions & 2 deletions src/components/ChatBox/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div ref={chatboxContainerRef} className="flex-grow-1 scroller d-flex flex-column pb-4">
{messageList.map(({ role, content, timestamp }) => (
<Message key={timestamp.toString()} variant={role} message={content} />
{messagesBeforeToday.map(({ role, content, timestamp }) => (
<Message key={timestamp} variant={role} message={content} />
))}
{(messageList.length !== 0 && messagesBeforeToday.length !== 0) && (<MessageDivider text="Today" />)}
{messagesToday.map(({ role, content, timestamp }) => (
<Message key={timestamp} variant={role} message={content} />
))}
{apiIsLoading && (
<div className="loading">Xpert is thinking</div>
Expand Down
102 changes: 102 additions & 0 deletions src/components/ChatBox/index.test.jsx
Original file line number Diff line number Diff line change
@@ -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(
<ChatBox {...componentProps} />,
initState,
));
};

describe('<ChatBox />', () => {
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');
});
});
20 changes: 20 additions & 0 deletions src/components/MessageDivider/MessageDivider.scss
Original file line number Diff line number Diff line change
@@ -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;
}
15 changes: 15 additions & 0 deletions src/components/MessageDivider/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import './MessageDivider.scss';
import PropTypes from 'prop-types';

const MessageDivider = ({ text }) => (
<div className="message-divider">
{text}
</div>
);

MessageDivider.propTypes = {
text: PropTypes.string.isRequired,
};

export default MessageDivider;

0 comments on commit 455345e

Please sign in to comment.