dia-gov's picture
Upload 569 files
cd6f98e verified
raw
history blame
3.62 kB
import clsx from "clsx";
import { useTranslation } from "next-i18next";
import type { ReactNode } from "react";
import React, { useEffect, useRef, useState } from "react";
import { FaArrowCircleDown, FaCommentDots } from "react-icons/fa";
import { ImSpinner2 } from "react-icons/im";
import type { HeaderProps } from "./MacWindowHeader";
import { MacWindowHeader, messageListId } from "./MacWindowHeader";
import { useAgentStore } from "../../stores";
import Button from "../Button";
import Input from "../Input";
import HideShow from "../motions/HideShow";
interface ChatControls {
value: string;
onChange: (string) => void;
handleChat: () => Promise<void>;
loading?: boolean;
}
interface ChatWindowProps extends HeaderProps {
children?: ReactNode;
setAgentRun?: (name: string, goal: string) => void;
visibleOnMobile?: boolean;
chatControls?: ChatControls;
}
const ChatWindow = ({ messages, children, title, chatControls }: ChatWindowProps) => {
const [t] = useTranslation();
const [hasUserScrolled, setHasUserScrolled] = useState(false);
const isThinking = useAgentStore.use.isAgentThinking();
const isStopped = useAgentStore.use.lifecycle() === "stopped";
const scrollRef = useRef<HTMLDivElement>(null);
const handleScroll = (event: React.UIEvent<HTMLDivElement>) => {
const { scrollTop, scrollHeight, clientHeight } = event.currentTarget;
// Use has scrolled if we have scrolled up at all from the bottom
const hasUserScrolled = scrollTop < scrollHeight - clientHeight - 10;
setHasUserScrolled(hasUserScrolled);
};
const handleScrollToBottom = (behaviour: "instant" | "smooth") => {
if (!scrollRef || !scrollRef.current) return;
scrollRef.current.scrollTo({
top: scrollRef.current.scrollHeight,
behavior: behaviour,
});
};
useEffect(() => {
if (!hasUserScrolled) {
handleScrollToBottom("instant");
}
});
return (
<div
className={clsx(
"flex h-full w-full max-w-[inherit] flex-1 flex-col overflow-auto text-slate-12 transition-all duration-500"
)}
>
<HideShow
showComponent={hasUserScrolled}
className="absolute bottom-11 right-6 z-40 cursor-pointer sm:bottom-14"
>
<FaArrowCircleDown
onClick={() => handleScrollToBottom("smooth")}
className="h-6 w-6 animate-bounce md:h-7 md:w-7"
/>
</HideShow>
<MacWindowHeader title={title} messages={messages} />
<div
className="mb-2 mr-2 flex-1 overflow-auto transition-all duration-500"
ref={scrollRef}
onScroll={handleScroll}
id={messageListId}
>
{children}
<div
className={clsx(
isThinking && !isStopped ? "opacity-100" : "opacity-0",
"mr-2 flex flex-row items-center gap-2 p-2 transition duration-300 sm:mr-4",
"text-xs sm:text-base"
)}
>
<p>🧠 Thinking</p>
<ImSpinner2 className="animate-spin" />
</div>
</div>
{chatControls && (
<div className="mt-auto flex flex-row gap-2 p-2 pt-0 sm:p-4">
<Input
small
placeholder="Chat with your agent..."
value={chatControls.value}
onChange={(e) => chatControls?.onChange(e.target.value)}
/>
<Button
className="px-1 py-1 sm:px-3 md:py-1"
onClick={chatControls?.handleChat}
disabled={chatControls.loading}
>
<FaCommentDots />
</Button>
</div>
)}
</div>
);
};
export default ChatWindow;