plane/web/store/estimate.store.ts
Prateek Shourya a71491ecb9
fix: estimate order not maintained in create/ update modal. (#3326)
* fix: estimate order not maintained in create/ update modal.

* fix: estimate points mutation on update.
2024-01-08 16:16:45 +05:30

197 lines
6.9 KiB
TypeScript

import { observable, action, makeObservable, runInAction, computed } from "mobx";
import set from "lodash/set";
// services
import { ProjectEstimateService } from "services/project";
// types
import { RootStore } from "store/root.store";
import { IEstimate, IEstimateFormData } from "@plane/types";
export interface IEstimateStore {
// observables
estimates: Record<string, IEstimate[] | null>;
// computed
areEstimatesEnabledForCurrentProject: boolean;
projectEstimates: IEstimate[] | null;
activeEstimateDetails: IEstimate | null;
// computed actions
areEstimatesEnabledForProject: (projectId: string) => boolean;
getEstimatePointValue: (estimateKey: number | null) => string;
getProjectEstimateById: (estimateId: string) => IEstimate | null;
getProjectActiveEstimateDetails: (projectId: string) => IEstimate | null;
// fetch actions
fetchProjectEstimates: (workspaceSlug: string, projectId: string) => Promise<IEstimate[]>;
// crud actions
createEstimate: (workspaceSlug: string, projectId: string, data: IEstimateFormData) => Promise<IEstimate>;
updateEstimate: (
workspaceSlug: string,
projectId: string,
estimateId: string,
data: IEstimateFormData
) => Promise<IEstimate>;
deleteEstimate: (workspaceSlug: string, projectId: string, estimateId: string) => Promise<void>;
}
export class EstimateStore implements IEstimateStore {
// observables
estimates: Record<string, IEstimate[] | null> = {};
// root store
rootStore;
// services
estimateService;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// observables
estimates: observable,
// computed
areEstimatesEnabledForCurrentProject: computed,
projectEstimates: computed,
activeEstimateDetails: computed,
// computed actions
areEstimatesEnabledForProject: action,
getProjectEstimateById: action,
getEstimatePointValue: action,
getProjectActiveEstimateDetails: action,
// actions
fetchProjectEstimates: action,
createEstimate: action,
updateEstimate: action,
deleteEstimate: action,
});
// root store
this.rootStore = _rootStore;
// services
this.estimateService = new ProjectEstimateService();
}
/**
* @description returns true if estimates are enabled for current project, false otherwise
*/
get areEstimatesEnabledForCurrentProject() {
const currentProjectDetails = this.rootStore.projectRoot.project.currentProjectDetails;
if (!currentProjectDetails) return false;
return Boolean(currentProjectDetails?.estimate);
}
/**
* @description returns the list of estimates for current project
*/
get projectEstimates() {
const projectId = this.rootStore.app.router.projectId;
if (!projectId) return null;
return this.estimates?.[projectId] || null;
}
/**
* @description returns the active estimate details for current project
*/
get activeEstimateDetails() {
const currentProjectDetails = this.rootStore.projectRoot.project.currentProjectDetails;
if (!currentProjectDetails || !currentProjectDetails?.estimate) return null;
return this.projectEstimates?.find((estimate) => estimate.id === currentProjectDetails?.estimate) || null;
}
/**
* @description returns true if estimates are enabled for a project using project id
* @param projectId
*/
areEstimatesEnabledForProject = (projectId: string) => {
const projectDetails = this.rootStore.projectRoot.project.getProjectById(projectId);
if (!projectDetails) return false;
return Boolean(projectDetails.estimate) ?? false;
};
/**
* @description returns the point value for the given estimate key to display in the UI
*/
getEstimatePointValue = (estimateKey: number | null) => {
if (estimateKey === null) return "None";
const activeEstimate = this.activeEstimateDetails;
return activeEstimate?.points?.find((point) => point.key === estimateKey)?.value || "None";
};
/**
* @description returns the estimate details for the given estimate id
* @param estimateId
*/
getProjectEstimateById = (estimateId: string) => {
if (!this.projectEstimates) return null;
const estimateInfo = this.projectEstimates?.find((estimate) => estimate.id === estimateId) || null;
return estimateInfo;
};
/**
* @description returns the estimate details for the given estimate id
* @param projectId
*/
getProjectActiveEstimateDetails = (projectId: string) => {
const projectDetails = this.rootStore.projectRoot.project.getProjectById(projectId);
if (!projectDetails || !projectDetails?.estimate) return null;
return this.projectEstimates?.find((estimate) => estimate.id === projectDetails?.estimate) || null;
};
/**
* @description fetches the list of estimates for the given project
* @param workspaceSlug
* @param projectId
*/
fetchProjectEstimates = async (workspaceSlug: string, projectId: string) =>
await this.estimateService.getEstimatesList(workspaceSlug, projectId).then((response) => {
runInAction(() => {
set(this.estimates, projectId, response);
});
return response;
});
/**
* @description creates a new estimate for the given project
* @param workspaceSlug
* @param projectId
* @param data
*/
createEstimate = async (workspaceSlug: string, projectId: string, data: IEstimateFormData) =>
await this.estimateService.createEstimate(workspaceSlug, projectId, data).then((response) => {
const responseEstimate = {
...response.estimate,
points: response.estimate_points,
};
runInAction(() => {
set(this.estimates, projectId, [responseEstimate, ...(this.estimates?.[projectId] || [])]);
});
return response.estimate;
});
/**
* @description updates the given estimate for the given project
* @param workspaceSlug
* @param projectId
* @param estimateId
* @param data
*/
updateEstimate = async (workspaceSlug: string, projectId: string, estimateId: string, data: IEstimateFormData) =>
await this.estimateService.patchEstimate(workspaceSlug, projectId, estimateId, data).then((response) => {
const updatedEstimates = (this.estimates?.[projectId] ?? []).map((estimate) =>
estimate.id === estimateId ? { ...estimate, ...data.estimate, points: [...data.estimate_points] } : estimate
);
runInAction(() => {
set(this.estimates, projectId, updatedEstimates);
});
return response;
});
/**
* @description deletes the given estimate for the given project
* @param workspaceSlug
* @param projectId
* @param estimateId
*/
deleteEstimate = async (workspaceSlug: string, projectId: string, estimateId: string) =>
await this.estimateService.deleteEstimate(workspaceSlug, projectId, estimateId).then(() => {
const updatedEstimates = (this.estimates?.[projectId] ?? []).filter((estimate) => estimate.id !== estimateId);
runInAction(() => {
set(this.estimates, projectId, updatedEstimates);
});
});
}