Skip to content

Commit

Permalink
feat: update UI (#39)
Browse files Browse the repository at this point in the history
* feat: add loading spinner

* feat: update log color
  • Loading branch information
rpidanny committed May 14, 2023
1 parent 040195c commit 29e8437
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 53 deletions.
21 changes: 12 additions & 9 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import { Layout, message } from 'antd';
import { Layout, message, Typography } from 'antd';
import React, { useEffect, useState } from 'react';

import axios from './axios';
import ChatRoom from './components/ChatRoom/index';

const { Header, Content } = Layout;
const { Title, Text } = Typography;

interface IMessage {
text: string;
sender: string;
timestamp: string;
date: string;
}

interface IHistory {
message: string;
sender: string;
timestamp: string;
date: string;
}

interface IInitResponse {
Expand All @@ -36,10 +37,10 @@ function App() {
const { data } = await axios.get<IInitResponse>('/api/init');
const { history, collection } = data;
setMessages(
history.map(({ message, sender, timestamp }) => ({
history.map(({ message, sender, date }) => ({
text: message,
sender,
timestamp,
date,
}))
);
setCollection(collection);
Expand All @@ -50,12 +51,14 @@ function App() {
}

return (
<Layout style={{ height: '100vh' }}>
<Header style={{ color: 'white' }}>Shelly ({collection})</Header>
<Layout style={{ height: '100vh', background: 'white' }}>
<Header>
<Title level={3} style={{ color: 'white' }}>
Shelly ({collection})
</Title>
</Header>
<Content
style={{
padding: '10px',
width: '80%',
marginLeft: 'auto',
marginRight: 'auto',
}}
Expand Down
96 changes: 60 additions & 36 deletions client/src/components/ChatRoom/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './styles.css';

import { SendOutlined, UserOutlined } from '@ant-design/icons';
import { Avatar, Input, List, message } from 'antd';
import { Avatar, Input, List, message, Spin, Typography } from 'antd';
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
import ReactMarkdown from 'react-markdown';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
Expand All @@ -10,22 +10,27 @@ import { dark } from 'react-syntax-highlighter/dist/esm/styles/prism';
import sheldon from '../../assets/sheldon_mid.png';
import axios from '../../axios';

const { Text } = Typography;
interface IMessage {
text: string;
sender: string;
timestamp: string;
date: string;
}

interface IChatRoomProps {
history: IMessage[];
}

function ChatRoom({ history }: IChatRoomProps) {
function ChatRoom({ history }: IChatRoomProps): JSX.Element {
const [loading, setLoading] = useState(false);
const [messages, setMessages] = useState<IMessage[]>(history);
const [newMessage, setNewMessage] = useState<string>('');
const chatRoomRef = useRef<HTMLDivElement>(null);
const messageInputRef = useRef<HTMLTextAreaElement>(null);

// const { setLoading } = useContext<ILoadingContextType>(LoadingContext);
console.log('History: ', history);

useEffect(() => {
setMessages(history);
}, [history]);
Expand All @@ -40,30 +45,37 @@ function ChatRoom({ history }: IChatRoomProps) {
setNewMessage(event.target.value);
}

function handleSendMessage() {
async function handleSendMessage() {
if (newMessage.trim() !== '') {
setLoading(true);
const newMessages = [
...messages,
{
text: newMessage,
sender: 'user',
timestamp: new Date().toISOString(),
date: new Date().toUTCString(),
},
];
setMessages(newMessages);
setNewMessage('');

// await new Promise((resolve) => setTimeout(resolve, 5000));
// setLoading(false);

axios
.post('/api/chat', { message: newMessage })
.then((response) => {
if (response.status === 200) {
const { text, sender, timestamp } = response.data;
setMessages([...messages, { text, sender, timestamp }]);
const { text, sender, date } = response.data;
setMessages([...newMessages, { text, sender, date }]);
}
})
.catch((error) => {
console.error(error);
message.error('Failed to send message');
})
.finally(() => {
setLoading(false);
});
}
}
Expand All @@ -75,9 +87,12 @@ function ChatRoom({ history }: IChatRoomProps) {
}
}

function renderItem({ text, sender }: IMessage) {
function renderItem({ text, sender, date }: IMessage): JSX.Element {
return (
<List.Item className="message-bubble">
<List.Item
className="message-bubble"
// style={{ backgroundColor: sender === 'user' ? '#eeeeee' : 'white' }}
>
<List.Item.Meta
avatar={
sender === 'user' ? (
Expand All @@ -86,33 +101,37 @@ function ChatRoom({ history }: IChatRoomProps) {
<Avatar src={sheldon} />
)
}
description={
<ReactMarkdown
components={{
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<SyntaxHighlighter
{...props}
// children={String(children).replace(/\n$/, '')}
style={dark}
language={match[1]}
PreTag="div"
>
{String(children)}
</SyntaxHighlighter>
) : (
<code {...props} className={className}>
{children}
</code>
);
},
}}
>
{text}
</ReactMarkdown>
}
description={date}
/>
<ReactMarkdown
className="markdown"
components={{
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<SyntaxHighlighter
{...props}
// children={String(children).replace(/\n$/, '')}
style={dark}
language={match[1]}
PreTag="div"
>
{String(children)}
</SyntaxHighlighter>
) : (
<code
{...props}
className={className}
style={{ textAlign: 'left' }}
>
{children}
</code>
);
},
}}
>
{text}
</ReactMarkdown>
</List.Item>
);
}
Expand All @@ -121,11 +140,16 @@ function ChatRoom({ history }: IChatRoomProps) {
<div className="chat-room">
<div className="chat-messages" ref={chatRoomRef}>
<List
itemLayout="horizontal"
itemLayout="vertical"
dataSource={messages}
style={{ padding: '10px', color: 'black' }}
renderItem={renderItem}
/>
{loading && (
<div className="loading-chat">
<Spin size="large" />
</div>
)}
</div>
<div className="chat-input">
<Input.TextArea
Expand Down
13 changes: 10 additions & 3 deletions client/src/components/ChatRoom/styles.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.chat-room {
height: 100%;
display: flex;
max-width: 70rem;
flex-direction: column;
justify-content: space-between;
/* align-items: center; */
Expand All @@ -11,7 +12,7 @@
margin-right: auto; */
flex: 1;
overflow-y: auto;
padding: 10px;
/* padding: 10px; */
/* max-width: 708rem; */
}

Expand All @@ -20,15 +21,17 @@
/* border-radius: 10px; */
/* border: 1px solid #ccc; */
/* background-color: #f0f0f0; */
margin-bottom: 10px;
/* margin-bottom: 10px; */
padding: 10px;
/* white-space: pre-wrap;
word-break: break-word; */
}

.chat-input {
display: flex;
align-items: center;
margin-top: 10px;
margin-top: 20px;
margin-bottom: 30px;
}

.send-icon {
Expand All @@ -37,3 +40,7 @@
cursor: pointer;
margin-left: 10px;
}

.loading-chat {
text-align: center;
}
15 changes: 10 additions & 5 deletions src/services/web/web.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import bodyParser from 'body-parser';
import chalk from 'chalk';
import cors from 'cors';
import express, { Express, Request, Response } from 'express';
import { Server } from 'http';
Expand All @@ -23,7 +24,9 @@ export class WebService {
this.setupRoutes(collection);

this.server = this.app.listen(port, () => {
this.logger.log(`Server started on http://localhost:${port}`);
this.logger.log(
`Server started on ${chalk.green(`http://localhost:${port}`)}`
);
});
}

Expand All @@ -36,7 +39,9 @@ export class WebService {
this.app.use(cors());
this.app.use(express.static(path.resolve('client', 'build')));
this.app.use((req: Request, res: any, next: () => void) => {
this.logger.log(`Incoming request ${req.method} ${req.url}`);
this.logger.log(
`Incoming request ${chalk.bold(req.method)} ${chalk.bold(req.url)}`
);
next();
});
}
Expand All @@ -49,7 +54,7 @@ export class WebService {
message,
sender: Sender.User,
collection,
date: new Date().toISOString(),
date: new Date().toUTCString(),
});

const answer = await this.dependencies.askService.askAboutCollection(
Expand All @@ -61,13 +66,13 @@ export class WebService {
message: answer,
sender: Sender.Shelly,
collection,
date: new Date().toISOString(),
date: new Date().toUTCString(),
});

res.json({
text: answer,
sender: Sender.Shelly,
date: new Date().toISOString(),
date: new Date().toUTCString(),
});
});

Expand Down

0 comments on commit 29e8437

Please sign in to comment.