Adding loading indicator

This commit is contained in:
2026-01-11 09:22:28 -05:00
parent 12eb110313
commit 07512409f1
2 changed files with 60 additions and 40 deletions

View File

@@ -40,6 +40,7 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
const [selectedConversation, setSelectedConversation] = const [selectedConversation, setSelectedConversation] =
useState<Conversation | null>(null); useState<Conversation | null>(null);
const [sidebarCollapsed, setSidebarCollapsed] = useState<boolean>(false); const [sidebarCollapsed, setSidebarCollapsed] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(false);
const messagesEndRef = useRef<HTMLDivElement>(null); const messagesEndRef = useRef<HTMLDivElement>(null);
const simbaAnswers = ["meow.", "hiss...", "purrrrrr", "yowOWROWWowowr"]; const simbaAnswers = ["meow.", "hiss...", "purrrrrr", "yowOWROWWowowr"];
@@ -131,11 +132,12 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
}, [selectedConversation?.id]); }, [selectedConversation?.id]);
const handleQuestionSubmit = async () => { const handleQuestionSubmit = async () => {
if (!query.trim()) return; // Don't submit empty messages if (!query.trim() || isLoading) return; // Don't submit empty messages or while loading
const currMessages = messages.concat([{ text: query, speaker: "user" }]); const currMessages = messages.concat([{ text: query, speaker: "user" }]);
setMessages(currMessages); setMessages(currMessages);
setQuery(""); // Clear input immediately after submission setQuery(""); // Clear input immediately after submission
setIsLoading(true);
if (simbaMode) { if (simbaMode) {
console.log("simba mode activated"); console.log("simba mode activated");
@@ -150,6 +152,7 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
}, },
]), ]),
); );
setIsLoading(false);
return; return;
} }
@@ -170,6 +173,8 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
if (error instanceof Error && error.message.includes("Session expired")) { if (error instanceof Error && error.message.includes("Session expired")) {
setAuthenticated(false); setAuthenticated(false);
} }
} finally {
setIsLoading(false);
} }
}; };
@@ -281,6 +286,7 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
} }
return <QuestionBubble key={index} text={msg.text} />; return <QuestionBubble key={index} text={msg.text} />;
})} })}
{isLoading && <AnswerBubble text="" loading={true} />}
<div ref={messagesEndRef} /> <div ref={messagesEndRef} />
</div> </div>
</div> </div>
@@ -294,6 +300,7 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
handleKeyDown={handleKeyDown} handleKeyDown={handleKeyDown}
handleQuestionSubmit={handleQuestionSubmit} handleQuestionSubmit={handleQuestionSubmit}
setSimbaMode={setSimbaMode} setSimbaMode={setSimbaMode}
isLoading={isLoading}
/> />
</div> </div>
</footer> </footer>

View File

@@ -1,43 +1,56 @@
import { useEffect, useState, useRef } from "react"; import { useEffect, useState, useRef } from "react";
type MessageInputProps = { type MessageInputProps = {
handleQueryChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void; handleQueryChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
handleKeyDown: (event: React.ChangeEvent<HTMLTextAreaElement>) => void; handleKeyDown: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
handleQuestionSubmit: () => void; handleQuestionSubmit: () => void;
setSimbaMode: (sdf: boolean) => void; setSimbaMode: (sdf: boolean) => void;
query: string; query: string;
} isLoading: boolean;
};
export const MessageInput = ({query, handleKeyDown, handleQueryChange, handleQuestionSubmit, setSimbaMode}: MessageInputProps) => { export const MessageInput = ({
return ( query,
<div className="flex flex-col gap-4 sticky bottom-0 bg-[#3D763A] p-6 rounded-xl"> handleKeyDown,
<div className="flex flex-row justify-between grow"> handleQueryChange,
<textarea handleQuestionSubmit,
className="p-3 sm:p-4 border border-blue-200 rounded-md grow bg-[#F9F5EB] min-h-[44px] resize-y" setSimbaMode,
onChange={handleQueryChange} isLoading,
onKeyDown={handleKeyDown} }: MessageInputProps) => {
value={query} return (
rows={2} <div className="flex flex-col gap-4 sticky bottom-0 bg-[#3D763A] p-6 rounded-xl">
placeholder="Type your message... (Press Enter to send, Shift+Enter for new line)" <div className="flex flex-row justify-between grow">
/> <textarea
</div> className="p-3 sm:p-4 border border-blue-200 rounded-md grow bg-[#F9F5EB] min-h-[44px] resize-y"
<div className="flex flex-row justify-between gap-2 grow"> onChange={handleQueryChange}
<button onKeyDown={handleKeyDown}
className="p-3 sm:p-4 min-h-[44px] border border-blue-400 bg-[#EDA541] hover:bg-blue-400 cursor-pointer rounded-md flex-grow text-sm sm:text-base" value={query}
onClick={() => handleQuestionSubmit()} rows={2}
type="submit" placeholder="Type your message... (Press Enter to send, Shift+Enter for new line)"
> />
Submit </div>
</button> <div className="flex flex-row justify-between gap-2 grow">
</div> <button
<div className="flex flex-row justify-center gap-2 grow items-center"> className={`p-3 sm:p-4 min-h-[44px] border border-blue-400 rounded-md flex-grow text-sm sm:text-base ${
<input isLoading
type="checkbox" ? "bg-gray-400 cursor-not-allowed opacity-50"
onChange={(event) => setSimbaMode(event.target.checked)} : "bg-[#EDA541] hover:bg-blue-400 cursor-pointer"
className="w-5 h-5 cursor-pointer" }`}
/> onClick={() => handleQuestionSubmit()}
<p className="text-sm sm:text-base">simba mode?</p> type="submit"
</div> disabled={isLoading}
</div> >
); {isLoading ? "Sending..." : "Submit"}
} </button>
</div>
<div className="flex flex-row justify-center gap-2 grow items-center">
<input
type="checkbox"
onChange={(event) => setSimbaMode(event.target.checked)}
className="w-5 h-5 cursor-pointer"
/>
<p className="text-sm sm:text-base">simba mode?</p>
</div>
</div>
);
};