mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: issue comment reaction
This commit is contained in:
parent
8f8b106a89
commit
8c63a9d7cd
@ -1,20 +1,20 @@
|
|||||||
export type TIssueCommentReaction = {
|
export type TIssueCommentReaction = {
|
||||||
id: string;
|
id: string;
|
||||||
|
comment: string;
|
||||||
|
actor: string;
|
||||||
|
reaction: string;
|
||||||
|
workspace: string;
|
||||||
|
project: string;
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
updated_at: Date;
|
updated_at: Date;
|
||||||
reaction: string;
|
|
||||||
created_by: string;
|
created_by: string;
|
||||||
updated_by: string;
|
updated_by: string;
|
||||||
project: string;
|
|
||||||
workspace: string;
|
|
||||||
actor: string;
|
|
||||||
comment: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIssueCommentReactionMap = {
|
export type TIssueCommentReactionMap = {
|
||||||
[issue_id: string]: TIssueCommentReaction;
|
[reaction_id: string]: TIssueCommentReaction;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIssueCommentReactionIdMap = {
|
export type TIssueCommentReactionIdMap = {
|
||||||
[issue_id: string]: string[];
|
[comment_id: string]: { [reaction: string]: string[] };
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,7 @@ export type TIssueReaction = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TIssueReactionMap = {
|
export type TIssueReactionMap = {
|
||||||
[issue_id: string]: TIssueReaction;
|
[reaction_id: string]: TIssueReaction;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIssueReactionIdMap = {
|
export type TIssueReactionIdMap = {
|
||||||
|
@ -6,6 +6,7 @@ import { useIssueDetail, useMention, useUser } from "hooks/store";
|
|||||||
// components
|
// components
|
||||||
import { IssueCommentBlock } from "./comment-block";
|
import { IssueCommentBlock } from "./comment-block";
|
||||||
import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
|
import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
|
||||||
|
import { IssueCommentReaction } from "../../reactions/issue-comment";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu } from "@plane/ui";
|
import { CustomMenu } from "@plane/ui";
|
||||||
// services
|
// services
|
||||||
@ -28,7 +29,7 @@ type TIssueCommentCard = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const IssueCommentCard: FC<TIssueCommentCard> = (props) => {
|
export const IssueCommentCard: FC<TIssueCommentCard> = (props) => {
|
||||||
const { commentId, activityOperations, ends, showAccessSpecifier = true } = props;
|
const { workspaceSlug, commentId, activityOperations, ends, showAccessSpecifier = true } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const {
|
const {
|
||||||
comment: { getCommentById },
|
comment: { getCommentById },
|
||||||
@ -67,7 +68,7 @@ export const IssueCommentCard: FC<TIssueCommentCard> = (props) => {
|
|||||||
isEditing && setFocus("comment_html");
|
isEditing && setFocus("comment_html");
|
||||||
}, [isEditing, setFocus]);
|
}, [isEditing, setFocus]);
|
||||||
|
|
||||||
if (!comment) return <></>;
|
if (!comment || !currentUser) return <></>;
|
||||||
return (
|
return (
|
||||||
<IssueCommentBlock
|
<IssueCommentBlock
|
||||||
commentId={commentId}
|
commentId={commentId}
|
||||||
@ -161,7 +162,13 @@ export const IssueCommentCard: FC<TIssueCommentCard> = (props) => {
|
|||||||
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
|
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
|
||||||
mentionHighlights={mentionHighlights}
|
mentionHighlights={mentionHighlights}
|
||||||
/>
|
/>
|
||||||
{/* <CommentReaction projectId={comment.project} commentId={comment.id} /> */}
|
|
||||||
|
<IssueCommentReaction
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
|
projectId={comment?.project_detail?.id}
|
||||||
|
commentId={comment.id}
|
||||||
|
currentUser={currentUser}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
</IssueCommentBlock>
|
</IssueCommentBlock>
|
||||||
|
@ -40,8 +40,6 @@ export type TActivityOperations = {
|
|||||||
createComment: (data: Partial<TIssueComment>) => Promise<void>;
|
createComment: (data: Partial<TIssueComment>) => Promise<void>;
|
||||||
updateComment: (commentId: string, data: Partial<TIssueComment>) => Promise<void>;
|
updateComment: (commentId: string, data: Partial<TIssueComment>) => Promise<void>;
|
||||||
removeComment: (commentId: string) => Promise<void>;
|
removeComment: (commentId: string) => Promise<void>;
|
||||||
createCommentReaction: (commentId: string, reaction: string) => Promise<void>;
|
|
||||||
removeCommentReaction: (commentId: string, reaction: string) => Promise<void>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
||||||
@ -106,52 +104,8 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createCommentReaction: async (commentId: string, reaction: string) => {
|
|
||||||
try {
|
|
||||||
if (!workspaceSlug || !projectId) throw new Error("Missing fields");
|
|
||||||
await createCommentReaction(workspaceSlug, projectId, commentId, reaction);
|
|
||||||
setToastAlert({
|
|
||||||
title: "Comment reaction added successfully.",
|
|
||||||
type: "success",
|
|
||||||
message: "Comment reaction added successfully.",
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setToastAlert({
|
|
||||||
title: "Comment reaction addition failed.",
|
|
||||||
type: "error",
|
|
||||||
message: "Comment reaction addition failed. Please try again later.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeCommentReaction: async (commentId: string, reaction: string) => {
|
|
||||||
try {
|
|
||||||
if (!workspaceSlug || !projectId) throw new Error("Missing fields");
|
|
||||||
await removeCommentReaction(workspaceSlug, projectId, commentId, reaction);
|
|
||||||
setToastAlert({
|
|
||||||
title: "Comment reaction removed successfully.",
|
|
||||||
type: "success",
|
|
||||||
message: "Comment reaction removed successfully.",
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setToastAlert({
|
|
||||||
title: "Comment reaction removal failed.",
|
|
||||||
type: "error",
|
|
||||||
message: "Comment reaction removal failed. Please try again later.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
[
|
[workspaceSlug, projectId, issueId, createComment, updateComment, removeComment, setToastAlert]
|
||||||
workspaceSlug,
|
|
||||||
projectId,
|
|
||||||
issueId,
|
|
||||||
createComment,
|
|
||||||
updateComment,
|
|
||||||
removeComment,
|
|
||||||
createCommentReaction,
|
|
||||||
removeCommentReaction,
|
|
||||||
setToastAlert,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const componentCommonProps = {
|
const componentCommonProps = {
|
||||||
@ -167,7 +121,7 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||||||
<div className="text-lg text-custom-text-100">Comments/Activity</div>
|
<div className="text-lg text-custom-text-100">Comments/Activity</div>
|
||||||
|
|
||||||
{/* rendering activity */}
|
{/* rendering activity */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-3">
|
||||||
<div className="relative flex items-center gap-1">
|
<div className="relative flex items-center gap-1">
|
||||||
{activityTabs.map((tab) => (
|
{activityTabs.map((tab) => (
|
||||||
<div
|
<div
|
||||||
@ -190,25 +144,25 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||||||
|
|
||||||
<div className="min-h-[200px]">
|
<div className="min-h-[200px]">
|
||||||
{activityTab === "all" ? (
|
{activityTab === "all" ? (
|
||||||
<>
|
<div className="space-y-3">
|
||||||
<IssueActivityCommentRoot {...componentCommonProps} activityOperations={activityOperations} />
|
<IssueActivityCommentRoot {...componentCommonProps} activityOperations={activityOperations} />
|
||||||
<IssueCommentCreateUpdate
|
<IssueCommentCreateUpdate
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
activityOperations={activityOperations}
|
activityOperations={activityOperations}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
) : activityTab === "activity" ? (
|
) : activityTab === "activity" ? (
|
||||||
<IssueActivityRoot {...componentCommonProps} />
|
<IssueActivityRoot {...componentCommonProps} />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<div className="space-y-3">
|
||||||
<IssueCommentRoot {...componentCommonProps} activityOperations={activityOperations} />
|
<IssueCommentRoot {...componentCommonProps} activityOperations={activityOperations} />
|
||||||
<IssueCommentCreateUpdate
|
<IssueCommentCreateUpdate
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
activityOperations={activityOperations}
|
activityOperations={activityOperations}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
118
web/components/issues/issue-detail/reactions/issue-comment.tsx
Normal file
118
web/components/issues/issue-detail/reactions/issue-comment.tsx
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { FC, useMemo } from "react";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// components
|
||||||
|
import { ReactionSelector } from "./reaction-selector";
|
||||||
|
// hooks
|
||||||
|
import { useIssueDetail } from "hooks/store";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
|
// types
|
||||||
|
import { IUser } from "@plane/types";
|
||||||
|
import { renderEmoji } from "helpers/emoji.helper";
|
||||||
|
|
||||||
|
export type TIssueCommentReaction = {
|
||||||
|
workspaceSlug: string;
|
||||||
|
projectId: string;
|
||||||
|
commentId: string;
|
||||||
|
currentUser: IUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IssueCommentReaction: FC<TIssueCommentReaction> = observer((props) => {
|
||||||
|
const { workspaceSlug, projectId, commentId, currentUser } = props;
|
||||||
|
|
||||||
|
// hooks
|
||||||
|
const {
|
||||||
|
commentReaction: { getCommentReactionsByCommentId, commentReactionsByUser },
|
||||||
|
createCommentReaction,
|
||||||
|
removeCommentReaction,
|
||||||
|
} = useIssueDetail();
|
||||||
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
|
const reactionIds = getCommentReactionsByCommentId(commentId);
|
||||||
|
const userReactions = commentReactionsByUser(commentId, currentUser.id).map((r) => r.reaction);
|
||||||
|
|
||||||
|
const issueCommentReactionOperations = useMemo(
|
||||||
|
() => ({
|
||||||
|
create: async (reaction: string) => {
|
||||||
|
try {
|
||||||
|
if (!workspaceSlug || !projectId || !commentId) throw new Error("Missing fields");
|
||||||
|
await createCommentReaction(workspaceSlug, projectId, commentId, reaction);
|
||||||
|
setToastAlert({
|
||||||
|
title: "Reaction created successfully",
|
||||||
|
type: "success",
|
||||||
|
message: "Reaction created successfully",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
setToastAlert({
|
||||||
|
title: "Reaction creation failed",
|
||||||
|
type: "error",
|
||||||
|
message: "Reaction creation failed",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
remove: async (reaction: string) => {
|
||||||
|
try {
|
||||||
|
if (!workspaceSlug || !projectId || !commentId || !currentUser?.id) throw new Error("Missing fields");
|
||||||
|
removeCommentReaction(workspaceSlug, projectId, commentId, reaction, currentUser.id);
|
||||||
|
setToastAlert({
|
||||||
|
title: "Reaction removed successfully",
|
||||||
|
type: "success",
|
||||||
|
message: "Reaction removed successfully",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
setToastAlert({
|
||||||
|
title: "Reaction remove failed",
|
||||||
|
type: "error",
|
||||||
|
message: "Reaction remove failed",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
react: async (reaction: string) => {
|
||||||
|
if (userReactions.includes(reaction)) await issueCommentReactionOperations.remove(reaction);
|
||||||
|
else await issueCommentReactionOperations.create(reaction);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
workspaceSlug,
|
||||||
|
projectId,
|
||||||
|
commentId,
|
||||||
|
currentUser,
|
||||||
|
createCommentReaction,
|
||||||
|
removeCommentReaction,
|
||||||
|
setToastAlert,
|
||||||
|
userReactions,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-4 relative flex items-center gap-1.5">
|
||||||
|
<ReactionSelector
|
||||||
|
size="md"
|
||||||
|
position="top"
|
||||||
|
value={userReactions}
|
||||||
|
onSelect={issueCommentReactionOperations.react}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{reactionIds &&
|
||||||
|
Object.keys(reactionIds || {}).map(
|
||||||
|
(reaction) =>
|
||||||
|
reactionIds[reaction]?.length > 0 && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => issueCommentReactionOperations.react(reaction)}
|
||||||
|
key={reaction}
|
||||||
|
className={`flex h-full items-center gap-1 rounded-md px-2 py-1 text-sm text-custom-text-100 ${
|
||||||
|
userReactions.includes(reaction) ? "bg-custom-primary-100/10" : "bg-custom-background-80"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span>{renderEmoji(reaction)}</span>
|
||||||
|
<span className={userReactions.includes(reaction) ? "text-custom-primary-100" : ""}>
|
||||||
|
{(reactionIds || {})[reaction].length}{" "}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -50,7 +50,7 @@ export const IssueReaction: FC<TIssueReaction> = observer((props) => {
|
|||||||
},
|
},
|
||||||
remove: async (reaction: string) => {
|
remove: async (reaction: string) => {
|
||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
|
if (!workspaceSlug || !projectId || !issueId || !currentUser?.id) throw new Error("Missing fields");
|
||||||
await removeReaction(workspaceSlug, projectId, issueId, reaction, currentUser.id);
|
await removeReaction(workspaceSlug, projectId, issueId, reaction, currentUser.id);
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
title: "Reaction removed successfully",
|
title: "Reaction removed successfully",
|
||||||
|
@ -101,6 +101,7 @@ export class IssueCommentStore implements IIssueCommentStore {
|
|||||||
return uniq(concat(_commentIds, commentIds));
|
return uniq(concat(_commentIds, commentIds));
|
||||||
});
|
});
|
||||||
comments.forEach((comment) => {
|
comments.forEach((comment) => {
|
||||||
|
this.rootIssueDetail.commentReaction.applyCommentReactions(comment.id, comment?.comment_reactions || []);
|
||||||
set(this.commentMap, comment.id, comment);
|
set(this.commentMap, comment.id, comment);
|
||||||
});
|
});
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
import { action, makeObservable, observable, runInAction } from "mobx";
|
import { action, makeObservable, observable, runInAction } from "mobx";
|
||||||
import set from "lodash/set";
|
import set from "lodash/set";
|
||||||
|
import update from "lodash/update";
|
||||||
|
import concat from "lodash/concat";
|
||||||
|
import find from "lodash/find";
|
||||||
|
import pull from "lodash/pull";
|
||||||
// services
|
// services
|
||||||
import { IssueReactionService } from "services/issue";
|
import { IssueReactionService } from "services/issue";
|
||||||
// types
|
// types
|
||||||
import { IIssueDetail } from "./root.store";
|
import { IIssueDetail } from "./root.store";
|
||||||
import { TIssueCommentReaction, TIssueCommentReactionIdMap, TIssueCommentReactionMap } from "@plane/types";
|
import { TIssueCommentReaction, TIssueCommentReactionIdMap, TIssueCommentReactionMap } from "@plane/types";
|
||||||
|
// helpers
|
||||||
|
import { groupReactions } from "helpers/emoji.helper";
|
||||||
|
|
||||||
export interface IIssueCommentReactionStoreActions {
|
export interface IIssueCommentReactionStoreActions {
|
||||||
// actions
|
// actions
|
||||||
@ -13,6 +19,7 @@ export interface IIssueCommentReactionStoreActions {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
commentId: string
|
commentId: string
|
||||||
) => Promise<TIssueCommentReaction[]>;
|
) => Promise<TIssueCommentReaction[]>;
|
||||||
|
applyCommentReactions: (commentId: string, commentReactions: TIssueCommentReaction[]) => void;
|
||||||
createCommentReaction: (
|
createCommentReaction: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
@ -23,7 +30,8 @@ export interface IIssueCommentReactionStoreActions {
|
|||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
commentId: string,
|
commentId: string,
|
||||||
reaction: string
|
reaction: string,
|
||||||
|
userId: string
|
||||||
) => Promise<any>;
|
) => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,8 +40,9 @@ export interface IIssueCommentReactionStore extends IIssueCommentReactionStoreAc
|
|||||||
commentReactions: TIssueCommentReactionIdMap;
|
commentReactions: TIssueCommentReactionIdMap;
|
||||||
commentReactionMap: TIssueCommentReactionMap;
|
commentReactionMap: TIssueCommentReactionMap;
|
||||||
// helper methods
|
// helper methods
|
||||||
getCommentReactionsByCommentId: (commentId: string) => string[] | undefined;
|
getCommentReactionsByCommentId: (commentId: string) => { [reaction_id: string]: string[] } | undefined;
|
||||||
getCommentReactionById: (reactionId: string) => TIssueCommentReaction | undefined;
|
getCommentReactionById: (reactionId: string) => TIssueCommentReaction | undefined;
|
||||||
|
commentReactionsByUser: (commentId: string, userId: string) => TIssueCommentReaction[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IssueCommentReactionStore implements IIssueCommentReactionStore {
|
export class IssueCommentReactionStore implements IIssueCommentReactionStore {
|
||||||
@ -52,6 +61,7 @@ export class IssueCommentReactionStore implements IIssueCommentReactionStore {
|
|||||||
commentReactionMap: observable,
|
commentReactionMap: observable,
|
||||||
// actions
|
// actions
|
||||||
fetchCommentReactions: action,
|
fetchCommentReactions: action,
|
||||||
|
applyCommentReactions: action,
|
||||||
createCommentReaction: action,
|
createCommentReaction: action,
|
||||||
removeCommentReaction: action,
|
removeCommentReaction: action,
|
||||||
});
|
});
|
||||||
@ -72,25 +82,66 @@ export class IssueCommentReactionStore implements IIssueCommentReactionStore {
|
|||||||
return this.commentReactionMap[reactionId] ?? undefined;
|
return this.commentReactionMap[reactionId] ?? undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
commentReactionsByUser = (commentId: string, userId: string) => {
|
||||||
|
if (!commentId || !userId) return [];
|
||||||
|
|
||||||
|
const reactions = this.getCommentReactionsByCommentId(commentId);
|
||||||
|
if (!reactions) return [];
|
||||||
|
|
||||||
|
const _userReactions: TIssueCommentReaction[] = [];
|
||||||
|
Object.keys(reactions).forEach((reaction) => {
|
||||||
|
reactions[reaction].map((reactionId) => {
|
||||||
|
const currentReaction = this.getCommentReactionById(reactionId);
|
||||||
|
if (currentReaction && currentReaction.actor === userId) _userReactions.push(currentReaction);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return _userReactions;
|
||||||
|
};
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
fetchCommentReactions = async (workspaceSlug: string, projectId: string, commentId: string) => {
|
fetchCommentReactions = async (workspaceSlug: string, projectId: string, commentId: string) => {
|
||||||
try {
|
try {
|
||||||
const reactions = await this.issueReactionService.listIssueCommentReactions(workspaceSlug, projectId, commentId);
|
const response = await this.issueReactionService.listIssueCommentReactions(workspaceSlug, projectId, commentId);
|
||||||
|
|
||||||
|
const groupedReactions = groupReactions(response || [], "reaction");
|
||||||
|
|
||||||
|
const commentReactionIdsMap: { [reaction: string]: string[] } = {};
|
||||||
|
|
||||||
|
Object.keys(groupedReactions).map((reactionId) => {
|
||||||
|
const reactionIds = (groupedReactions[reactionId] || []).map((reaction) => reaction.id);
|
||||||
|
commentReactionIdsMap[reactionId] = reactionIds;
|
||||||
|
});
|
||||||
|
|
||||||
const reactionIds = reactions.map((reaction) => reaction.id);
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
set(this.commentReactions, commentId, reactionIds);
|
set(this.commentReactions, commentId, commentReactionIdsMap);
|
||||||
reactions.forEach((reaction) => {
|
response.forEach((reaction) => set(this.commentReactionMap, reaction.id, reaction));
|
||||||
set(this.commentReactionMap, reaction.id, reaction);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return reactions;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
applyCommentReactions = (commentId: string, commentReactions: TIssueCommentReaction[]) => {
|
||||||
|
const groupedReactions = groupReactions(commentReactions || [], "reaction");
|
||||||
|
|
||||||
|
const commentReactionIdsMap: { [reaction: string]: string[] } = {};
|
||||||
|
|
||||||
|
Object.keys(groupedReactions).map((reactionId) => {
|
||||||
|
const reactionIds = (groupedReactions[reactionId] || []).map((reaction) => reaction.id);
|
||||||
|
commentReactionIdsMap[reactionId] = reactionIds;
|
||||||
|
});
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
set(this.commentReactions, commentId, commentReactionIdsMap);
|
||||||
|
commentReactions.forEach((reaction) => set(this.commentReactionMap, reaction.id, reaction));
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
createCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) => {
|
createCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await this.issueReactionService.createIssueCommentReaction(workspaceSlug, projectId, commentId, {
|
const response = await this.issueReactionService.createIssueCommentReaction(workspaceSlug, projectId, commentId, {
|
||||||
@ -98,7 +149,10 @@ export class IssueCommentReactionStore implements IIssueCommentReactionStore {
|
|||||||
});
|
});
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.commentReactions[commentId].push(response.id);
|
update(this.commentReactions, [commentId, reaction], (reactionId) => {
|
||||||
|
if (!reactionId) return [response.id];
|
||||||
|
return concat(reactionId, response.id);
|
||||||
|
});
|
||||||
set(this.commentReactionMap, response.id, response);
|
set(this.commentReactionMap, response.id, response);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -108,14 +162,23 @@ export class IssueCommentReactionStore implements IIssueCommentReactionStore {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
removeCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) => {
|
removeCommentReaction = async (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
commentId: string,
|
||||||
|
reaction: string,
|
||||||
|
userId: string
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const reactionIndex = this.commentReactions[commentId].findIndex((_reaction) => _reaction === reaction);
|
const userReactions = this.commentReactionsByUser(commentId, userId);
|
||||||
if (reactionIndex >= 0)
|
const currentReaction = find(userReactions, { actor: userId, reaction: reaction });
|
||||||
|
|
||||||
|
if (currentReaction && currentReaction.id) {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.commentReactions[commentId].splice(reactionIndex, 1);
|
pull(this.commentReactions[commentId][reaction], currentReaction.id);
|
||||||
delete this.commentReactionMap[reaction];
|
delete this.commentReactionMap[reaction];
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const response = await this.issueReactionService.deleteIssueCommentReaction(
|
const response = await this.issueReactionService.deleteIssueCommentReaction(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
IIssueCommentReactionStoreActions,
|
IIssueCommentReactionStoreActions,
|
||||||
} from "./comment_reaction.store";
|
} from "./comment_reaction.store";
|
||||||
|
|
||||||
import { TIssue, TIssueComment, TIssueLink, TIssueRelationTypes } from "@plane/types";
|
import { TIssue, TIssueComment, TIssueCommentReaction, TIssueLink, TIssueRelationTypes } from "@plane/types";
|
||||||
|
|
||||||
export type TPeekIssue = {
|
export type TPeekIssue = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
@ -238,8 +238,15 @@ export class IssueDetail implements IIssueDetail {
|
|||||||
// comment reaction
|
// comment reaction
|
||||||
fetchCommentReactions = async (workspaceSlug: string, projectId: string, commentId: string) =>
|
fetchCommentReactions = async (workspaceSlug: string, projectId: string, commentId: string) =>
|
||||||
this.commentReaction.fetchCommentReactions(workspaceSlug, projectId, commentId);
|
this.commentReaction.fetchCommentReactions(workspaceSlug, projectId, commentId);
|
||||||
|
applyCommentReactions = async (commentId: string, commentReactions: TIssueCommentReaction[]) =>
|
||||||
|
this.commentReaction.applyCommentReactions(commentId, commentReactions);
|
||||||
createCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) =>
|
createCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) =>
|
||||||
this.commentReaction.createCommentReaction(workspaceSlug, projectId, commentId, reaction);
|
this.commentReaction.createCommentReaction(workspaceSlug, projectId, commentId, reaction);
|
||||||
removeCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) =>
|
removeCommentReaction = async (
|
||||||
this.commentReaction.removeCommentReaction(workspaceSlug, projectId, commentId, reaction);
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
commentId: string,
|
||||||
|
reaction: string,
|
||||||
|
userId: string
|
||||||
|
) => this.commentReaction.removeCommentReaction(workspaceSlug, projectId, commentId, reaction, userId);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user