diff --git a/packages/types/src/issues/activity/issue_comment.d.ts b/packages/types/src/issues/activity/issue_comment.d.ts index 95be9a7d4..e61b35585 100644 --- a/packages/types/src/issues/activity/issue_comment.d.ts +++ b/packages/types/src/issues/activity/issue_comment.d.ts @@ -40,7 +40,7 @@ export type TIssueComment = { }; export type TCommentsOperations = { - createComment: (data: Partial) => Promise; + createComment: (data: Partial) => Promise | undefined>; updateComment: (commentId: string, data: Partial) => Promise; removeComment: (commentId: string) => Promise; uploadCommentAsset: (blockId: string, file: File, commentId?: string) => Promise; diff --git a/web/core/components/comments/comment-card.tsx b/web/core/components/comments/comment-card.tsx index 0f52cd66b..dd9e61e03 100644 --- a/web/core/components/comments/comment-card.tsx +++ b/web/core/components/comments/comment-card.tsx @@ -161,7 +161,9 @@ export const CommentCard: FC = observer((props) => { return asset_id; }} projectId={projectId?.toString() ?? ""} - /> + editorClassName="[&>*]:!py-0 [&>*]:!text-sm" + parentClassName="p-2" + />
{!isEmpty && ( @@ -181,7 +183,10 @@ export const CommentCard: FC = observer((props) => { diff --git a/web/core/components/comments/comment-create.tsx b/web/core/components/comments/comment-create.tsx index d5ccbdeb1..1321a385f 100644 --- a/web/core/components/comments/comment-create.tsx +++ b/web/core/components/comments/comment-create.tsx @@ -5,15 +5,17 @@ import { useForm, Controller } from "react-hook-form"; import { EIssueCommentAccessSpecifier } from "@plane/constants"; // plane editor import { EditorRefApi } from "@plane/editor"; -// components +// plane types import { TIssueComment, TCommentsOperations } from "@plane/types"; +// components import { LiteTextEditor } from "@/components/editor"; // constants -// helpers import { cn } from "@/helpers/common.helper"; +// helpers import { isCommentEmpty } from "@/helpers/string.helper"; // hooks import { useWorkspace } from "@/hooks/store"; +// services import { FileService } from "@/services/file.service"; type TCommentCreate = { @@ -22,12 +24,21 @@ type TCommentCreate = { activityOperations: TCommentsOperations; showToolbarInitially?: boolean; projectId?: string; + onSubmitCallback?: (elementId: string) => void; }; // services const fileService = new FileService(); + export const CommentCreate: FC = observer((props) => { - const { workspaceSlug, entityId, activityOperations, showToolbarInitially = false, projectId } = props; + const { + workspaceSlug, + entityId, + activityOperations, + showToolbarInitially = false, + projectId, + onSubmitCallback, + } = props; // states const [uploadedAssetIds, setUploadedAssetIds] = useState([]); // refs @@ -51,7 +62,8 @@ export const CommentCreate: FC = observer((props) => { const onSubmit = async (formData: Partial) => { try { - await activityOperations.createComment(formData); + const comment = await activityOperations.createComment(formData); + if (comment?.id) onSubmitCallback?.(comment.id); if (uploadedAssetIds.length > 0) { if (projectId) { await fileService.updateBulkProjectAssetsUploadStatus(workspaceSlug, projectId.toString(), entityId, { @@ -81,7 +93,15 @@ export const CommentCreate: FC = observer((props) => {
{ - if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey && !isEmpty && !isSubmitting) + if ( + e.key === "Enter" && + !e.shiftKey && + !e.ctrlKey && + !e.metaKey && + !isEmpty && + !isSubmitting && + editorRef.current?.isEditorReadyToDiscard() + ) handleSubmit(onSubmit)(e); }} > diff --git a/web/core/components/comments/comments.tsx b/web/core/components/comments/comments.tsx index 70fe1a095..0614bb165 100644 --- a/web/core/components/comments/comments.tsx +++ b/web/core/components/comments/comments.tsx @@ -1,9 +1,11 @@ "use client"; -import React, { FC } from "react"; +import React, { FC, useMemo } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // plane imports +import smoothScrollIntoView from "smooth-scroll-into-view-if-needed"; +import { E_SORT_ORDER } from "@plane/constants"; import { TCommentsOperations, TIssueComment } from "@plane/types"; // local components import { CommentCard } from "./comment-card"; @@ -15,26 +17,45 @@ type TCommentsWrapper = { isEditingAllowed?: boolean; activityOperations: TCommentsOperations; comments: TIssueComment[] | string[]; + sortOrder?: E_SORT_ORDER; getCommentById?: (activityId: string) => TIssueComment | undefined; }; export const CommentsWrapper: FC = observer((props) => { - const { entityId, activityOperations, comments, getCommentById, isEditingAllowed = true, projectId } = props; + const { + entityId, + activityOperations, + comments, + getCommentById, + isEditingAllowed = true, + projectId, + sortOrder, + } = props; // router const { workspaceSlug: routerWorkspaceSlug } = useParams(); const workspaceSlug = routerWorkspaceSlug?.toString(); - - return ( -
- {isEditingAllowed && ( + const renderCommentCreate = useMemo( + () => + isEditingAllowed && ( { + const sourceElementId = elementId ?? ""; + const sourceElement = document.getElementById(sourceElementId); + if (sourceElement) + await smoothScrollIntoView(sourceElement, { behavior: "smooth", block: "center", duration: 1500 }); + }} /> - )} + ), + [isEditingAllowed, workspaceSlug, entityId, activityOperations, projectId] + ); + return ( +
+ {sortOrder === E_SORT_ORDER.DESC && renderCommentCreate}
{comments?.map((data, index) => { let comment; @@ -58,6 +79,7 @@ export const CommentsWrapper: FC = observer((props) => { ); })}
+ {sortOrder === E_SORT_ORDER.ASC && renderCommentCreate}
); }); diff --git a/web/core/components/issues/issue-detail/issue-activity/root.tsx b/web/core/components/issues/issue-detail/issue-activity/root.tsx index 2acefbf68..67f7351a9 100644 --- a/web/core/components/issues/issue-detail/issue-activity/root.tsx +++ b/web/core/components/issues/issue-detail/issue-activity/root.tsx @@ -1,6 +1,6 @@ "use client"; -import { FC } from "react"; +import { FC, useMemo } from "react"; import { observer } from "mobx-react"; // plane package imports import { E_SORT_ORDER, TActivityFilters, defaultActivityFilters, EUserPermissions } from "@plane/constants"; @@ -81,6 +81,18 @@ export const IssueActivity: FC = observer((props) => { const activityOperations = useCommentOperations(workspaceSlug, projectId, issueId); const project = getProjectById(projectId); + const renderCommentCreationBox = useMemo( + () => ( + + ), + [workspaceSlug, issueId, activityOperations, projectId] + ); if (!project) return <>; return ( @@ -111,6 +123,7 @@ export const IssueActivity: FC = observer((props) => {
+ {!disabled && sortOrder === E_SORT_ORDER.DESC && renderCommentCreationBox} = observer((props) => { disabled={disabled} sortOrder={sortOrder || E_SORT_ORDER.ASC} /> - {!disabled && ( - - )} + {!disabled && sortOrder === E_SORT_ORDER.ASC && renderCommentCreationBox}