plane/web/store/issue/issue-details/comment.store.ts
2024-03-19 20:08:35 +05:30

186 lines
5.3 KiB
TypeScript

import concat from "lodash/concat";
import pull from "lodash/pull";
import set from "lodash/set";
import uniq from "lodash/uniq";
import update from "lodash/update";
import { action, makeObservable, observable, runInAction } from "mobx";
// services
import { IssueCommentService } from "@/services/issue";
// types
import { TIssueComment, TIssueCommentMap, TIssueCommentIdMap } from "@plane/types";
import { IIssueDetail } from "./root.store";
export type TCommentLoader = "fetch" | "create" | "update" | "delete" | "mutate" | undefined;
export interface IIssueCommentStoreActions {
fetchComments: (
workspaceSlug: string,
projectId: string,
issueId: string,
loaderType?: TCommentLoader
) => Promise<TIssueComment[]>;
createComment: (
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<TIssueComment>
) => Promise<any>;
updateComment: (
workspaceSlug: string,
projectId: string,
issueId: string,
commentId: string,
data: Partial<TIssueComment>
) => Promise<any>;
removeComment: (workspaceSlug: string, projectId: string, issueId: string, commentId: string) => Promise<any>;
}
export interface IIssueCommentStore extends IIssueCommentStoreActions {
// observables
loader: TCommentLoader;
comments: TIssueCommentIdMap;
commentMap: TIssueCommentMap;
// helper methods
getCommentsByIssueId: (issueId: string) => string[] | undefined;
getCommentById: (activityId: string) => TIssueComment | undefined;
}
export class IssueCommentStore implements IIssueCommentStore {
// observables
loader: TCommentLoader = "fetch";
comments: TIssueCommentIdMap = {};
commentMap: TIssueCommentMap = {};
// root store
rootIssueDetail: IIssueDetail;
// services
issueCommentService;
constructor(rootStore: IIssueDetail) {
makeObservable(this, {
// observables
loader: observable.ref,
comments: observable,
commentMap: observable,
// actions
fetchComments: action,
createComment: action,
updateComment: action,
removeComment: action,
});
// root store
this.rootIssueDetail = rootStore;
// services
this.issueCommentService = new IssueCommentService();
}
// helper methods
getCommentsByIssueId = (issueId: string) => {
if (!issueId) return undefined;
return this.comments[issueId] ?? undefined;
};
getCommentById = (commentId: string) => {
if (!commentId) return undefined;
return this.commentMap[commentId] ?? undefined;
};
fetchComments = async (
workspaceSlug: string,
projectId: string,
issueId: string,
loaderType: TCommentLoader = "fetch"
) => {
try {
this.loader = loaderType;
let props = {};
const _commentIds = this.getCommentsByIssueId(issueId);
if (_commentIds && _commentIds.length > 0) {
const _comment = this.getCommentById(_commentIds[_commentIds.length - 1]);
if (_comment) props = { created_at__gt: _comment.created_at };
}
const comments = await this.issueCommentService.getIssueComments(workspaceSlug, projectId, issueId, props);
const commentIds = comments.map((comment) => comment.id);
runInAction(() => {
update(this.comments, issueId, (_commentIds) => {
if (!_commentIds) return commentIds;
return uniq(concat(_commentIds, commentIds));
});
comments.forEach((comment) => {
this.rootIssueDetail.commentReaction.applyCommentReactions(comment.id, comment?.comment_reactions || []);
set(this.commentMap, comment.id, comment);
});
this.loader = undefined;
});
return comments;
} catch (error) {
throw error;
}
};
createComment = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssueComment>) => {
try {
const response = await this.issueCommentService.createIssueComment(workspaceSlug, projectId, issueId, data);
runInAction(() => {
update(this.comments, issueId, (_commentIds) => {
if (!_commentIds) return [response.id];
return uniq(concat(_commentIds, [response.id]));
});
set(this.commentMap, response.id, response);
});
return response;
} catch (error) {
throw error;
}
};
updateComment = async (
workspaceSlug: string,
projectId: string,
issueId: string,
commentId: string,
data: Partial<TIssueComment>
) => {
try {
runInAction(() => {
Object.keys(data).forEach((key) => {
set(this.commentMap, [commentId, key], data[key as keyof TIssueComment]);
});
});
const response = await this.issueCommentService.patchIssueComment(
workspaceSlug,
projectId,
issueId,
commentId,
data
);
return response;
} catch (error) {
this.rootIssueDetail.activity.fetchActivities(workspaceSlug, projectId, issueId);
throw error;
}
};
removeComment = async (workspaceSlug: string, projectId: string, issueId: string, commentId: string) => {
try {
const response = await this.issueCommentService.deleteIssueComment(workspaceSlug, projectId, issueId, commentId);
runInAction(() => {
pull(this.comments[issueId], commentId);
delete this.commentMap[commentId];
});
return response;
} catch (error) {
throw error;
}
};
}