import { Fragment, type SubmitEvent, useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import Icon from "@/components/ui/icon"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useChat, useModels, useSelectedOrganisation, useSelectedProject } from "@/lib/query/hooks"; import { parseError } from "@/lib/server"; import Avatar from "./avatar"; import { useAuthenticatedSession } from "./session-provider"; import { IconButton } from "./ui/icon-button"; import { Input } from "./ui/input"; export function Chat({ setHighlighted }: { setHighlighted: (ids: number[]) => void }) { const { user } = useAuthenticatedSession(); const selectedOrganisation = useSelectedOrganisation(); const selectedProject = useSelectedProject(); const chat = useChat(); const models = useModels(); const [isOpen, setIsOpen] = useState(false); const [message, setMessage] = useState(""); const [response, setResponse] = useState(""); const [lastUserMessage, setLastUserMessage] = useState(""); const [error, setError] = useState(null); const [selectedModel, setSelectedModel] = useState(""); useEffect(() => { if (isOpen && !models.data) { models.mutate(); } }, [isOpen, models]); useEffect(() => { if (models.data && models.data.length > 0 && !selectedModel) { setSelectedModel(models.data[0].id); } }, [models.data, selectedModel]); const handleSubmit = async (e: SubmitEvent) => { e.preventDefault(); if (!message.trim()) return; if (!selectedOrganisation || !selectedProject) { setError("Please select an organisation and project first"); return; } setError(null); setResponse(""); setHighlighted([]); setLastUserMessage(message.trim()); try { const data = await chat.mutateAsync({ orgId: selectedOrganisation.Organisation.id, projectId: selectedProject.Project.id, message: message.trim(), model: selectedModel || "trinity-large-preview-free", }); setResponse(data.text); setHighlighted(data.highlighted_issues); setMessage(""); } catch (err) { const errorMessage = parseError(err as Error); setError(errorMessage); } }; return ( <> setIsOpen(!isOpen)} className="fixed bottom-4 left-1/2 -translate-x-1/2 z-50 rounded-full" size="lg" variant="outline" > {isOpen && (
{lastUserMessage && (

{lastUserMessage}

)} {(chat.isPending || response) && (
{"sprint {!response && (
)} {response && (

{response.split("\n").map((line, index) => ( // biome-ignore lint/suspicious/noArrayIndexKey: <> {line}
))}

)}
)}
{models.data && models.data.length > 0 && ( )} ) => setMessage(e.target.value)} placeholder={`Ask me anything about the ${selectedProject?.Project.name || "..."} project...`} disabled={chat.isPending} showCounter={false} />
{} {error && (

{error}

)}
)} ); }