[WEB-3529] fix: comment reset + edit comment font size + comment box position (#6909)

* fix: comment reset + edit comment font size

* fix: dynamically setting the position of the comment box

* fix: refactor

* fix: nomenclature
This commit is contained in:
Akshita Goyal 2025-04-11 01:40:05 +05:30 committed by GitHub
parent 882520b3c7
commit 2818310619
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 77 additions and 25 deletions

View file

@ -40,7 +40,7 @@ export type TIssueComment = {
};
export type TCommentsOperations = {
createComment: (data: Partial<TIssueComment>) => Promise<void>;
createComment: (data: Partial<TIssueComment>) => Promise<Partial<TIssueComment> | undefined>;
updateComment: (commentId: string, data: Partial<TIssueComment>) => Promise<void>;
removeComment: (commentId: string) => Promise<void>;
uploadCommentAsset: (blockId: string, file: File, commentId?: string) => Promise<TFileSignedURLResponse>;

View file

@ -161,7 +161,9 @@ export const CommentCard: FC<TCommentCard> = observer((props) => {
return asset_id;
}}
projectId={projectId?.toString() ?? ""}
/>
editorClassName="[&>*]:!py-0 [&>*]:!text-sm"
parentClassName="p-2"
/>
</div>
<div className="flex gap-1 self-end">
{!isEmpty && (
@ -181,7 +183,10 @@ export const CommentCard: FC<TCommentCard> = observer((props) => {
<button
type="button"
className="group rounded border border-red-500 bg-red-500/20 p-2 shadow-md duration-300 hover:bg-red-500"
onClick={() => setIsEditing(false)}
onClick={() => {
setIsEditing(false);
editorRef.current?.setEditorValue(comment.comment_html ?? "<p></p>");
}}
>
<X className="size-3 text-red-500 duration-300 group-hover:text-white" />
</button>

View file

@ -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<TCommentCreate> = observer((props) => {
const { workspaceSlug, entityId, activityOperations, showToolbarInitially = false, projectId } = props;
const {
workspaceSlug,
entityId,
activityOperations,
showToolbarInitially = false,
projectId,
onSubmitCallback,
} = props;
// states
const [uploadedAssetIds, setUploadedAssetIds] = useState<string[]>([]);
// refs
@ -51,7 +62,8 @@ export const CommentCreate: FC<TCommentCreate> = observer((props) => {
const onSubmit = async (formData: Partial<TIssueComment>) => {
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<TCommentCreate> = observer((props) => {
<div
className={cn("sticky bottom-0 z-[4] bg-custom-background-100 sm:static")}
onKeyDown={(e) => {
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);
}}
>

View file

@ -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<TCommentsWrapper> = 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 (
<div className="relative flex flex-col gap-y-2 h-full overflow-hidden">
{isEditingAllowed && (
const renderCommentCreate = useMemo(
() =>
isEditingAllowed && (
<CommentCreate
workspaceSlug={workspaceSlug}
entityId={entityId}
activityOperations={activityOperations}
projectId={projectId}
onSubmitCallback={async (elementId: string) => {
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 (
<div className="relative flex flex-col gap-y-2 h-full overflow-hidden">
{sortOrder === E_SORT_ORDER.DESC && renderCommentCreate}
<div className="flex-grow py-4 overflow-y-auto">
{comments?.map((data, index) => {
let comment;
@ -58,6 +79,7 @@ export const CommentsWrapper: FC<TCommentsWrapper> = observer((props) => {
);
})}
</div>
{sortOrder === E_SORT_ORDER.ASC && renderCommentCreate}
</div>
);
});

View file

@ -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<TIssueActivity> = observer((props) => {
const activityOperations = useCommentOperations(workspaceSlug, projectId, issueId);
const project = getProjectById(projectId);
const renderCommentCreationBox = useMemo(
() => (
<CommentCreate
workspaceSlug={workspaceSlug}
entityId={issueId}
activityOperations={activityOperations}
showToolbarInitially
projectId={projectId}
/>
),
[workspaceSlug, issueId, activityOperations, projectId]
);
if (!project) return <></>;
return (
@ -111,6 +123,7 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
<div className="space-y-3">
<div className="min-h-[200px]">
<div className="space-y-3">
{!disabled && sortOrder === E_SORT_ORDER.DESC && renderCommentCreationBox}
<IssueActivityCommentRoot
projectId={projectId}
workspaceSlug={workspaceSlug}
@ -121,15 +134,7 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
disabled={disabled}
sortOrder={sortOrder || E_SORT_ORDER.ASC}
/>
{!disabled && (
<CommentCreate
workspaceSlug={workspaceSlug}
entityId={issueId}
activityOperations={activityOperations}
showToolbarInitially
projectId={projectId}
/>
)}
{!disabled && sortOrder === E_SORT_ORDER.ASC && renderCommentCreationBox}
</div>
</div>
</div>