Skip to content

Commit ab5c20c

Browse files
committed
Automatically scroll to start of latest message
1 parent 613f322 commit ab5c20c

File tree

3 files changed

+43
-27
lines changed

3 files changed

+43
-27
lines changed

client/components/ChatBot/GeneralChatbot.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,17 @@ const GeneralReadingChatBot = () => {
1919
const [currentMessage, setCurrentMessage] = useState("");
2020

2121
const { messages, isWaitingForResponse, isLoadingHistory, isOpen } = useSelector(({ chatbot }) => chatbot);
22-
const messagesEndRef = useRef(null)
22+
const latestMessageRef = useRef(null)
2323

2424
// Fetch conversation history when chatbot starts
2525
useEffect(() => {
2626
dispatch(getGeneralAgentConversationHistory());
2727
}, []);
2828

29-
const scrollToBottom = () => {
30-
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
31-
}
29+
const scrollToLatestMessage = () => latestMessageRef.current?.scrollIntoView({ behavior: 'smooth' })
3230

3331
useEffect(() => {
34-
scrollToBottom()
32+
scrollToLatestMessage()
3533
}, [messages])
3634

3735
// Add a static "init" message from the bot if there are no messages yet
@@ -85,7 +83,7 @@ const GeneralReadingChatBot = () => {
8583

8684
{/* Display other messages */}
8785
{messages.map((message, index) => (
88-
<div key={index} className={`message message-${message.type}`} style={{display: 'block'}}>
86+
<div ref={index === messages.length - 1 ? latestMessageRef : null} key={index} className={`message message-${message.type}`} style={{display: 'block'}}>
8987
{message.text ? <ReactMarkdown children={message.text} /> : <FormattedMessage id="Error rendering message" />}
9088
</div>
9189
))}
@@ -94,7 +92,6 @@ const GeneralReadingChatBot = () => {
9492
<Spinner animation="border" variant="info" />
9593
</div>
9694
)}
97-
<div ref={messagesEndRef} />
9895
</>
9996
)}
10097
</div>
@@ -108,11 +105,6 @@ const GeneralReadingChatBot = () => {
108105
onChange={(e) => setCurrentMessage(e.target.value)}
109106
/>
110107
<Button type="submit" primary disabled={isWaitingForResponse}>
111-
{/* isWaitingForResponse ? (
112-
<Spinner animation="border" variant="warning" />
113-
) : (
114-
<FormattedMessage id="submit-chat-message" defaultMessage="Send" />
115-
)*/}
116108
<FormattedMessage id="submit-chat-message" defaultMessage="Send" />
117109
</Button>
118110
<ChatbotSuggestions isWaitingForResponse={isWaitingForResponse} />

client/components/ChatBot/PracticeChatbot.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, { useState, useEffect, useRef } from 'react';
22
import { useSelector, useDispatch } from 'react-redux'
33
import { useParams } from 'react-router-dom'
44
import { Spinner } from 'react-bootstrap'
@@ -63,6 +63,7 @@ const PracticeChatbot = () => {
6363
const [isCollapsed, setIsCollapsed] = useState(false);
6464
const [validToChat, setValidToChat] = useState(false);
6565

66+
const latestMessageRef = useRef(null)
6667

6768
const handleMessageSubmit = (event) => {
6869
event.preventDefault();
@@ -86,6 +87,12 @@ const PracticeChatbot = () => {
8687

8788
const toggleCollapse = () => setIsCollapsed(!isCollapsed);
8889

90+
const scrollToLatestMessage = () => latestMessageRef.current?.scrollIntoView({ behavior: 'smooth' })
91+
92+
useEffect(() => {
93+
scrollToLatestMessage()
94+
}, [messages])
95+
8996
useEffect(() => {
9097
if(Object.keys(currentWord).length && !listen && !speak) {
9198
let totalRequestedHints = []
@@ -258,7 +265,7 @@ const PracticeChatbot = () => {
258265
<>
259266
{/********this is for CHATTING: MESSAGE-USER + MESSAGE-BOT ********/}
260267
{/******** MESSAGE-USER + MESSAGE-BOT: no other types ********/}
261-
<div key={index} className={`message message-${message.type}`} style={{display: 'block'}}>
268+
<div ref={index === messages.length - 1 ? latestMessageRef : null} key={index} className={`message message-${message.type}`} style={{display: 'block'}}>
262269
{message.text ? (
263270
<ReactMarkdown children={message.text} />
264271
) : (
@@ -297,6 +304,11 @@ const PracticeChatbot = () => {
297304
)}
298305
</>
299306
))}
307+
{isWaitingForResponse && (
308+
<div style={{ display: 'flex', justifyContent: 'center', margin: '20px 0 10px' }}>
309+
<Spinner animation="border" variant="info" />
310+
</div>
311+
)}
300312
</>
301313
)}
302314
</div>
@@ -312,10 +324,11 @@ const PracticeChatbot = () => {
312324
onChange={(e) => setCurrentMessage(e.target.value)}
313325
/>
314326
<Button type="submit" primary disabled={!validToChat || isWaitingForResponse}>
315-
{isWaitingForResponse /* variant="info" variant="white" size="sm" */
327+
{/* isWaitingForResponse
316328
? <Spinner animation="border" variant="warning" />
317329
: <FormattedMessage id="submit-chat-message" defaultMessage="Send" />
318-
}
330+
*/}
331+
<FormattedMessage id="submit-chat-message" defaultMessage="Send" />
319332
</Button>
320333
<ChatbotSuggestions isWaitingForResponse={isWaitingForResponse} />
321334
</form>): (

client/components/ChatBot/ReadingPracticeChatbot.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, { useState, useEffect, useRef } from 'react';
22
import { useSelector, useDispatch } from 'react-redux';
33
import { Spinner } from 'react-bootstrap';
44
import { Button, Icon } from 'semantic-ui-react';
@@ -25,6 +25,14 @@ const ReadingPracticeChatBot = () => {
2525

2626
const { messages, isWaitingForResponse, isLoadingHistory } = useSelector(({ chatbot }) => chatbot);
2727

28+
const latestMessageRef = useRef(null)
29+
30+
const scrollToLatestMessage = () => latestMessageRef.current?.scrollIntoView({ behavior: 'smooth' })
31+
32+
useEffect(() => {
33+
scrollToLatestMessage()
34+
}, [messages])
35+
2836
// Fetch conversation history when the chatbot starts
2937
useEffect(() => {
3038
if (session_id && current_reading_test_question?.question_id) {
@@ -74,11 +82,18 @@ const ReadingPracticeChatBot = () => {
7482
{isLoadingHistory ? (
7583
<Spinner animation="border" variant="info" className="spinner-history" />
7684
) : (
77-
messages.map((message, index) => (
78-
<div key={index} className={`message message-${message.type}`} style={{display: 'block'}}>
79-
{message.text ? <ReactMarkdown children={message.text} /> : <FormattedMessage id="Error rendering message" />}
80-
</div>
81-
))
85+
<>
86+
{messages.map((message, index) => (
87+
<div ref={index === messages.length - 1 ? latestMessageRef : null} key={index} className={`message message-${message.type}`} style={{display: 'block'}}>
88+
{message.text ? <ReactMarkdown children={message.text} /> : <FormattedMessage id="Error rendering message" />}
89+
</div>
90+
))}
91+
{isWaitingForResponse && (
92+
<div style={{ display: 'flex', justifyContent: 'center', margin: '20px 0 10px' }}>
93+
<Spinner animation="border" variant="info" />
94+
</div>
95+
)}
96+
</>
8297
)}
8398
</div>
8499
<form onSubmit={handleMessageSubmit} className="chatbot-input-form">
@@ -91,11 +106,7 @@ const ReadingPracticeChatBot = () => {
91106
onChange={(e) => setCurrentMessage(e.target.value)}
92107
/>
93108
<Button type="submit" primary disabled={isWaitingForResponse}>
94-
{isWaitingForResponse ? (
95-
<Spinner animation="border" variant="warning" />
96-
) : (
97-
<FormattedMessage id="submit-chat-message" defaultMessage="Send" />
98-
)}
109+
<FormattedMessage id="submit-chat-message" defaultMessage="Send" />
99110
</Button>
100111
<ChatbotSuggestions isWaitingForResponse={isWaitingForResponse} />
101112
</form>

0 commit comments

Comments
 (0)