-
Notifications
You must be signed in to change notification settings - Fork 1
/
MainChat.tsx
100 lines (90 loc) · 2.88 KB
/
MainChat.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { useContext, useEffect } from 'react';
import { Socket } from 'socket.io-client';
import { ChatContext } from '../context/ChatContext.tsx';
import { Action, MessageContext } from '../context/MessageContext.tsx';
import { useWebsocket } from '../hooks/useWebsocket.ts';
import AppInfo from './AppInfo.tsx';
import Messages from './ChatMessages.tsx';
import ErrorMessage from './ErrorMessage.tsx';
import SearchInput from './SearchInput.tsx';
import Spinner from './Spinner.tsx';
import loadHistory from '../lib/history.ts';
import { debounce } from 'lodash';
import ClearDialog from './ClearDialog.tsx';
import SuggestedResponsePanel from './SuggestedResponsePanel.tsx';
export function scrollToBottom(scrollBehavior: string = 'auto') {
const chatContainer = document.querySelector('.chat-container');
if (!!chatContainer) {
(chatContainer as HTMLElement).style.scrollBehavior = scrollBehavior;
chatContainer.scrollTop = chatContainer.scrollHeight;
}
}
export function handleMessageDispatch(
dispatch: React.Dispatch<Action>,
text: string,
streaming: boolean,
) {
dispatch({
type: 'request',
message: { text, isUser: true, timestamp: new Date() },
});
if (streaming) {
dispatch({
type: 'startStreaming',
message: { text: '', isUser: false, timestamp: new Date() },
});
}
}
export default function MainChat() {
const { websocketUrl, setIsConnected, streaming, historySize } =
useContext(ChatContext);
const { state, dispatch } = useContext(MessageContext);
const { data, isLoading, error, connected } = state;
const socket: React.MutableRefObject<Socket | null> = useWebsocket({
websocketUrl,
dispatch,
});
const debouncedScrollToBottom = debounce(scrollToBottom, 500);
useEffect(() => {
const messages = loadHistory(historySize);
dispatch({ type: 'bulkLoad', messages });
}, []);
useEffect(() => {
debouncedScrollToBottom();
}, [data]);
useEffect(() => {
if (!!setIsConnected) {
setIsConnected(connected);
}
}, [connected]);
// Hide the question prompt when the user has typed something and streaming is enabled.
const handleHeader = streaming && !isLoading;
return (
<>
<AppInfo
dispatch={dispatch}
connected={connected}
socket={socket}
expandAppInfo={handleHeader}
/>
<ClearDialog />
{!!error && (
<ErrorMessage
message={error}
clearFunc={() => dispatch({ type: 'clearFailure' })}
/>
)}
<div className="overflow-auto chat-container grow bg-[#E6F3FB]">
<Messages />
{isLoading && <Spinner />}
</div>
{data && data.length > 0 && data[data.length - 1].suggestedResponses && (
<SuggestedResponsePanel
possibleResponses={data[data.length - 1].suggestedResponses ?? []}
/>
)}
{/* Search input */}
<SearchInput />
</>
);
}