"use client"; import { FC, useEffect, useRef, useState } from "react"; import { observer } from "mobx-react"; import { useForm } from "react-hook-form"; import { Check, Globe2, Lock, Pencil, Trash2, X } from "lucide-react"; // PLane import { EIssueCommentAccessSpecifier } from "@plane/constants"; import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/editor"; import { useTranslation } from "@plane/i18n"; import { TIssueComment, TCommentsOperations } from "@plane/types"; import { CustomMenu } from "@plane/ui"; // components import { LiteTextEditor, LiteTextReadOnlyEditor } from "@/components/editor"; // helpers import { isCommentEmpty } from "@/helpers/string.helper"; // hooks import { useUser } from "@/hooks/store"; // import { CommentBlock } from "@/plane-web/components/comments"; import { CommentReactions } from "./comment-reaction"; type TCommentCard = { workspaceSlug: string; comment: TIssueComment | undefined; activityOperations: TCommentsOperations; ends: "top" | "bottom" | undefined; showAccessSpecifier?: boolean; disabled?: boolean; projectId?: string; }; export const CommentCard: FC = observer((props) => { const { workspaceSlug, comment, activityOperations, ends, showAccessSpecifier = false, disabled = false, projectId, } = props; const { t } = useTranslation(); // refs const editorRef = useRef(null); const showEditorRef = useRef(null); // state const [isEditing, setIsEditing] = useState(false); // store hooks const { data: currentUser } = useUser(); // form info const { formState: { isSubmitting }, handleSubmit, setFocus, watch, setValue, } = useForm>({ defaultValues: { comment_html: comment?.comment_html }, }); // derived values const workspaceId = comment?.workspace; const commentHTML = watch("comment_html"); const isEmpty = isCommentEmpty(commentHTML ?? undefined); const isEditorReadyToDiscard = editorRef.current?.isEditorReadyToDiscard(); const isSubmitButtonDisabled = isSubmitting || !isEditorReadyToDiscard; const isDisabled = isSubmitting || isEmpty || isSubmitButtonDisabled; // helpers const onEnter = async (formData: Partial) => { if (isSubmitting || !comment) return; setIsEditing(false); await activityOperations.updateComment(comment.id, formData); editorRef.current?.setEditorValue(formData?.comment_html ?? "

"); showEditorRef.current?.setEditorValue(formData?.comment_html ?? "

"); }; useEffect(() => { if (isEditing) { setFocus("comment_html"); } }, [isEditing, setFocus]); if (!comment || !currentUser || !workspaceId) return <>; return ( {!disabled && currentUser?.id === comment.actor && ( setIsEditing(true)} className="flex items-center gap-1"> {t("common.actions.edit")} {showAccessSpecifier && ( <> {comment.access === "INTERNAL" ? ( activityOperations.updateComment(comment.id, { access: EIssueCommentAccessSpecifier.EXTERNAL }) } className="flex items-center gap-1" > {t("issue.comments.switch.public")} ) : ( activityOperations.updateComment(comment.id, { access: EIssueCommentAccessSpecifier.INTERNAL }) } className="flex items-center gap-1" > {t("issue.comments.switch.private")} )} )} activityOperations.removeComment(comment.id)} className="flex items-center gap-1" > {t("common.actions.delete")} )} } ends={ends} > <>
{ if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey && !isEmpty) handleSubmit(onEnter)(e); }} > setValue("comment_html", comment_html)} onEnterKeyPress={(e) => { if (!isEmpty && !isSubmitting) { handleSubmit(onEnter)(e); } }} showSubmitButton={false} uploadFile={async (blockId, file) => { const { asset_id } = await activityOperations.uploadCommentAsset(blockId, file, comment.id); return asset_id; }} projectId={projectId?.toString() ?? ""} parentClassName="p-2" displayConfig={{ fontSize: "small-font", }} />
{!isEmpty && ( )}
{showAccessSpecifier && (
{comment.access === EIssueCommentAccessSpecifier.INTERNAL ? ( ) : ( )}
)}
); });