import { FC, useCallback, useEffect, useState } from "react"; import debounce from "lodash/debounce"; import { observer } from "mobx-react"; import { Controller, useForm } from "react-hook-form"; // types import { TIssue } from "@plane/types"; // ui import { Loader } from "@plane/ui"; // components import { RichTextEditor, RichTextReadOnlyEditor } from "@/components/editor"; import { TIssueOperations } from "@/components/issues/issue-detail"; // helpers import { getDescriptionPlaceholder } from "@/helpers/issue.helper"; // hooks import { useWorkspace } from "@/hooks/store"; export type IssueDescriptionInputProps = { containerClassName?: string; workspaceSlug: string; projectId: string; issueId: string; initialValue: string | undefined; disabled?: boolean; issueOperations: TIssueOperations; placeholder?: string | ((isFocused: boolean, value: string) => string); setIsSubmitting: (initialValue: "submitting" | "submitted" | "saved") => void; swrIssueDescription: string | null | undefined; }; export const IssueDescriptionInput: FC = observer((props) => { const { containerClassName, workspaceSlug, projectId, issueId, disabled, swrIssueDescription, initialValue, issueOperations, setIsSubmitting, placeholder, } = props; const { handleSubmit, reset, control } = useForm({ defaultValues: { description_html: initialValue, }, }); const [localIssueDescription, setLocalIssueDescription] = useState({ id: issueId, description_html: initialValue, }); const handleDescriptionFormSubmit = useCallback( async (formData: Partial) => { await issueOperations.update(workspaceSlug, projectId, issueId, { description_html: formData.description_html ?? "

", }); }, [workspaceSlug, projectId, issueId, issueOperations] ); const { getWorkspaceBySlug } = useWorkspace(); // computed values const workspaceId = getWorkspaceBySlug(workspaceSlug)?.id as string; // reset form values useEffect(() => { if (!issueId) return; reset({ id: issueId, description_html: initialValue === "" ? "

" : initialValue, }); setLocalIssueDescription({ id: issueId, description_html: initialValue === "" ? "

" : initialValue, }); }, [initialValue, issueId, reset]); // ADDING handleDescriptionFormSubmit TO DEPENDENCY ARRAY PRODUCES ADVERSE EFFECTS // TODO: Verify the exhaustive-deps warning // eslint-disable-next-line react-hooks/exhaustive-deps const debouncedFormSave = useCallback( debounce(async () => { handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted")); }, 1500), [handleSubmit, issueId] ); return ( <> {localIssueDescription.description_html ? ( !disabled ? (

"} value={swrIssueDescription ?? null} workspaceSlug={workspaceSlug} workspaceId={workspaceId} projectId={projectId} dragDropEnabled onChange={(_description: object, description_html: string) => { setIsSubmitting("submitting"); onChange(description_html); debouncedFormSave(); }} placeholder={ placeholder ? placeholder : (isFocused, value) => getDescriptionPlaceholder(isFocused, value) } containerClassName={containerClassName} /> ) : ( ) } /> ) : ( )} ); });