chore: option to switch access of a comment (#2116)

This commit is contained in:
Aaryan Khandelwal 2023-09-07 12:54:30 +05:30 committed by GitHub
parent d26aa1b2da
commit 81436902a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 75 additions and 31 deletions

View File

@ -38,7 +38,7 @@ export const InboxIssueActivity: React.FC<Props> = ({ issueDetails }) => {
: null
);
const handleCommentUpdate = async (comment: IIssueComment) => {
const handleCommentUpdate = async (commentId: string, data: Partial<IIssueComment>) => {
if (!workspaceSlug || !projectId || !inboxIssueId) return;
await issuesService
@ -46,8 +46,8 @@ export const InboxIssueActivity: React.FC<Props> = ({ issueDetails }) => {
workspaceSlug as string,
projectId as string,
inboxIssueId as string,
comment.id,
comment,
commentId,
data,
user
)
.then(() => mutateIssueActivity());

View File

@ -15,14 +15,16 @@ import { IIssueActivity, IIssueComment } from "types";
type Props = {
activity: IIssueActivity[] | undefined;
handleCommentUpdate: (comment: IIssueComment) => Promise<void>;
handleCommentUpdate: (commentId: string, data: Partial<IIssueComment>) => Promise<void>;
handleCommentDelete: (commentId: string) => Promise<void>;
showAccessSpecifier?: boolean;
};
export const IssueActivitySection: React.FC<Props> = ({
activity,
handleCommentUpdate,
handleCommentDelete,
showAccessSpecifier = false,
}) => {
const router = useRouter();
const { workspaceSlug } = router.query;
@ -131,10 +133,11 @@ export const IssueActivitySection: React.FC<Props> = ({
return (
<div key={activityItem.id} className="mt-4">
<CommentCard
workspaceSlug={workspaceSlug as string}
comment={activityItem as IIssueComment}
onSubmit={handleCommentUpdate}
handleCommentDeletion={handleCommentDelete}
onSubmit={handleCommentUpdate}
showAccessSpecifier={showAccessSpecifier}
workspaceSlug={workspaceSlug as string}
/>
</div>
);

View File

@ -7,7 +7,7 @@ import { ChatBubbleLeftEllipsisIcon, CheckIcon, XMarkIcon } from "@heroicons/rea
// hooks
import useUser from "hooks/use-user";
// ui
import { CustomMenu } from "components/ui";
import { CustomMenu, Icon } from "components/ui";
import { CommentReaction } from "components/issues";
import { TipTapEditor } from "components/tiptap";
// helpers
@ -16,17 +16,19 @@ import { timeAgo } from "helpers/date-time.helper";
import type { IIssueComment } from "types";
type Props = {
workspaceSlug: string;
comment: IIssueComment;
onSubmit: (comment: IIssueComment) => void;
handleCommentDeletion: (comment: string) => void;
onSubmit: (commentId: string, data: Partial<IIssueComment>) => void;
showAccessSpecifier?: boolean;
workspaceSlug: string;
};
export const CommentCard: React.FC<Props> = ({
comment,
workspaceSlug,
onSubmit,
handleCommentDeletion,
onSubmit,
showAccessSpecifier = false,
workspaceSlug,
}) => {
const { user } = useUser();
@ -45,11 +47,11 @@ export const CommentCard: React.FC<Props> = ({
defaultValues: comment,
});
const onEnter = (formData: IIssueComment) => {
const onEnter = (formData: Partial<IIssueComment>) => {
if (isSubmitting) return;
setIsEditing(false);
onSubmit(formData);
onSubmit(comment.id, formData);
editorRef.current?.setEditorValue(formData.comment_html);
showEditorRef.current?.setEditorValue(formData.comment_html);
@ -99,7 +101,7 @@ export const CommentCard: React.FC<Props> = ({
: comment.actor_detail.display_name}
</div>
<p className="mt-0.5 text-xs text-custom-text-200">
Commented {timeAgo(comment.created_at)}
commented {timeAgo(comment.created_at)}
</p>
</div>
<div className="issue-comments-section p-0">
@ -137,7 +139,15 @@ export const CommentCard: React.FC<Props> = ({
</button>
</div>
</form>
<div className={`${isEditing ? "hidden" : ""}`}>
<div className={`relative ${isEditing ? "hidden" : ""}`}>
{showAccessSpecifier && (
<div className="absolute top-1 right-1.5 z-[1] text-custom-text-300">
<Icon
iconName={comment.access === "INTERNAL" ? "lock" : "public"}
className="!text-xs"
/>
</div>
)}
<TipTapEditor
workspaceSlug={workspaceSlug as string}
ref={showEditorRef}
@ -151,13 +161,44 @@ export const CommentCard: React.FC<Props> = ({
</div>
{user?.id === comment.actor && (
<CustomMenu ellipsis>
<CustomMenu.MenuItem onClick={() => setIsEditing(true)}>Edit</CustomMenu.MenuItem>
<CustomMenu.MenuItem
onClick={() => setIsEditing(true)}
className="flex items-center gap-1"
>
<Icon iconName="edit" />
Edit comment
</CustomMenu.MenuItem>
{showAccessSpecifier && (
<>
{comment.access === "INTERNAL" ? (
<CustomMenu.MenuItem
renderAs="button"
onClick={() => onSubmit(comment.id, { access: "EXTERNAL" })}
className="flex items-center gap-1"
>
<Icon iconName="public" />
Switch to public comment
</CustomMenu.MenuItem>
) : (
<CustomMenu.MenuItem
renderAs="button"
onClick={() => onSubmit(comment.id, { access: "INTERNAL" })}
className="flex items-center gap-1"
>
<Icon iconName="lock" />
Switch to private comment
</CustomMenu.MenuItem>
)}
</>
)}
<CustomMenu.MenuItem
onClick={() => {
handleCommentDeletion(comment.id);
}}
className="flex items-center gap-1"
>
Delete
<Icon iconName="delete" />
Delete comment
</CustomMenu.MenuItem>
</CustomMenu>
)}

View File

@ -77,7 +77,7 @@ export const IssueMainContent: React.FC<Props> = ({
: null
);
const handleCommentUpdate = async (comment: IIssueComment) => {
const handleCommentUpdate = async (commentId: string, data: Partial<IIssueComment>) => {
if (!workspaceSlug || !projectId || !issueId) return;
await issuesService
@ -85,8 +85,8 @@ export const IssueMainContent: React.FC<Props> = ({
workspaceSlug as string,
projectId as string,
issueId as string,
comment.id,
comment,
commentId,
data,
user
)
.then(() => mutateIssueActivity());
@ -222,6 +222,7 @@ export const IssueMainContent: React.FC<Props> = ({
activity={issueActivity}
handleCommentUpdate={handleCommentUpdate}
handleCommentDelete={handleCommentDelete}
showAccessSpecifier={projectDetails && projectDetails.is_deployed}
/>
<AddComment
onSubmit={handleAddComment}

View File

@ -5,6 +5,7 @@ import issuesService from "services/issues.service";
// hooks
import useUser from "hooks/use-user";
import useToast from "hooks/use-toast";
import useProjectDetails from "hooks/use-project-details";
// components
import { AddComment, IssueActivitySection } from "components/issues";
// types
@ -22,6 +23,7 @@ export const PeekOverviewIssueActivity: React.FC<Props> = ({ workspaceSlug, issu
const { setToastAlert } = useToast();
const { user } = useUser();
const { projectDetails } = useProjectDetails();
const { data: issueActivity, mutate: mutateIssueActivity } = useSWR(
workspaceSlug && issue ? PROJECT_ISSUES_ACTIVITY(issue.id) : null,
@ -30,18 +32,11 @@ export const PeekOverviewIssueActivity: React.FC<Props> = ({ workspaceSlug, issu
: null
);
const handleCommentUpdate = async (comment: IIssueComment) => {
const handleCommentUpdate = async (commentId: string, data: Partial<IIssueComment>) => {
if (!workspaceSlug || !issue) return;
await issuesService
.patchIssueComment(
workspaceSlug as string,
issue.project,
issue.id,
comment.id,
comment,
user
)
.patchIssueComment(workspaceSlug as string, issue.project, issue.id, commentId, data, user)
.then(() => mutateIssueActivity());
};
@ -80,9 +75,13 @@ export const PeekOverviewIssueActivity: React.FC<Props> = ({ workspaceSlug, issu
activity={issueActivity}
handleCommentUpdate={handleCommentUpdate}
handleCommentDelete={handleCommentDelete}
showAccessSpecifier={projectDetails && projectDetails.is_deployed}
/>
<div className="mt-4">
<AddComment onSubmit={handleAddComment} />
<AddComment
onSubmit={handleAddComment}
showAccessSpecifier={projectDetails && projectDetails.is_deployed}
/>
</div>
</div>
</div>

View File

@ -204,7 +204,7 @@ class ProjectIssuesServices extends APIService {
projectId: string,
issueId: string,
commentId: string,
data: IIssueComment,
data: Partial<IIssueComment>,
user: ICurrentUserResponse | undefined
): Promise<any> {
return this.patch(