feat: init
This commit is contained in:
231
apps/web/core/store/inbox/inbox-issue.store.ts
Normal file
231
apps/web/core/store/inbox/inbox-issue.store.ts
Normal file
@@ -0,0 +1,231 @@
|
||||
import { clone, set } from "lodash-es";
|
||||
import { makeObservable, observable, runInAction, action } from "mobx";
|
||||
import type {
|
||||
TInboxIssue,
|
||||
TInboxIssueStatus,
|
||||
EInboxIssueSource,
|
||||
TIssue,
|
||||
TInboxDuplicateIssueDetails,
|
||||
} from "@plane/types";
|
||||
import { EInboxIssueStatus } from "@plane/types";
|
||||
// helpers
|
||||
// local db
|
||||
import { addIssueToPersistanceLayer } from "@/local-db/utils/utils";
|
||||
// services
|
||||
import { InboxIssueService } from "@/services/inbox";
|
||||
import { IssueService } from "@/services/issue";
|
||||
// store
|
||||
import type { CoreRootStore } from "../root.store";
|
||||
|
||||
export interface IInboxIssueStore {
|
||||
isLoading: boolean;
|
||||
id: string;
|
||||
status: TInboxIssueStatus;
|
||||
issue: Partial<TIssue>;
|
||||
snoozed_till: Date | undefined;
|
||||
source: EInboxIssueSource | undefined;
|
||||
duplicate_to: string | undefined;
|
||||
created_by: string | undefined;
|
||||
duplicate_issue_detail: TInboxDuplicateIssueDetails | undefined;
|
||||
// actions
|
||||
updateInboxIssueStatus: (status: TInboxIssueStatus) => Promise<void>; // accept, decline
|
||||
updateInboxIssueDuplicateTo: (issueId: string) => Promise<void>; // connecting the inbox issue to the project existing issue
|
||||
updateInboxIssueSnoozeTill: (date: Date | undefined) => Promise<void>; // snooze the issue
|
||||
updateIssue: (issue: Partial<TIssue>) => Promise<void>; // updating the issue
|
||||
updateProjectIssue: (issue: Partial<TIssue>) => Promise<void>; // updating the issue
|
||||
fetchIssueActivity: () => Promise<void>; // fetching the issue activity
|
||||
}
|
||||
|
||||
export class InboxIssueStore implements IInboxIssueStore {
|
||||
// observables
|
||||
isLoading: boolean = false;
|
||||
id: string;
|
||||
status: TInboxIssueStatus = EInboxIssueStatus.PENDING;
|
||||
issue: Partial<TIssue> = {};
|
||||
snoozed_till: Date | undefined;
|
||||
source: EInboxIssueSource | undefined;
|
||||
duplicate_to: string | undefined;
|
||||
created_by: string | undefined;
|
||||
duplicate_issue_detail: TInboxDuplicateIssueDetails | undefined = undefined;
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
// services
|
||||
inboxIssueService;
|
||||
issueService;
|
||||
|
||||
constructor(
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
data: TInboxIssue,
|
||||
private store: CoreRootStore
|
||||
) {
|
||||
this.id = data.id;
|
||||
this.status = data.status;
|
||||
this.issue = data?.issue;
|
||||
this.snoozed_till = data?.snoozed_till || undefined;
|
||||
this.duplicate_to = data?.duplicate_to || undefined;
|
||||
this.created_by = data?.created_by || undefined;
|
||||
this.source = data?.source || undefined;
|
||||
this.duplicate_issue_detail = data?.duplicate_issue_detail || undefined;
|
||||
this.workspaceSlug = workspaceSlug;
|
||||
this.projectId = projectId;
|
||||
// services
|
||||
this.inboxIssueService = new InboxIssueService();
|
||||
this.issueService = new IssueService();
|
||||
// observable variables should be defined after the initialization of the values
|
||||
makeObservable(this, {
|
||||
id: observable,
|
||||
status: observable,
|
||||
issue: observable,
|
||||
snoozed_till: observable,
|
||||
duplicate_to: observable,
|
||||
duplicate_issue_detail: observable,
|
||||
created_by: observable,
|
||||
source: observable,
|
||||
// actions
|
||||
updateInboxIssueStatus: action,
|
||||
updateInboxIssueDuplicateTo: action,
|
||||
updateInboxIssueSnoozeTill: action,
|
||||
updateIssue: action,
|
||||
updateProjectIssue: action,
|
||||
fetchIssueActivity: action,
|
||||
});
|
||||
}
|
||||
|
||||
updateInboxIssueStatus = async (status: TInboxIssueStatus) => {
|
||||
const previousData: Partial<TInboxIssue> = {
|
||||
status: this.status,
|
||||
};
|
||||
|
||||
try {
|
||||
if (!this.issue.id) return;
|
||||
|
||||
const inboxIssue = await this.inboxIssueService.update(this.workspaceSlug, this.projectId, this.issue.id, {
|
||||
status: status,
|
||||
});
|
||||
runInAction(() => set(this, "status", inboxIssue?.status));
|
||||
|
||||
// If issue accepted sync issue to local db
|
||||
if (status === EInboxIssueStatus.ACCEPTED) {
|
||||
const updatedIssue = { ...this.issue, ...inboxIssue.issue };
|
||||
this.store.issue.issues.addIssue([updatedIssue]);
|
||||
await addIssueToPersistanceLayer(updatedIssue);
|
||||
}
|
||||
} catch {
|
||||
runInAction(() => set(this, "status", previousData.status));
|
||||
}
|
||||
};
|
||||
|
||||
updateInboxIssueDuplicateTo = async (issueId: string) => {
|
||||
const inboxStatus = EInboxIssueStatus.DUPLICATE;
|
||||
const previousData: Partial<TInboxIssue> = {
|
||||
status: this.status,
|
||||
duplicate_to: this.duplicate_to,
|
||||
duplicate_issue_detail: this.duplicate_issue_detail,
|
||||
};
|
||||
try {
|
||||
if (!this.issue.id) return;
|
||||
const inboxIssue = await this.inboxIssueService.update(this.workspaceSlug, this.projectId, this.issue.id, {
|
||||
status: inboxStatus,
|
||||
duplicate_to: issueId,
|
||||
});
|
||||
runInAction(() => {
|
||||
set(this, "status", inboxIssue?.status);
|
||||
set(this, "duplicate_to", inboxIssue?.duplicate_to);
|
||||
set(this, "duplicate_issue_detail", inboxIssue?.duplicate_issue_detail);
|
||||
});
|
||||
} catch {
|
||||
runInAction(() => {
|
||||
set(this, "status", previousData.status);
|
||||
set(this, "duplicate_to", previousData.duplicate_to);
|
||||
set(this, "duplicate_issue_detail", previousData.duplicate_issue_detail);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
updateInboxIssueSnoozeTill = async (date: Date | undefined) => {
|
||||
const inboxStatus = date ? EInboxIssueStatus.SNOOZED : EInboxIssueStatus.PENDING;
|
||||
const previousData: Partial<TInboxIssue> = {
|
||||
status: this.status,
|
||||
snoozed_till: this.snoozed_till,
|
||||
};
|
||||
try {
|
||||
if (!this.issue.id) return;
|
||||
const inboxIssue = await this.inboxIssueService.update(this.workspaceSlug, this.projectId, this.issue.id, {
|
||||
status: inboxStatus,
|
||||
snoozed_till: date ? new Date(date) : null,
|
||||
});
|
||||
runInAction(() => {
|
||||
set(this, "status", inboxIssue?.status);
|
||||
set(this, "snoozed_till", inboxIssue?.snoozed_till);
|
||||
});
|
||||
} catch {
|
||||
runInAction(() => {
|
||||
set(this, "status", previousData.status);
|
||||
set(this, "snoozed_till", previousData.snoozed_till);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
updateIssue = async (issue: Partial<TIssue>) => {
|
||||
const inboxIssue = clone(this.issue);
|
||||
try {
|
||||
if (!this.issue.id) return;
|
||||
Object.keys(issue).forEach((key) => {
|
||||
const issueKey = key as keyof TIssue;
|
||||
set(this.issue, issueKey, issue[issueKey]);
|
||||
});
|
||||
await this.inboxIssueService.updateIssue(this.workspaceSlug, this.projectId, this.issue.id, issue);
|
||||
// fetching activity
|
||||
this.fetchIssueActivity();
|
||||
} catch {
|
||||
Object.keys(issue).forEach((key) => {
|
||||
const issueKey = key as keyof TIssue;
|
||||
set(this.issue, issueKey, inboxIssue[issueKey]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
updateProjectIssue = async (issue: Partial<TIssue>) => {
|
||||
const inboxIssue = clone(this.issue);
|
||||
try {
|
||||
if (!this.issue.id) return;
|
||||
Object.keys(issue).forEach((key) => {
|
||||
const issueKey = key as keyof TIssue;
|
||||
set(this.issue, issueKey, issue[issueKey]);
|
||||
});
|
||||
await this.issueService.patchIssue(this.workspaceSlug, this.projectId, this.issue.id, issue);
|
||||
if (issue.cycle_id) {
|
||||
await this.store.issue.issueDetail.addIssueToCycle(this.workspaceSlug, this.projectId, issue.cycle_id, [
|
||||
this.issue.id,
|
||||
]);
|
||||
}
|
||||
if (issue.module_ids) {
|
||||
await this.store.issue.issueDetail.changeModulesInIssue(
|
||||
this.workspaceSlug,
|
||||
this.projectId,
|
||||
this.issue.id,
|
||||
issue.module_ids,
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
// fetching activity
|
||||
this.fetchIssueActivity();
|
||||
} catch {
|
||||
Object.keys(issue).forEach((key) => {
|
||||
const issueKey = key as keyof TIssue;
|
||||
set(this.issue, issueKey, inboxIssue[issueKey]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
fetchIssueActivity = async () => {
|
||||
try {
|
||||
if (!this.issue.id) return;
|
||||
await this.store.issue.issueDetail.fetchActivities(this.workspaceSlug, this.projectId, this.issue.id);
|
||||
} catch {
|
||||
console.error("Failed to fetch issue activity");
|
||||
}
|
||||
};
|
||||
}
|
||||
507
apps/web/core/store/inbox/project-inbox.store.ts
Normal file
507
apps/web/core/store/inbox/project-inbox.store.ts
Normal file
@@ -0,0 +1,507 @@
|
||||
import { uniq, update, isEmpty, omit, set } from "lodash-es";
|
||||
import { action, computed, makeObservable, observable, runInAction } from "mobx";
|
||||
import { computedFn } from "mobx-utils";
|
||||
import type { EPastDurationFilters } from "@plane/constants";
|
||||
// types
|
||||
import type {
|
||||
TInboxIssue,
|
||||
TInboxIssueCurrentTab,
|
||||
TInboxIssueFilter,
|
||||
TInboxIssueSorting,
|
||||
TInboxIssuePaginationInfo,
|
||||
TInboxIssueSortingOrderByQueryParam,
|
||||
} from "@plane/types";
|
||||
import { EInboxIssueCurrentTab, EInboxIssueStatus } from "@plane/types";
|
||||
import { getCustomDates } from "@plane/utils";
|
||||
// helpers
|
||||
// services
|
||||
import { InboxIssueService } from "@/services/inbox";
|
||||
// root store
|
||||
import type { IInboxIssueStore } from "@/store/inbox/inbox-issue.store";
|
||||
import { InboxIssueStore } from "@/store/inbox/inbox-issue.store";
|
||||
import type { CoreRootStore } from "../root.store";
|
||||
|
||||
type TLoader =
|
||||
| "init-loading"
|
||||
| "mutation-loading"
|
||||
| "filter-loading"
|
||||
| "pagination-loading"
|
||||
| "issue-loading"
|
||||
| undefined;
|
||||
|
||||
export interface IProjectInboxStore {
|
||||
currentTab: TInboxIssueCurrentTab;
|
||||
loader: TLoader;
|
||||
error: { message: string; status: "init-error" | "pagination-error" } | undefined;
|
||||
currentInboxProjectId: string;
|
||||
filtersMap: Record<string, Partial<TInboxIssueFilter>>; // projectId -> Partial<TInboxIssueFilter>
|
||||
sortingMap: Record<string, Partial<TInboxIssueSorting>>; // projectId -> Partial<TInboxIssueSorting>
|
||||
inboxIssuePaginationInfo: TInboxIssuePaginationInfo | undefined;
|
||||
inboxIssues: Record<string, IInboxIssueStore>; // issue_id -> IInboxIssueStore
|
||||
inboxIssueIds: string[];
|
||||
// computed
|
||||
inboxFilters: Partial<TInboxIssueFilter>; // computed project inbox filters
|
||||
inboxSorting: Partial<TInboxIssueSorting>; // computed project inbox sorting
|
||||
getAppliedFiltersCount: number;
|
||||
filteredInboxIssueIds: string[];
|
||||
// computed functions
|
||||
getIssueInboxByIssueId: (issueId: string) => IInboxIssueStore;
|
||||
getIsIssueAvailable: (inboxIssueId: string) => boolean;
|
||||
// helper actions
|
||||
inboxIssueQueryParams: (
|
||||
inboxFilters: Partial<TInboxIssueFilter>,
|
||||
inboxSorting: Partial<TInboxIssueSorting>,
|
||||
pagePerCount: number,
|
||||
paginationCursor: string
|
||||
) => Partial<Record<keyof TInboxIssueFilter, string>>;
|
||||
createOrUpdateInboxIssue: (inboxIssues: TInboxIssue[], workspaceSlug: string, projectId: string) => void;
|
||||
initializeDefaultFilters: (projectId: string, tab: TInboxIssueCurrentTab) => void;
|
||||
// actions
|
||||
handleCurrentTab: (workspaceSlug: string, projectId: string, tab: TInboxIssueCurrentTab) => void;
|
||||
handleInboxIssueFilters: <T extends keyof TInboxIssueFilter>(key: T, value: TInboxIssueFilter[T]) => void; // if user sends me undefined, I will remove the value from the filter key
|
||||
handleInboxIssueSorting: <T extends keyof TInboxIssueSorting>(key: T, value: TInboxIssueSorting[T]) => void; // if user sends me undefined, I will remove the value from the filter key
|
||||
fetchInboxIssues: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
loadingType?: TLoader,
|
||||
tab?: TInboxIssueCurrentTab | undefined
|
||||
) => Promise<void>;
|
||||
fetchInboxPaginationIssues: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
fetchInboxIssueById: (workspaceSlug: string, projectId: string, inboxIssueId: string) => Promise<TInboxIssue>;
|
||||
createInboxIssue: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
data: Partial<TInboxIssue>
|
||||
) => Promise<TInboxIssue | undefined>;
|
||||
deleteInboxIssue: (workspaceSlug: string, projectId: string, inboxIssueId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export class ProjectInboxStore implements IProjectInboxStore {
|
||||
// constants
|
||||
PER_PAGE_COUNT = 10;
|
||||
// observables
|
||||
currentTab: TInboxIssueCurrentTab = EInboxIssueCurrentTab.OPEN;
|
||||
loader: TLoader = "init-loading";
|
||||
error: { message: string; status: "init-error" | "pagination-error" } | undefined = undefined;
|
||||
currentInboxProjectId: string = "";
|
||||
filtersMap: Record<string, Partial<TInboxIssueFilter>> = {};
|
||||
sortingMap: Record<string, Partial<TInboxIssueSorting>> = {};
|
||||
inboxIssuePaginationInfo: TInboxIssuePaginationInfo | undefined = undefined;
|
||||
inboxIssues: Record<string, IInboxIssueStore> = {};
|
||||
inboxIssueIds: string[] = [];
|
||||
// services
|
||||
inboxIssueService;
|
||||
|
||||
constructor(private store: CoreRootStore) {
|
||||
makeObservable(this, {
|
||||
currentTab: observable.ref,
|
||||
loader: observable.ref,
|
||||
error: observable,
|
||||
currentInboxProjectId: observable.ref,
|
||||
filtersMap: observable,
|
||||
sortingMap: observable,
|
||||
inboxIssuePaginationInfo: observable,
|
||||
inboxIssues: observable,
|
||||
inboxIssueIds: observable,
|
||||
// computed
|
||||
inboxFilters: computed,
|
||||
inboxSorting: computed,
|
||||
getAppliedFiltersCount: computed,
|
||||
filteredInboxIssueIds: computed,
|
||||
// actions
|
||||
handleInboxIssueFilters: action,
|
||||
handleInboxIssueSorting: action,
|
||||
fetchInboxIssues: action,
|
||||
fetchInboxPaginationIssues: action,
|
||||
fetchInboxIssueById: action,
|
||||
createInboxIssue: action,
|
||||
deleteInboxIssue: action,
|
||||
});
|
||||
this.inboxIssueService = new InboxIssueService();
|
||||
}
|
||||
|
||||
// computed
|
||||
/**
|
||||
* @description computed project inbox filters
|
||||
*/
|
||||
get inboxFilters() {
|
||||
const { projectId } = this.store.router;
|
||||
if (!projectId) return {} as TInboxIssueFilter;
|
||||
return this.filtersMap?.[projectId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description computed project inbox sorting
|
||||
*/
|
||||
get inboxSorting() {
|
||||
const { projectId } = this.store.router;
|
||||
if (!projectId) return {} as TInboxIssueSorting;
|
||||
return this.sortingMap?.[projectId];
|
||||
}
|
||||
|
||||
get getAppliedFiltersCount() {
|
||||
let count = 0;
|
||||
this.inboxFilters != undefined &&
|
||||
Object.keys(this.inboxFilters).forEach((key) => {
|
||||
const filterKey = key as keyof TInboxIssueFilter;
|
||||
if (this.inboxFilters[filterKey] && this.inboxFilters?.[filterKey])
|
||||
count = count + (this.inboxFilters?.[filterKey]?.length ?? 0);
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
||||
get filteredInboxIssueIds() {
|
||||
let appliedFilters =
|
||||
this.currentTab === EInboxIssueCurrentTab.OPEN
|
||||
? [EInboxIssueStatus.PENDING, EInboxIssueStatus.SNOOZED]
|
||||
: [EInboxIssueStatus.ACCEPTED, EInboxIssueStatus.DECLINED, EInboxIssueStatus.DUPLICATE];
|
||||
appliedFilters = appliedFilters.filter((filter) => this.inboxFilters?.status?.includes(filter));
|
||||
const currentTime = new Date().getTime();
|
||||
|
||||
return this.currentTab === EInboxIssueCurrentTab.OPEN
|
||||
? this.inboxIssueIds.filter((id) => {
|
||||
if (appliedFilters.length == 2) return true;
|
||||
if (appliedFilters[0] === EInboxIssueStatus.SNOOZED)
|
||||
return (
|
||||
this.inboxIssues[id].status === EInboxIssueStatus.SNOOZED &&
|
||||
currentTime < new Date(this.inboxIssues[id].snoozed_till!).getTime()
|
||||
);
|
||||
if (appliedFilters[0] === EInboxIssueStatus.PENDING)
|
||||
return (
|
||||
appliedFilters.includes(this.inboxIssues[id].status) ||
|
||||
(this.inboxIssues[id].status === EInboxIssueStatus.SNOOZED &&
|
||||
currentTime > new Date(this.inboxIssues[id].snoozed_till!).getTime())
|
||||
);
|
||||
})
|
||||
: this.inboxIssueIds.filter((id) => appliedFilters.includes(this.inboxIssues[id].status));
|
||||
}
|
||||
|
||||
getIssueInboxByIssueId = computedFn((issueId: string) => this.inboxIssues?.[issueId]);
|
||||
|
||||
getIsIssueAvailable = computedFn((inboxIssueId: string) => {
|
||||
if (!this.inboxIssueIds) return true;
|
||||
return this.inboxIssueIds.includes(inboxIssueId);
|
||||
});
|
||||
|
||||
inboxIssueQueryParams = (
|
||||
inboxFilters: Partial<TInboxIssueFilter>,
|
||||
inboxSorting: Partial<TInboxIssueSorting>,
|
||||
pagePerCount: number,
|
||||
paginationCursor: string
|
||||
) => {
|
||||
const filters: Partial<Record<keyof TInboxIssueFilter, string>> = {};
|
||||
!isEmpty(inboxFilters) &&
|
||||
Object.keys(inboxFilters).forEach((key) => {
|
||||
const filterKey = key as keyof TInboxIssueFilter;
|
||||
if (inboxFilters[filterKey] && inboxFilters[filterKey]?.length) {
|
||||
if (["created_at", "updated_at"].includes(filterKey) && (inboxFilters[filterKey] || [])?.length > 0) {
|
||||
const appliedDateFilters: string[] = [];
|
||||
inboxFilters[filterKey]?.forEach((value) => {
|
||||
const dateValue = value as EPastDurationFilters;
|
||||
appliedDateFilters.push(getCustomDates(dateValue));
|
||||
});
|
||||
filters[filterKey] = appliedDateFilters?.join(",");
|
||||
} else filters[filterKey] = inboxFilters[filterKey]?.join(",");
|
||||
}
|
||||
});
|
||||
|
||||
const sorting: TInboxIssueSortingOrderByQueryParam = {
|
||||
order_by: "-issue__created_at",
|
||||
};
|
||||
if (inboxSorting?.order_by && inboxSorting?.sort_by) {
|
||||
switch (inboxSorting.order_by) {
|
||||
case "issue__created_at":
|
||||
if (inboxSorting.sort_by === "desc") sorting.order_by = `-issue__created_at`;
|
||||
else sorting.order_by = "issue__created_at";
|
||||
break;
|
||||
case "issue__updated_at":
|
||||
if (inboxSorting.sort_by === "desc") sorting.order_by = `-issue__updated_at`;
|
||||
else sorting.order_by = "issue__updated_at";
|
||||
break;
|
||||
case "issue__sequence_id":
|
||||
if (inboxSorting.sort_by === "desc") sorting.order_by = `-issue__sequence_id`;
|
||||
else sorting.order_by = "issue__sequence_id";
|
||||
break;
|
||||
default:
|
||||
sorting.order_by = "-issue__created_at";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...filters,
|
||||
...sorting,
|
||||
per_page: pagePerCount,
|
||||
cursor: paginationCursor,
|
||||
};
|
||||
};
|
||||
|
||||
createOrUpdateInboxIssue = (inboxIssues: TInboxIssue[], workspaceSlug: string, projectId: string) => {
|
||||
if (inboxIssues && inboxIssues.length > 0) {
|
||||
inboxIssues.forEach((inbox: TInboxIssue) => {
|
||||
const existingInboxIssueDetail = this.getIssueInboxByIssueId(inbox?.issue?.id);
|
||||
if (existingInboxIssueDetail)
|
||||
Object.assign(existingInboxIssueDetail, {
|
||||
...inbox,
|
||||
issue: {
|
||||
...existingInboxIssueDetail.issue,
|
||||
...inbox.issue,
|
||||
},
|
||||
});
|
||||
else
|
||||
set(this.inboxIssues, [inbox?.issue?.id], new InboxIssueStore(workspaceSlug, projectId, inbox, this.store));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// actions
|
||||
handleCurrentTab = (workspaceSlug: string, projectId: string, tab: TInboxIssueCurrentTab) => {
|
||||
if (workspaceSlug && projectId) {
|
||||
runInAction(() => {
|
||||
set(this, "currentTab", tab);
|
||||
set(this, ["inboxIssueIds"], []);
|
||||
set(this, ["inboxIssuePaginationInfo"], undefined);
|
||||
set(this.sortingMap, [projectId], { order_by: "issue__created_at", sort_by: "desc" });
|
||||
set(this.filtersMap, [projectId], {
|
||||
status:
|
||||
tab === EInboxIssueCurrentTab.OPEN
|
||||
? [EInboxIssueStatus.PENDING]
|
||||
: [EInboxIssueStatus.ACCEPTED, EInboxIssueStatus.DECLINED, EInboxIssueStatus.DUPLICATE],
|
||||
});
|
||||
});
|
||||
this.fetchInboxIssues(workspaceSlug, projectId, "filter-loading");
|
||||
}
|
||||
};
|
||||
|
||||
handleInboxIssueFilters = <T extends keyof TInboxIssueFilter>(key: T, value: TInboxIssueFilter[T]) => {
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
if (workspaceSlug && projectId) {
|
||||
runInAction(() => {
|
||||
set(this.filtersMap, [projectId, key], value);
|
||||
set(this, ["inboxIssuePaginationInfo"], undefined);
|
||||
});
|
||||
this.fetchInboxIssues(workspaceSlug, projectId, "filter-loading");
|
||||
}
|
||||
};
|
||||
|
||||
handleInboxIssueSorting = <T extends keyof TInboxIssueSorting>(key: T, value: TInboxIssueSorting[T]) => {
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
if (workspaceSlug && projectId) {
|
||||
runInAction(() => {
|
||||
set(this.sortingMap, [projectId, key], value);
|
||||
set(this, ["inboxIssuePaginationInfo"], undefined);
|
||||
});
|
||||
this.fetchInboxIssues(workspaceSlug, projectId, "filter-loading");
|
||||
}
|
||||
};
|
||||
|
||||
initializeDefaultFilters = (projectId: string, tab: TInboxIssueCurrentTab) => {
|
||||
if (!projectId || !tab) return;
|
||||
if (isEmpty(this.inboxFilters)) {
|
||||
set(this.filtersMap, [projectId], {
|
||||
status:
|
||||
tab === EInboxIssueCurrentTab.OPEN
|
||||
? [EInboxIssueStatus.PENDING]
|
||||
: [EInboxIssueStatus.ACCEPTED, EInboxIssueStatus.DECLINED, EInboxIssueStatus.DUPLICATE],
|
||||
});
|
||||
}
|
||||
if (isEmpty(this.inboxSorting)) {
|
||||
set(this.sortingMap, [projectId], { order_by: "issue__created_at", sort_by: "desc" });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description fetch intake issues with paginated data
|
||||
* @param workspaceSlug
|
||||
* @param projectId
|
||||
*/
|
||||
fetchInboxIssues = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
loadingType: TLoader = undefined,
|
||||
tab: TInboxIssueCurrentTab | undefined = undefined
|
||||
) => {
|
||||
try {
|
||||
if (loadingType === undefined && tab) this.initializeDefaultFilters(projectId, tab);
|
||||
|
||||
if (this.currentInboxProjectId != projectId) {
|
||||
runInAction(() => {
|
||||
set(this, ["currentInboxProjectId"], projectId);
|
||||
set(this, ["inboxIssues"], {});
|
||||
set(this, ["inboxIssueIds"], []);
|
||||
set(this, ["inboxIssuePaginationInfo"], undefined);
|
||||
});
|
||||
}
|
||||
if (Object.keys(this.inboxIssueIds).length === 0) this.loader = "init-loading";
|
||||
else this.loader = "mutation-loading";
|
||||
if (loadingType) this.loader = loadingType;
|
||||
|
||||
const status = this.inboxFilters?.status;
|
||||
const queryParams = this.inboxIssueQueryParams(
|
||||
{ ...this.inboxFilters, status },
|
||||
this.inboxSorting,
|
||||
this.PER_PAGE_COUNT,
|
||||
`${this.PER_PAGE_COUNT}:0:0`
|
||||
);
|
||||
const { results, ...paginationInfo } = await this.inboxIssueService.list(workspaceSlug, projectId, queryParams);
|
||||
|
||||
runInAction(() => {
|
||||
this.loader = undefined;
|
||||
set(this, "inboxIssuePaginationInfo", paginationInfo);
|
||||
if (results) {
|
||||
const issueIds = results.map((value) => value?.issue?.id);
|
||||
set(this, ["inboxIssueIds"], issueIds);
|
||||
this.createOrUpdateInboxIssue(results, workspaceSlug, projectId);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching the intake issues", error);
|
||||
this.loader = undefined;
|
||||
this.error = {
|
||||
message: "Error fetching the intake work items please try again later.",
|
||||
status: "init-error",
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description fetch intake issues with paginated data
|
||||
* @param workspaceSlug
|
||||
* @param projectId
|
||||
*/
|
||||
fetchInboxPaginationIssues = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
if (
|
||||
this.inboxIssuePaginationInfo &&
|
||||
(!this.inboxIssuePaginationInfo?.total_results ||
|
||||
(this.inboxIssuePaginationInfo?.total_results &&
|
||||
this.inboxIssueIds.length < this.inboxIssuePaginationInfo?.total_results))
|
||||
) {
|
||||
const queryParams = this.inboxIssueQueryParams(
|
||||
this.inboxFilters,
|
||||
this.inboxSorting,
|
||||
this.PER_PAGE_COUNT,
|
||||
this.inboxIssuePaginationInfo?.next_cursor || `${this.PER_PAGE_COUNT}:0:0`
|
||||
);
|
||||
const { results, ...paginationInfo } = await this.inboxIssueService.list(workspaceSlug, projectId, queryParams);
|
||||
|
||||
runInAction(() => {
|
||||
set(this, "inboxIssuePaginationInfo", paginationInfo);
|
||||
if (results && results.length > 0) {
|
||||
const issueIds = results.map((value) => value?.issue?.id);
|
||||
update(this, ["inboxIssueIds"], (ids) => uniq([...ids, ...issueIds]));
|
||||
this.createOrUpdateInboxIssue(results, workspaceSlug, projectId);
|
||||
}
|
||||
});
|
||||
} else set(this, ["inboxIssuePaginationInfo", "next_page_results"], false);
|
||||
} catch (error) {
|
||||
console.error("Error fetching the intake issues", error);
|
||||
this.error = {
|
||||
message: "Error fetching the paginated intake work items please try again later.",
|
||||
status: "pagination-error",
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description fetch intake issue with issue id
|
||||
* @param workspaceSlug
|
||||
* @param projectId
|
||||
* @param inboxIssueId
|
||||
*/
|
||||
fetchInboxIssueById = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
inboxIssueId: string
|
||||
): Promise<TInboxIssue> => {
|
||||
try {
|
||||
this.loader = "issue-loading";
|
||||
const inboxIssue = await this.inboxIssueService.retrieve(workspaceSlug, projectId, inboxIssueId);
|
||||
const issueId = inboxIssue?.issue?.id || undefined;
|
||||
|
||||
if (inboxIssue && issueId) {
|
||||
runInAction(() => {
|
||||
this.createOrUpdateInboxIssue([inboxIssue], workspaceSlug, projectId);
|
||||
set(this, "loader", undefined);
|
||||
});
|
||||
await Promise.all([
|
||||
// fetching reactions
|
||||
this.store.issue.issueDetail.fetchReactions(workspaceSlug, projectId, issueId),
|
||||
// fetching activity
|
||||
this.store.issue.issueDetail.fetchActivities(workspaceSlug, projectId, issueId),
|
||||
// fetching comments
|
||||
this.store.issue.issueDetail.fetchComments(workspaceSlug, projectId, issueId),
|
||||
// fetching attachments
|
||||
this.store.issue.issueDetail.fetchAttachments(workspaceSlug, projectId, issueId),
|
||||
]);
|
||||
}
|
||||
return inboxIssue;
|
||||
} catch (error) {
|
||||
console.error("Error fetching the intake issue with intake issue id");
|
||||
this.loader = undefined;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description create intake issue
|
||||
* @param workspaceSlug
|
||||
* @param projectId
|
||||
* @param data
|
||||
*/
|
||||
createInboxIssue = async (workspaceSlug: string, projectId: string, data: Partial<TInboxIssue>) => {
|
||||
try {
|
||||
const inboxIssueResponse = await this.inboxIssueService.create(workspaceSlug, projectId, data);
|
||||
if (inboxIssueResponse)
|
||||
runInAction(() => {
|
||||
update(this, ["inboxIssueIds"], (ids) => [...ids, inboxIssueResponse?.issue?.id]);
|
||||
set(
|
||||
this.inboxIssues,
|
||||
[inboxIssueResponse?.issue?.id],
|
||||
new InboxIssueStore(workspaceSlug, projectId, inboxIssueResponse, this.store)
|
||||
);
|
||||
set(
|
||||
this,
|
||||
["inboxIssuePaginationInfo", "total_results"],
|
||||
(this.inboxIssuePaginationInfo?.total_results || 0) + 1
|
||||
);
|
||||
});
|
||||
return inboxIssueResponse;
|
||||
} catch {
|
||||
console.error("Error creating the intake issue");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description delete intake issue
|
||||
* @param workspaceSlug
|
||||
* @param projectId
|
||||
* @param inboxIssueId
|
||||
*/
|
||||
deleteInboxIssue = async (workspaceSlug: string, projectId: string, inboxIssueId: string) => {
|
||||
const currentIssue = this.inboxIssues?.[inboxIssueId];
|
||||
try {
|
||||
if (!currentIssue) return;
|
||||
await this.inboxIssueService.destroy(workspaceSlug, projectId, inboxIssueId).then(() => {
|
||||
runInAction(() => {
|
||||
set(
|
||||
this,
|
||||
["inboxIssuePaginationInfo", "total_results"],
|
||||
(this.inboxIssuePaginationInfo?.total_results || 0) - 1
|
||||
);
|
||||
set(this, "inboxIssues", omit(this.inboxIssues, inboxIssueId));
|
||||
set(
|
||||
this,
|
||||
["inboxIssueIds"],
|
||||
this.inboxIssueIds.filter((id) => id !== inboxIssueId)
|
||||
);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error removing the intake issue");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user