import React, { useEffect, useState, useRef } from "react"; import { useRouter } from "next/router"; // react-hook-form import { useForm } from "react-hook-form"; // services import aiService from "services/ai.service"; import trackEventServices from "services/track-event.service"; // hooks import useToast from "hooks/use-toast"; import useUserAuth from "hooks/use-user-auth"; // ui import { Input, PrimaryButton, SecondaryButton } from "components/ui"; // components import { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "@plane/rich-text-editor"; // types import { IIssue, IPageBlock } from "types"; type Props = { isOpen: boolean; handleClose: () => void; inset?: string; content: string; htmlContent?: string; onResponse: (response: string) => void; projectId: string; block?: IPageBlock; issue?: IIssue; }; type FormData = { prompt: string; task: string; }; export const GptAssistantModal: React.FC = ({ isOpen, handleClose, inset = "top-0 left-0", content, htmlContent, onResponse, projectId, block, issue, }) => { const [response, setResponse] = useState(""); const [invalidResponse, setInvalidResponse] = useState(false); const router = useRouter(); const { workspaceSlug } = router.query; const { user } = useUserAuth(); const editorRef = useRef(null); const { setToastAlert } = useToast(); const { handleSubmit, register, reset, setFocus, formState: { isSubmitting }, } = useForm({ defaultValues: { prompt: content, task: "", }, }); const onClose = () => { handleClose(); setResponse(""); setInvalidResponse(false); reset(); }; const handleResponse = async (formData: FormData) => { if (!workspaceSlug || !projectId) return; if (formData.task === "") { setToastAlert({ type: "error", title: "Error!", message: "Please enter some task to get AI assistance.", }); return; } await aiService .createGptTask( workspaceSlug as string, projectId as string, { prompt: content && content !== "" ? content : htmlContent ?? "", task: formData.task, }, user ) .then((res) => { setResponse(res.response_html); setFocus("task"); if (res.response === "") setInvalidResponse(true); else setInvalidResponse(false); }) .catch((err) => { const error = err?.data?.error; if (err.status === 429) setToastAlert({ type: "error", title: "Error!", message: error || "You have reached the maximum number of requests of 50 requests per month per user.", }); else setToastAlert({ type: "error", title: "Error!", message: error || "Some error occurred. Please try again.", }); }); }; useEffect(() => { if (isOpen) setFocus("task"); }, [isOpen, setFocus]); useEffect(() => { editorRef.current?.setEditorValue(htmlContent ?? `

${content}

`); }, [htmlContent, editorRef, content]); return (
{((content && content !== "") || (htmlContent && htmlContent !== "

")) && (
Content: ${content}

`} customClassName="-m-3" noBorder borderOnFocus={false} ref={editorRef} />
)} {response !== "" && (
Response: ${response}

`} customClassName="-mx-3 -my-3" noBorder borderOnFocus={false} />
)} {invalidResponse && (
No response could be generated. This may be due to insufficient content or task information. Please try again.
)}
{response !== "" && ( { onResponse(response); onClose(); if (block) trackEventServices.trackUseGPTResponseEvent( block, "USE_GPT_RESPONSE_IN_PAGE_BLOCK", user ); else if (issue) trackEventServices.trackUseGPTResponseEvent( issue, "USE_GPT_RESPONSE_IN_ISSUE", user ); }} > Use this response )}
Close {isSubmitting ? "Generating response..." : response === "" ? "Generate response" : "Generate again"}
); };