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

Fix Xpert styling issues, fix lingering bugs, and make improvements. #8

Merged
merged 3 commits into from
Aug 21, 2023
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
38 changes: 0 additions & 38 deletions src/components/ChatBox/ChatBox.css

This file was deleted.

36 changes: 36 additions & 0 deletions src/components/ChatBox/ChatBox.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.scroller {
overflow-y: scroll;
scrollbar-color: rebeccapurple green;
scrollbar-width: thin;
width: 100%;
opacity: 1;
margin-right: 0;

&:after {
content: ""; /* Add an empty content area after the chat messages */
display: block;
height: 0;
clear: both;
}
}

.loading {
font-size: 13px;
padding-left: 10px;

&:after {
overflow: hidden;
display: inline-block;
vertical-align: bottom;
-webkit-animation: ellipsis steps(4,end) 900ms infinite;
animation: ellipsis steps(4,end) 900ms infinite;
content: "\2026"; /* ascii code for the ellipsis character */
width: 0px;
}
}

@keyframes ellipsis {
to {
width: 1.25em;
}
}
31 changes: 11 additions & 20 deletions src/components/ChatBox/index.jsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,30 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import Message from '../Message';
import './ChatBox.css';
import './ChatBox.scss';

// container for all of the messages
const ChatBox = ({ messageList, chatboxContainerRef }) => {
const [isResponseLoading, setResponseLoading] = useState(false);

useEffect(() => {
if (messageList[messageList.length - 1]?.role === 'user') {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved the API loading state into Redux. Before, it was part of the Chatbox component state. We were deriving the loading state from state in the Redux store that was being modified by a few different action creators, which meant that the "Xpert is thinking..." message wasn't showing properly.

Moving this state into the Redux store fixes the display of the "Xpert is thinking..." message, makes it easier to define and set this value, and makes it available to other components in the tree that may need it later (e.g. disabling the button during loading).

setResponseLoading(true);
} else {
setResponseLoading(false);
}
}, [messageList]);
const ChatBox = ({ chatboxContainerRef }) => {
const { messageList, apiIsLoading } = useSelector(state => state.learningAssistant);

return (
<div ref={chatboxContainerRef} className="scroller container d-flex justify-content-center">
<div ref={chatboxContainerRef} className="scroller d-flex flex-column">
{messageList.map(({ role, content, timestamp }) => (
<Message key={timestamp.toString()} variant={role} message={content} timestamp={timestamp} />
))}
{isResponseLoading && (
{apiIsLoading && (
<div className="loading">Xpert is thinking</div>
)}
</div>
);
};

ChatBox.propTypes = {
messageList: PropTypes.arrayOf(PropTypes.shape({
role: PropTypes.string.isRequired,
content: PropTypes.string.isRequired,
timestamp: PropTypes.instanceOf(Date).isRequired,
})).isRequired,
chatboxContainerRef: PropTypes.string.isRequired,
chatboxContainerRef: PropTypes.oneOfType([
PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
]).isRequired,
};

export default ChatBox;
25 changes: 0 additions & 25 deletions src/components/Message/Message.css

This file was deleted.

19 changes: 19 additions & 0 deletions src/components/Message/Message.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.message {
width: fit-content;
max-width: 70%;
border-radius: 10px;
font-size: 15px;

&.user {
background:#EBEBEB;
}

&.assistant {
background:#0A3055;
color: white;
}
}

.time {
font-size: 10px;
}
14 changes: 10 additions & 4 deletions src/components/Message/index.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import React from 'react';
import './Message.css';
import './Message.scss';
import PropTypes from 'prop-types';

const Message = ({ variant, message, timestamp }) => {
if (!timestamp) {
return null;
}

const parsedTimestamp = new Date(Date.parse(timestamp));

return (
<div className={`msg ${variant}`} data-hj-suppress>
<div
className={`message ${variant} ${variant === 'user' ? 'align-self-end' : ''} text-left my-1 mx-2 py-1 px-2`}
data-hj-suppress
>
{message}
<div className="time">{`${timestamp?.getHours()}:${timestamp?.getMinutes()}:${timestamp?.getSeconds()}`}</div>
<div className="time text-right pl-2">{`${parsedTimestamp?.getHours()}:${parsedTimestamp?.getMinutes()}:${parsedTimestamp?.getSeconds()}`}</div>
</div>
);
};

Message.propTypes = {
variant: PropTypes.string.isRequired,
message: PropTypes.string.isRequired,
timestamp: PropTypes.instanceOf(Date).isRequired,
timestamp: PropTypes.string.isRequired,
};

export default Message;
33 changes: 0 additions & 33 deletions src/components/Sidebar/Sidebar.css

This file was deleted.

81 changes: 81 additions & 0 deletions src/components/Sidebar/Sidebar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
.sidebar {
height: 100vh;
/* Set the height of the chat container */
overflow-y: scroll;
/* Enable vertical scrolling */
scroll-behavior: smooth;
/* Add smooth scrolling behavior */
top: 0;
bottom: 0;
border-left-width: 1px;
border-color: #9CA3AF;
background-color: #F9FAFB;

&.open {
width: 30%;
right: 0;
}

h1 {
font-size: 1.25rem;
line-height: 1.75rem;
}

button.close {
/* Override default opacity:0.5 for buttons */
opacity: 1;
height: fit-content;
top: 0;
right: 0;
background: none;

svg {
width: 1.5rem;
height: 1.5rem;
fill: #6B7280;
}

svg:hover {
fill: #4B5563;
}
}

button.clear {
/* Bootstrap doesn't have any 0.75*$spacer utility classes. */
padding-left: 0.75rem;
padding-right: 0.75rem;
border-radius: 9999px;
border-style: solid;
background-color: #DBEAFE;
color: #1E3A8A;
}

form {
input {
border-width: 1px;
border-color: #D1D5DB;
border-radius: 0.375rem;
border-style: solid;

&:hover {
outline-style: none;
border-color: #3B82F6;
}
}

button {
color: #1E3A8A;
background: none;
}
}
}

.separator {
z-index: 100;
width: 100%;
height: 10px;
padding: 10px;
background: -webkit-linear-gradient(270deg, rgba(0, 0, 0, 0.35), transparent);
background: linear-gradient(180deg, rgba(0, 0, 0, 0.35), transparent);
opacity: 0.2;
}
Loading
Loading