mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
add modified stores for projects, cycles, modules and views
This commit is contained in:
parent
d0688e5287
commit
31e9705afb
370
web/store/cycle.store.ts
Normal file
370
web/store/cycle.store.ts
Normal file
@ -0,0 +1,370 @@
|
||||
import { action, computed, observable, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { ICycle, TCycleView, CycleDateCheckData } from "types";
|
||||
// mobx
|
||||
import { RootStore } from "store/root.store";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
import { IssueService } from "services/issue";
|
||||
import { CycleService } from "services/cycle.service";
|
||||
|
||||
export interface ICycleStore {
|
||||
loader: boolean;
|
||||
error: any | null;
|
||||
|
||||
cycleView: TCycleView;
|
||||
|
||||
cycleId: string | null;
|
||||
cycleMap: {
|
||||
[projectId: string]: {
|
||||
[cycleId: string]: ICycle;
|
||||
};
|
||||
};
|
||||
cycles: {
|
||||
[projectId: string]: {
|
||||
[filterType: string]: string[];
|
||||
};
|
||||
};
|
||||
|
||||
// computed
|
||||
getCycleById: (cycleId: string) => ICycle | null;
|
||||
projectCycles: string[] | null;
|
||||
projectCompletedCycles: string[] | null;
|
||||
projectUpcomingCycles: string[] | null;
|
||||
projectDraftCycles: string[] | null;
|
||||
|
||||
// actions
|
||||
validateDate: (workspaceSlug: string, projectId: string, payload: CycleDateCheckData) => Promise<any>;
|
||||
|
||||
fetchCycles: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
params: "all" | "current" | "upcoming" | "draft" | "completed" | "incomplete"
|
||||
) => Promise<void>;
|
||||
fetchCycleDetails: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<ICycle>;
|
||||
|
||||
createCycle: (workspaceSlug: string, projectId: string, data: Partial<ICycle>) => Promise<ICycle>;
|
||||
updateCycleDetails: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
cycleId: string,
|
||||
data: Partial<ICycle>
|
||||
) => Promise<ICycle>;
|
||||
deleteCycle: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<void>;
|
||||
|
||||
addCycleToFavorites: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<any>;
|
||||
removeCycleFromFavorites: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export class CycleStore implements ICycleStore {
|
||||
loader: boolean = false;
|
||||
error: any | null = null;
|
||||
|
||||
cycleView: TCycleView = "all";
|
||||
|
||||
cycleId: string | null = null;
|
||||
cycleMap: {
|
||||
[projectId: string]: {
|
||||
[cycleId: string]: ICycle;
|
||||
};
|
||||
} = {};
|
||||
cycles: {
|
||||
[projectId: string]: {
|
||||
[filterType: string]: string[];
|
||||
};
|
||||
} = {};
|
||||
|
||||
// root store
|
||||
rootStore;
|
||||
// services
|
||||
projectService;
|
||||
issueService;
|
||||
cycleService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
loader: observable,
|
||||
error: observable.ref,
|
||||
|
||||
cycleId: observable.ref,
|
||||
cycleMap: observable.ref,
|
||||
cycles: observable.ref,
|
||||
|
||||
// computed
|
||||
projectCycles: computed,
|
||||
projectCompletedCycles: computed,
|
||||
projectUpcomingCycles: computed,
|
||||
projectDraftCycles: computed,
|
||||
|
||||
// actions
|
||||
getCycleById: action,
|
||||
|
||||
fetchCycles: action,
|
||||
fetchCycleDetails: action,
|
||||
|
||||
createCycle: action,
|
||||
updateCycleDetails: action,
|
||||
deleteCycle: action,
|
||||
|
||||
addCycleToFavorites: action,
|
||||
removeCycleFromFavorites: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
this.projectService = new ProjectService();
|
||||
this.issueService = new IssueService();
|
||||
this.cycleService = new CycleService();
|
||||
}
|
||||
|
||||
// computed
|
||||
get projectCycles() {
|
||||
const projectId = this.rootStore.project.projectId;
|
||||
|
||||
if (!projectId) return null;
|
||||
return this.cycles[projectId]?.all || null;
|
||||
}
|
||||
|
||||
get projectCompletedCycles() {
|
||||
const projectId = this.rootStore.project.projectId;
|
||||
|
||||
if (!projectId) return null;
|
||||
|
||||
return this.cycles[projectId]?.completed || null;
|
||||
}
|
||||
|
||||
get projectUpcomingCycles() {
|
||||
const projectId = this.rootStore.project.projectId;
|
||||
|
||||
if (!projectId) return null;
|
||||
|
||||
return this.cycles[projectId]?.upcoming || null;
|
||||
}
|
||||
|
||||
get projectDraftCycles() {
|
||||
const projectId = this.rootStore.project.projectId;
|
||||
|
||||
if (!projectId) return null;
|
||||
|
||||
return this.cycles[projectId]?.draft || null;
|
||||
}
|
||||
|
||||
getCycleById = (cycleId: string) => this.cycleMap[this.rootStore.project][cycleId] || null;
|
||||
|
||||
// actions
|
||||
setCycleView = (_cycleView: TCycleView) => (this.cycleView = _cycleView);
|
||||
|
||||
validateDate = async (workspaceSlug: string, projectId: string, payload: CycleDateCheckData) => {
|
||||
try {
|
||||
const response = await this.cycleService.cycleDateCheck(workspaceSlug, projectId, payload);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to validate cycle dates", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchCycles = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
params: "all" | "current" | "upcoming" | "draft" | "completed" | "incomplete"
|
||||
) => {
|
||||
try {
|
||||
this.loader = true;
|
||||
this.error = null;
|
||||
|
||||
const cyclesResponse = await this.cycleService.getCyclesWithParams(workspaceSlug, projectId, params);
|
||||
|
||||
runInAction(() => {
|
||||
this.cycleMap = {
|
||||
...this.cycleMap,
|
||||
[projectId]: {
|
||||
...this.cycleMap[projectId],
|
||||
...cyclesResponse,
|
||||
},
|
||||
};
|
||||
this.cycles = {
|
||||
...this.cycles,
|
||||
[projectId]: { ...this.cycles[projectId], [params]: Object.keys(cyclesResponse) },
|
||||
};
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch project cycles in project store", error);
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchCycleDetails = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
||||
try {
|
||||
const response = await this.cycleService.getCycleDetails(workspaceSlug, projectId, cycleId);
|
||||
|
||||
runInAction(() => {
|
||||
this.cycleMap = {
|
||||
...this.cycleMap,
|
||||
[projectId]: {
|
||||
...this.cycleMap[projectId],
|
||||
[response?.id]: response,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to fetch cycle detail from cycle store");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
createCycle = async (workspaceSlug: string, projectId: string, data: Partial<ICycle>) => {
|
||||
try {
|
||||
const response = await this.cycleService.createCycle(workspaceSlug, projectId, data);
|
||||
|
||||
runInAction(() => {
|
||||
this.cycleMap = {
|
||||
...this.cycleMap,
|
||||
[projectId]: {
|
||||
...this.cycleMap[projectId],
|
||||
[response?.id]: response,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const _currentView = this.cycleView === "active" ? "current" : this.cycleView;
|
||||
this.fetchCycles(workspaceSlug, projectId, _currentView);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to create cycle from cycle store");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateCycleDetails = async (workspaceSlug: string, projectId: string, cycleId: string, data: Partial<ICycle>) => {
|
||||
try {
|
||||
const _response = await this.cycleService.patchCycle(workspaceSlug, projectId, cycleId, data);
|
||||
|
||||
const currentCycle = this.cycleMap[projectId][cycleId];
|
||||
|
||||
runInAction(() => {
|
||||
this.cycleMap = {
|
||||
...this.cycleMap,
|
||||
[projectId]: {
|
||||
...this.cycleMap[projectId],
|
||||
[cycleId]: { ...currentCycle, ...data },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const _currentView = this.cycleView === "active" ? "current" : this.cycleView;
|
||||
this.fetchCycles(workspaceSlug, projectId, _currentView);
|
||||
|
||||
return _response;
|
||||
} catch (error) {
|
||||
console.log("Failed to patch cycle from cycle store");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
deleteCycle = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
||||
try {
|
||||
const currentProjectCycles = this.cycleMap[projectId];
|
||||
delete currentProjectCycles[cycleId];
|
||||
|
||||
runInAction(() => {
|
||||
this.cycleMap = {
|
||||
...this.cycleMap,
|
||||
[projectId]: currentProjectCycles,
|
||||
};
|
||||
});
|
||||
|
||||
const _response = await this.cycleService.deleteCycle(workspaceSlug, projectId, cycleId);
|
||||
|
||||
return _response;
|
||||
} catch (error) {
|
||||
console.log("Failed to delete cycle from cycle store");
|
||||
|
||||
const _currentView = this.cycleView === "active" ? "current" : this.cycleView;
|
||||
this.fetchCycles(workspaceSlug, projectId, _currentView);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
addCycleToFavorites = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
||||
try {
|
||||
const currentCycle = this.cycleMap[projectId][cycleId];
|
||||
|
||||
if (currentCycle.is_favorite) return;
|
||||
|
||||
runInAction(() => {
|
||||
this.cycleMap = {
|
||||
...this.cycleMap,
|
||||
[projectId]: {
|
||||
...this.cycleMap[projectId],
|
||||
[cycleId]: { ...currentCycle, is_favorite: true },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// updating through api.
|
||||
const response = await this.cycleService.addCycleToFavorites(workspaceSlug, projectId, { cycle: cycleId });
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to add cycle to favorites in the cycles store", error);
|
||||
|
||||
// reset on error
|
||||
const currentCycle = this.cycleMap[projectId][cycleId];
|
||||
|
||||
runInAction(() => {
|
||||
this.cycleMap = {
|
||||
...this.cycleMap,
|
||||
[projectId]: {
|
||||
...this.cycleMap[projectId],
|
||||
[cycleId]: { ...currentCycle, is_favorite: false },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
removeCycleFromFavorites = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
||||
try {
|
||||
const currentCycle = this.cycleMap[projectId][cycleId];
|
||||
|
||||
if (!currentCycle.is_favorite) return;
|
||||
|
||||
runInAction(() => {
|
||||
this.cycleMap = {
|
||||
...this.cycleMap,
|
||||
[projectId]: {
|
||||
...this.cycleMap[projectId],
|
||||
[cycleId]: { ...currentCycle, is_favorite: false },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const response = await this.cycleService.removeCycleFromFavorites(workspaceSlug, projectId, cycleId);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to remove cycle from favorites - Cycle Store", error);
|
||||
|
||||
// reset on error
|
||||
const currentCycle = this.cycleMap[projectId][cycleId];
|
||||
runInAction(() => {
|
||||
this.cycleMap = {
|
||||
...this.cycleMap,
|
||||
[projectId]: {
|
||||
...this.cycleMap[projectId],
|
||||
[cycleId]: { ...currentCycle, is_favorite: true },
|
||||
},
|
||||
};
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
446
web/store/module.store.ts
Normal file
446
web/store/module.store.ts
Normal file
@ -0,0 +1,446 @@
|
||||
import { action, computed, observable, makeObservable, runInAction } from "mobx";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
import { ModuleService } from "services/module.service";
|
||||
// types
|
||||
import { IModule, ILinkDetails } from "types";
|
||||
import { RootStore } from "store/root.store";
|
||||
|
||||
export interface IModuleStore {
|
||||
// states
|
||||
loader: boolean;
|
||||
error: any | null;
|
||||
|
||||
// observables
|
||||
moduleId: string | null;
|
||||
moduleMap: {
|
||||
[project_id: string]: {
|
||||
[module_id: string]: IModule;
|
||||
};
|
||||
};
|
||||
|
||||
// actions
|
||||
getModuleById: (moduleId: string) => IModule | null;
|
||||
|
||||
fetchModules: (workspaceSlug: string, projectId: string) => void;
|
||||
fetchModuleDetails: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<IModule>;
|
||||
|
||||
createModule: (workspaceSlug: string, projectId: string, data: Partial<IModule>) => Promise<IModule>;
|
||||
updateModuleDetails: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
moduleId: string,
|
||||
data: Partial<IModule>
|
||||
) => Promise<IModule>;
|
||||
deleteModule: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
||||
|
||||
createModuleLink: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
moduleId: string,
|
||||
data: Partial<ILinkDetails>
|
||||
) => Promise<ILinkDetails>;
|
||||
updateModuleLink: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
moduleId: string,
|
||||
linkId: string,
|
||||
data: Partial<ILinkDetails>
|
||||
) => Promise<ILinkDetails>;
|
||||
deleteModuleLink: (workspaceSlug: string, projectId: string, moduleId: string, linkId: string) => Promise<void>;
|
||||
|
||||
addModuleToFavorites: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
||||
removeModuleFromFavorites: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
||||
|
||||
// computed
|
||||
projectModules: string[] | null;
|
||||
}
|
||||
|
||||
export class ModulesStore implements IModuleStore {
|
||||
// states
|
||||
loader: boolean = false;
|
||||
error: any | null = null;
|
||||
|
||||
// observables
|
||||
moduleId: string | null = null;
|
||||
moduleMap: {
|
||||
[project_id: string]: {
|
||||
[module_id: string]: IModule;
|
||||
};
|
||||
} = {};
|
||||
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
// services
|
||||
projectService;
|
||||
moduleService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// states
|
||||
loader: observable,
|
||||
error: observable.ref,
|
||||
|
||||
// observables
|
||||
moduleId: observable.ref,
|
||||
moduleMap: observable.ref,
|
||||
|
||||
// actions
|
||||
getModuleById: action,
|
||||
|
||||
fetchModules: action,
|
||||
fetchModuleDetails: action,
|
||||
|
||||
createModule: action,
|
||||
updateModuleDetails: action,
|
||||
deleteModule: action,
|
||||
|
||||
createModuleLink: action,
|
||||
updateModuleLink: action,
|
||||
deleteModuleLink: action,
|
||||
|
||||
addModuleToFavorites: action,
|
||||
removeModuleFromFavorites: action,
|
||||
|
||||
// computed
|
||||
projectModules: computed,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
|
||||
// services
|
||||
this.projectService = new ProjectService();
|
||||
this.moduleService = new ModuleService();
|
||||
}
|
||||
|
||||
// computed
|
||||
get projectModules() {
|
||||
if (!this.rootStore.project.projectId) return null;
|
||||
|
||||
return Object.keys(this.moduleMap[this.rootStore.project.projectId]) || null;
|
||||
}
|
||||
|
||||
getModuleById = (moduleId: string) => this.moduleMap[this.rootStore.project.projectId][moduleId] || null;
|
||||
|
||||
// actions
|
||||
|
||||
fetchModules = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.loader = true;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
const modulesResponse = await this.moduleService.getModules(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: modulesResponse,
|
||||
};
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch modules list in module store", error);
|
||||
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
fetchModuleDetails = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.loader = true;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
const response = await this.moduleService.getModuleDetails(workspaceSlug, projectId, moduleId);
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[moduleId]: response,
|
||||
},
|
||||
};
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch module details in module store", error);
|
||||
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
createModule = async (workspaceSlug: string, projectId: string, data: Partial<IModule>) => {
|
||||
try {
|
||||
const response = await this.moduleService.createModule(workspaceSlug, projectId, data);
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[response.id]: response,
|
||||
},
|
||||
};
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
});
|
||||
this.fetchModules(workspaceSlug, projectId);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("Failed to create module in module store", error);
|
||||
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateModuleDetails = async (workspaceSlug: string, projectId: string, moduleId: string, data: Partial<IModule>) => {
|
||||
try {
|
||||
const currentModule = this.moduleMap[projectId][moduleId];
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[moduleId]: { ...currentModule, ...data },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const response = await this.moduleService.patchModule(workspaceSlug, projectId, moduleId, data);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("Failed to update module in module store", error);
|
||||
|
||||
this.fetchModules(workspaceSlug, projectId);
|
||||
this.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||
|
||||
runInAction(() => {
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
deleteModule = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
||||
try {
|
||||
const currentProjectModules = this.moduleMap[projectId];
|
||||
delete currentProjectModules[moduleId];
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: currentProjectModules,
|
||||
};
|
||||
});
|
||||
|
||||
await this.moduleService.deleteModule(workspaceSlug, projectId, moduleId);
|
||||
} catch (error) {
|
||||
console.error("Failed to delete module in module store", error);
|
||||
|
||||
this.fetchModules(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
this.error = error;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
createModuleLink = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
moduleId: string,
|
||||
data: Partial<ILinkDetails>
|
||||
) => {
|
||||
try {
|
||||
const response = await this.moduleService.createModuleLink(workspaceSlug, projectId, moduleId, data);
|
||||
|
||||
const currentModule = this.moduleMap[projectId][moduleId];
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[moduleId]: { ...currentModule, link_module: [response, ...currentModule.link_module] },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("Failed to create module link in module store", error);
|
||||
|
||||
this.fetchModules(workspaceSlug, projectId);
|
||||
this.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||
|
||||
runInAction(() => {
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateModuleLink = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
moduleId: string,
|
||||
linkId: string,
|
||||
data: Partial<ILinkDetails>
|
||||
) => {
|
||||
try {
|
||||
const response = await this.moduleService.updateModuleLink(workspaceSlug, projectId, moduleId, linkId, data);
|
||||
|
||||
const currentModule = this.moduleMap[projectId][moduleId];
|
||||
const linkModules = currentModule.link_module.map((link) => (link.id === linkId ? response : link));
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[moduleId]: { ...currentModule, link_module: linkModules },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("Failed to update module link in module store", error);
|
||||
|
||||
this.fetchModules(workspaceSlug, projectId);
|
||||
this.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||
|
||||
runInAction(() => {
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
deleteModuleLink = async (workspaceSlug: string, projectId: string, moduleId: string, linkId: string) => {
|
||||
try {
|
||||
const currentModule = this.moduleMap[projectId][moduleId];
|
||||
const linkModules = currentModule.link_module.filter((link) => link.id !== linkId);
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[moduleId]: { ...currentModule, link_module: linkModules },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await this.moduleService.deleteModuleLink(workspaceSlug, projectId, moduleId, linkId);
|
||||
} catch (error) {
|
||||
console.error("Failed to delete module link in module store", error);
|
||||
|
||||
this.fetchModules(workspaceSlug, projectId);
|
||||
this.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||
|
||||
runInAction(() => {
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
addModuleToFavorites = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
||||
try {
|
||||
const currentModule = this.moduleMap[projectId][moduleId];
|
||||
|
||||
if (currentModule.is_favorite) return;
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[moduleId]: { ...currentModule, is_favorite: true },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await this.moduleService.addModuleToFavorites(workspaceSlug, projectId, {
|
||||
module: moduleId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to add module to favorites in module store", error);
|
||||
|
||||
const currentModule = this.moduleMap[projectId][moduleId];
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[moduleId]: { ...currentModule, is_favorite: false },
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
removeModuleFromFavorites = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
||||
try {
|
||||
const currentModule = this.moduleMap[projectId][moduleId];
|
||||
|
||||
if (!currentModule.is_favorite) return;
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[moduleId]: { ...currentModule, is_favorite: false },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await this.moduleService.removeModuleFromFavorites(workspaceSlug, projectId, moduleId);
|
||||
} catch (error) {
|
||||
console.error("Failed to remove module from favorites in module store", error);
|
||||
|
||||
const currentModule = this.moduleMap[projectId][moduleId];
|
||||
|
||||
runInAction(() => {
|
||||
this.moduleMap = {
|
||||
...this.moduleMap,
|
||||
[projectId]: {
|
||||
...this.moduleMap[projectId],
|
||||
[moduleId]: { ...currentModule, is_favorite: true },
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
290
web/store/project-view.store.ts
Normal file
290
web/store/project-view.store.ts
Normal file
@ -0,0 +1,290 @@
|
||||
import { observable, action, makeObservable, runInAction } from "mobx";
|
||||
// services
|
||||
import { ViewService } from "services/view.service";
|
||||
import { RootStore } from "store/root.store";
|
||||
// types
|
||||
import { IProjectView } from "types";
|
||||
|
||||
export interface IProjectViewsStore {
|
||||
// states
|
||||
loader: boolean;
|
||||
error: any | null;
|
||||
|
||||
// observables
|
||||
viewId: string | null;
|
||||
viewMap: {
|
||||
[projectId: string]: {
|
||||
[viewId: string]: IProjectView;
|
||||
};
|
||||
};
|
||||
|
||||
// actions
|
||||
fetchViews: (workspaceSlug: string, projectId: string) => Promise<IProjectView[]>;
|
||||
fetchViewDetails: (workspaceSlug: string, projectId: string, viewId: string) => Promise<IProjectView>;
|
||||
createView: (workspaceSlug: string, projectId: string, data: Partial<IProjectView>) => Promise<IProjectView>;
|
||||
updateView: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
viewId: string,
|
||||
data: Partial<IProjectView>
|
||||
) => Promise<IProjectView>;
|
||||
deleteView: (workspaceSlug: string, projectId: string, viewId: string) => Promise<any>;
|
||||
addViewToFavorites: (workspaceSlug: string, projectId: string, viewId: string) => Promise<any>;
|
||||
removeViewFromFavorites: (workspaceSlug: string, projectId: string, viewId: string) => Promise<any>;
|
||||
}
|
||||
|
||||
export class ProjectViewsStore implements IProjectViewsStore {
|
||||
// states
|
||||
loader: boolean = false;
|
||||
error: any | null = null;
|
||||
|
||||
// observables
|
||||
viewId: string | null = null;
|
||||
viewMap: {
|
||||
[projectId: string]: {
|
||||
[viewId: string]: IProjectView;
|
||||
};
|
||||
} = {};
|
||||
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
// services
|
||||
viewService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// states
|
||||
loader: observable.ref,
|
||||
error: observable.ref,
|
||||
|
||||
// observables
|
||||
viewId: observable.ref,
|
||||
viewMap: observable.ref,
|
||||
|
||||
// actions
|
||||
fetchViews: action,
|
||||
fetchViewDetails: action,
|
||||
createView: action,
|
||||
updateView: action,
|
||||
deleteView: action,
|
||||
addViewToFavorites: action,
|
||||
removeViewFromFavorites: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
|
||||
this.viewService = new ViewService();
|
||||
}
|
||||
|
||||
setViewId = (viewId: string | null) => {
|
||||
this.viewId = viewId;
|
||||
};
|
||||
|
||||
fetchViews = async (workspaceSlug: string, projectId: string): Promise<IProjectView[]> => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.loader = true;
|
||||
});
|
||||
|
||||
const response = await this.viewService.getViews(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.viewMap = {
|
||||
...this.viewMap,
|
||||
[projectId]: response,
|
||||
};
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchViewDetails = async (workspaceSlug: string, projectId: string, viewId: string): Promise<IProjectView> => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.loader = true;
|
||||
});
|
||||
|
||||
const response = await this.viewService.getViewDetails(workspaceSlug, projectId, viewId);
|
||||
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.viewMap = {
|
||||
...this.viewMap,
|
||||
[projectId]: {
|
||||
...this.viewMap[projectId],
|
||||
[response.id]: response,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
createView = async (workspaceSlug: string, projectId: string, data: Partial<IProjectView>): Promise<IProjectView> => {
|
||||
try {
|
||||
const response = await this.viewService.createView(workspaceSlug, projectId, data);
|
||||
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.viewMap = {
|
||||
...this.viewMap,
|
||||
[projectId]: {
|
||||
...this.viewMap[projectId],
|
||||
[response.id]: response,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateView = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
viewId: string,
|
||||
data: Partial<IProjectView>
|
||||
): Promise<IProjectView> => {
|
||||
try {
|
||||
const currentView = this.viewMap[projectId][viewId];
|
||||
|
||||
runInAction(() => {
|
||||
this.viewMap = {
|
||||
...this.viewMap,
|
||||
[projectId]: {
|
||||
...this.viewMap[projectId],
|
||||
[viewId]: { ...currentView, ...data },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const response = await this.viewService.patchView(workspaceSlug, projectId, viewId, data);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchViewDetails(workspaceSlug, projectId, viewId);
|
||||
|
||||
runInAction(() => {
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
deleteView = async (workspaceSlug: string, projectId: string, viewId: string): Promise<any> => {
|
||||
try {
|
||||
const currentProjectViews = this.viewMap[projectId];
|
||||
delete currentProjectViews[viewId];
|
||||
|
||||
runInAction(() => {
|
||||
this.viewMap = {
|
||||
...this.viewMap,
|
||||
[projectId]: currentProjectViews,
|
||||
};
|
||||
});
|
||||
|
||||
await this.viewService.deleteView(workspaceSlug, projectId, viewId);
|
||||
} catch (error) {
|
||||
this.fetchViews(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
addViewToFavorites = async (workspaceSlug: string, projectId: string, viewId: string) => {
|
||||
try {
|
||||
const currentView = this.viewMap[projectId][viewId];
|
||||
|
||||
if (currentView.is_favorite) return;
|
||||
|
||||
runInAction(() => {
|
||||
this.viewMap = {
|
||||
...this.viewMap,
|
||||
[projectId]: {
|
||||
...this.viewMap[projectId],
|
||||
[viewId]: { ...currentView, is_favorite: true },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await this.viewService.addViewToFavorites(workspaceSlug, projectId, {
|
||||
view: viewId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to add view to favorites in view store", error);
|
||||
|
||||
const currentView = this.viewMap[projectId][viewId];
|
||||
runInAction(() => {
|
||||
this.viewMap = {
|
||||
...this.viewMap,
|
||||
[projectId]: {
|
||||
...this.viewMap[projectId],
|
||||
[viewId]: { ...currentView, is_favorite: false },
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
removeViewFromFavorites = async (workspaceSlug: string, projectId: string, viewId: string) => {
|
||||
try {
|
||||
const currentView = this.viewMap[projectId][viewId];
|
||||
|
||||
if (!currentView.is_favorite) return;
|
||||
|
||||
runInAction(() => {
|
||||
this.viewMap = {
|
||||
...this.viewMap,
|
||||
[projectId]: {
|
||||
...this.viewMap[projectId],
|
||||
[viewId]: { ...currentView, is_favorite: false },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await this.viewService.removeViewFromFavorites(workspaceSlug, projectId, viewId);
|
||||
} catch (error) {
|
||||
console.error("Failed to remove view from favorites in view store", error);
|
||||
|
||||
const currentView = this.viewMap[projectId][viewId];
|
||||
runInAction(() => {
|
||||
this.viewMap = {
|
||||
...this.viewMap,
|
||||
[projectId]: {
|
||||
...this.viewMap[projectId],
|
||||
[viewId]: { ...currentView, is_favorite: true },
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
13
web/store/project/index.ts
Normal file
13
web/store/project/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { ProjectsStore } from "./projects.store";
|
||||
import { ProjectPublishStore } from "./project-publish.store";
|
||||
import { RootStore } from "store/root.store";
|
||||
|
||||
export class ProjectRootStore {
|
||||
projects: ProjectsStore;
|
||||
publish: ProjectPublishStore;
|
||||
|
||||
constructor(_root: RootStore) {
|
||||
this.projects = new ProjectsStore(_root);
|
||||
this.publish = new ProjectPublishStore(this);
|
||||
}
|
||||
}
|
265
web/store/project/project-publish.store.ts
Normal file
265
web/store/project/project-publish.store.ts
Normal file
@ -0,0 +1,265 @@
|
||||
import { observable, action, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { ProjectRootStore } from "./";
|
||||
// services
|
||||
import { ProjectPublishService } from "services/project";
|
||||
|
||||
export type TProjectPublishViews = "list" | "gantt" | "kanban" | "calendar" | "spreadsheet";
|
||||
|
||||
export type TProjectPublishViewsSettings = {
|
||||
[key in TProjectPublishViews]: boolean;
|
||||
};
|
||||
|
||||
export interface IProjectPublishSettings {
|
||||
id?: string;
|
||||
project?: string;
|
||||
comments: boolean;
|
||||
reactions: boolean;
|
||||
votes: boolean;
|
||||
views: TProjectPublishViewsSettings;
|
||||
inbox: string | null;
|
||||
}
|
||||
|
||||
export interface IProjectPublishStore {
|
||||
generalLoader: boolean;
|
||||
fetchSettingsLoader: boolean;
|
||||
error: any | null;
|
||||
|
||||
projectPublishSettings: IProjectPublishSettings | "not-initialized";
|
||||
|
||||
getProjectSettingsAsync: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
publishProject: (workspaceSlug: string, projectId: string, data: IProjectPublishSettings) => Promise<void>;
|
||||
updateProjectSettingsAsync: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
projectPublishId: string,
|
||||
data: IProjectPublishSettings
|
||||
) => Promise<void>;
|
||||
unPublishProject: (workspaceSlug: string, projectId: string, projectPublishId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export class ProjectPublishStore implements IProjectPublishStore {
|
||||
// states
|
||||
generalLoader: boolean = false;
|
||||
fetchSettingsLoader: boolean = false;
|
||||
error: any | null = null;
|
||||
|
||||
// actions
|
||||
project_id: string | null = null;
|
||||
projectPublishSettings: IProjectPublishSettings | "not-initialized" = "not-initialized";
|
||||
|
||||
// root store
|
||||
projectRootStore: ProjectRootStore;
|
||||
|
||||
// services
|
||||
projectPublishService;
|
||||
|
||||
constructor(_projectRootStore: ProjectRootStore) {
|
||||
makeObservable(this, {
|
||||
// states
|
||||
generalLoader: observable,
|
||||
fetchSettingsLoader: observable,
|
||||
error: observable,
|
||||
|
||||
// observables
|
||||
project_id: observable,
|
||||
projectPublishSettings: observable.ref,
|
||||
|
||||
// actions
|
||||
getProjectSettingsAsync: action,
|
||||
publishProject: action,
|
||||
updateProjectSettingsAsync: action,
|
||||
unPublishProject: action,
|
||||
});
|
||||
|
||||
this.projectRootStore = _projectRootStore;
|
||||
|
||||
// services
|
||||
this.projectPublishService = new ProjectPublishService();
|
||||
}
|
||||
|
||||
getProjectSettingsAsync = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.fetchSettingsLoader = true;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
const response = await this.projectPublishService.getProjectSettingsAsync(workspaceSlug, projectId);
|
||||
|
||||
if (response && response.length > 0) {
|
||||
const _projectPublishSettings: IProjectPublishSettings = {
|
||||
id: response[0]?.id,
|
||||
comments: response[0]?.comments,
|
||||
reactions: response[0]?.reactions,
|
||||
votes: response[0]?.votes,
|
||||
views: {
|
||||
list: response[0]?.views?.list || false,
|
||||
kanban: response[0]?.views?.kanban || false,
|
||||
calendar: response[0]?.views?.calendar || false,
|
||||
gantt: response[0]?.views?.gantt || false,
|
||||
spreadsheet: response[0]?.views?.spreadsheet || false,
|
||||
},
|
||||
inbox: response[0]?.inbox || null,
|
||||
project: response[0]?.project || null,
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.projectPublishSettings = _projectPublishSettings;
|
||||
this.fetchSettingsLoader = false;
|
||||
this.error = null;
|
||||
});
|
||||
} else {
|
||||
runInAction(() => {
|
||||
this.projectPublishSettings = "not-initialized";
|
||||
this.fetchSettingsLoader = false;
|
||||
this.error = null;
|
||||
});
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.fetchSettingsLoader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
publishProject = async (workspaceSlug: string, projectId: string, data: IProjectPublishSettings) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.generalLoader = true;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
const response = await this.projectPublishService.createProjectSettingsAsync(workspaceSlug, projectId, data);
|
||||
|
||||
if (response) {
|
||||
const _projectPublishSettings: IProjectPublishSettings = {
|
||||
id: response?.id || null,
|
||||
comments: response?.comments || false,
|
||||
reactions: response?.reactions || false,
|
||||
votes: response?.votes || false,
|
||||
views: { ...response?.views },
|
||||
inbox: response?.inbox || null,
|
||||
project: response?.project || null,
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.projectPublishSettings = _projectPublishSettings;
|
||||
this.projectRootStore.projects.projectsMap = {
|
||||
...this.projectRootStore.projects.projectsMap,
|
||||
[workspaceSlug]: {
|
||||
...this.projectRootStore.projects.projectsMap[workspaceSlug],
|
||||
[projectId]: {
|
||||
...this.projectRootStore.projects.projectsMap[workspaceSlug][projectId],
|
||||
is_deployed: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
this.generalLoader = false;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.generalLoader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
updateProjectSettingsAsync = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
projectPublishId: string,
|
||||
data: IProjectPublishSettings
|
||||
) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.generalLoader = true;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
const response = await this.projectPublishService.updateProjectSettingsAsync(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
projectPublishId,
|
||||
data
|
||||
);
|
||||
|
||||
if (response) {
|
||||
const _projectPublishSettings: IProjectPublishSettings = {
|
||||
id: response?.id || null,
|
||||
comments: response?.comments || false,
|
||||
reactions: response?.reactions || false,
|
||||
votes: response?.votes || false,
|
||||
views: { ...response?.views },
|
||||
inbox: response?.inbox || null,
|
||||
project: response?.project || null,
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.projectPublishSettings = _projectPublishSettings;
|
||||
this.generalLoader = false;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.generalLoader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
unPublishProject = async (workspaceSlug: string, projectId: string, projectPublishId: string) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.generalLoader = true;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
const response = await this.projectPublishService.deleteProjectSettingsAsync(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
projectPublishId
|
||||
);
|
||||
|
||||
runInAction(() => {
|
||||
this.projectPublishSettings = "not-initialized";
|
||||
this.projectRootStore.projects.projectsMap = {
|
||||
...this.projectRootStore.projects.projectsMap,
|
||||
[workspaceSlug]: {
|
||||
...this.projectRootStore.projects.projectsMap[workspaceSlug],
|
||||
[projectId]: {
|
||||
...this.projectRootStore.projects.projectsMap[workspaceSlug][projectId],
|
||||
is_deployed: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
this.generalLoader = false;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.generalLoader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
return error;
|
||||
}
|
||||
};
|
||||
}
|
360
web/store/project/projects.store.ts
Normal file
360
web/store/project/projects.store.ts
Normal file
@ -0,0 +1,360 @@
|
||||
import { observable, action, computed, makeObservable, runInAction } from "mobx";
|
||||
import { IssueLabelService, IssueService } from "services/issue";
|
||||
import { ProjectService, ProjectStateService } from "services/project";
|
||||
import { RootStore } from "store/root.store";
|
||||
|
||||
import { IProject } from "types";
|
||||
|
||||
export interface IProjectsStore {
|
||||
loader: boolean;
|
||||
error: any | null;
|
||||
|
||||
searchQuery: string;
|
||||
projectId: string | null;
|
||||
projectsMap: {
|
||||
[workspaceSlug: string]: {
|
||||
[projectId: string]: IProject; // projectId: project Info
|
||||
};
|
||||
};
|
||||
|
||||
// computed
|
||||
searchedProjects: string[];
|
||||
workspaceProjects: string[] | null;
|
||||
joinedProjects: string[];
|
||||
favoriteProjects: string[];
|
||||
currentProjectDetails: IProject | undefined;
|
||||
|
||||
// actions
|
||||
setSearchQuery: (query: string) => void;
|
||||
getProjectById: (workspaceSlug: string, projectId: string) => IProject | null;
|
||||
|
||||
fetchProjects: (workspaceSlug: string) => Promise<void>;
|
||||
fetchProjectDetails: (workspaceSlug: string, projectId: string) => Promise<any>;
|
||||
|
||||
addProjectToFavorites: (workspaceSlug: string, projectId: string) => Promise<any>;
|
||||
removeProjectFromFavorites: (workspaceSlug: string, projectId: string) => Promise<any>;
|
||||
|
||||
orderProjectsWithSortOrder: (sourceIndex: number, destinationIndex: number, projectId: string) => number;
|
||||
updateProjectView: (workspaceSlug: string, projectId: string, viewProps: any) => Promise<any>;
|
||||
|
||||
createProject: (workspaceSlug: string, data: any) => Promise<any>;
|
||||
updateProject: (workspaceSlug: string, projectId: string, data: Partial<IProject>) => Promise<any>;
|
||||
deleteProject: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export class ProjectsStore implements IProjectsStore {
|
||||
loader: boolean = false;
|
||||
error: any | null = null;
|
||||
|
||||
projectId: string | null = null;
|
||||
searchQuery: string = "";
|
||||
projectsMap: {
|
||||
[workspaceSlug: string]: {
|
||||
[projectId: string]: IProject; // projectId: project Info
|
||||
};
|
||||
};
|
||||
|
||||
// root store
|
||||
rootStore: RootStore;
|
||||
// service
|
||||
projectService;
|
||||
issueLabelService;
|
||||
issueService;
|
||||
stateService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
loader: observable,
|
||||
error: observable,
|
||||
|
||||
searchQuery: observable.ref,
|
||||
projectId: observable.ref,
|
||||
projectsMap: observable.ref,
|
||||
|
||||
// computed
|
||||
searchedProjects: computed,
|
||||
workspaceProjects: computed,
|
||||
|
||||
currentProjectDetails: computed,
|
||||
|
||||
joinedProjects: computed,
|
||||
favoriteProjects: computed,
|
||||
|
||||
// action
|
||||
setSearchQuery: action,
|
||||
fetchProjects: action,
|
||||
fetchProjectDetails: action,
|
||||
|
||||
addProjectToFavorites: action,
|
||||
removeProjectFromFavorites: action,
|
||||
|
||||
orderProjectsWithSortOrder: action,
|
||||
updateProjectView: action,
|
||||
createProject: action,
|
||||
updateProject: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
|
||||
this.projectService = new ProjectService();
|
||||
this.issueService = new IssueService();
|
||||
this.issueLabelService = new IssueLabelService();
|
||||
this.stateService = new ProjectStateService();
|
||||
}
|
||||
|
||||
get searchedProjects() {
|
||||
if (!this.rootStore.workspace.workspaceSlug) return [];
|
||||
|
||||
const currentProjectsMap = this.projectsMap[this.rootStore.workspace.workspaceSlug];
|
||||
const projectIds = Object.keys(currentProjectsMap);
|
||||
return this.searchQuery === ""
|
||||
? projectIds
|
||||
: projectIds?.filter((projectId) => {
|
||||
currentProjectsMap[projectId].name.toLowerCase().includes(this.searchQuery.toLowerCase()) ||
|
||||
currentProjectsMap[projectId].identifier.toLowerCase().includes(this.searchQuery.toLowerCase());
|
||||
});
|
||||
}
|
||||
|
||||
get workspaceProjects() {
|
||||
if (!this.rootStore.workspace.workspaceSlug) return null;
|
||||
const currentProjectsMap = this.projectsMap[this.rootStore.workspace.workspaceSlug];
|
||||
|
||||
const projectIds = Object.keys(currentProjectsMap);
|
||||
if (!projectIds) return null;
|
||||
return projectIds;
|
||||
}
|
||||
|
||||
get currentProjectDetails() {
|
||||
if (!this.projectId || !this.rootStore.workspace.workspaceSlug) return;
|
||||
return this.projectsMap[this.rootStore.workspace.workspaceSlug][this.projectId];
|
||||
}
|
||||
|
||||
get joinedProjects() {
|
||||
if (!this.rootStore.workspace.workspaceSlug) return [];
|
||||
|
||||
const currentProjectsMap = this.projectsMap[this.rootStore.workspace.workspaceSlug];
|
||||
const projectIds = Object.keys(currentProjectsMap);
|
||||
|
||||
return projectIds?.filter((projectId) => currentProjectsMap[projectId].is_member);
|
||||
}
|
||||
|
||||
get favoriteProjects() {
|
||||
if (!this.rootStore.workspace.workspaceSlug) return [];
|
||||
|
||||
const currentProjectsMap = this.projectsMap[this.rootStore.workspace.workspaceSlug];
|
||||
const projectIds = Object.keys(currentProjectsMap);
|
||||
|
||||
return projectIds?.filter((projectId) => currentProjectsMap[projectId].is_favorite);
|
||||
}
|
||||
|
||||
setSearchQuery = (query: string) => {
|
||||
this.searchQuery = query;
|
||||
};
|
||||
|
||||
/**
|
||||
* get Workspace projects using workspace slug
|
||||
* @param workspaceSlug
|
||||
* @returns
|
||||
*
|
||||
*/
|
||||
fetchProjects = async (workspaceSlug: string) => {
|
||||
try {
|
||||
const currentProjectsMap = await this.projectService.getProjects(workspaceSlug);
|
||||
runInAction(() => {
|
||||
this.projectsMap = {
|
||||
...this.projectsMap,
|
||||
[workspaceSlug]: currentProjectsMap,
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Failed to fetch project from workspace store");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchProjectDetails = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const response = await this.projectService.getProject(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
this.projectsMap = {
|
||||
...this.projectsMap,
|
||||
[workspaceSlug]: {
|
||||
...this.projectsMap[workspaceSlug],
|
||||
[projectId]: response,
|
||||
},
|
||||
};
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Error while fetching project details", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
getProjectById = (workspaceSlug: string, projectId: string) => {
|
||||
const currentProjectsMap = this.projectsMap?.[workspaceSlug];
|
||||
if (!currentProjectsMap) return null;
|
||||
|
||||
const projectInfo: IProject | null = currentProjectsMap[projectId] || null;
|
||||
return projectInfo;
|
||||
};
|
||||
|
||||
addProjectToFavorites = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const currentProject = this.projectsMap?.[workspaceSlug]?.[projectId];
|
||||
|
||||
runInAction(() => {
|
||||
this.projectsMap = {
|
||||
...this.projectsMap,
|
||||
[workspaceSlug]: {
|
||||
...this.projectsMap[workspaceSlug],
|
||||
[projectId]: { ...currentProject, is_favorite: true },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const response = await this.projectService.addProjectToFavorites(workspaceSlug, projectId);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to add project to favorite");
|
||||
await this.fetchProjects(workspaceSlug);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
removeProjectFromFavorites = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const currentProject = this.projectsMap?.[workspaceSlug]?.[projectId];
|
||||
|
||||
runInAction(() => {
|
||||
this.projectsMap = {
|
||||
...this.projectsMap,
|
||||
[workspaceSlug]: {
|
||||
...this.projectsMap[workspaceSlug],
|
||||
[projectId]: { ...currentProject, is_favorite: false },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const response = await this.projectService.removeProjectFromFavorites(workspaceSlug, projectId);
|
||||
await this.fetchProjects(workspaceSlug);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to add project to favorite");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
orderProjectsWithSortOrder = (sortIndex: number, destinationIndex: number, projectId: string) => {
|
||||
try {
|
||||
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
|
||||
if (!workspaceSlug) return 0;
|
||||
|
||||
const projectsList = Object.values(this.projectsMap[workspaceSlug] || {}) || [];
|
||||
let updatedSortOrder = projectsList[sortIndex].sort_order;
|
||||
|
||||
if (destinationIndex === 0) updatedSortOrder = (projectsList[0].sort_order as number) - 1000;
|
||||
else if (destinationIndex === projectsList.length - 1)
|
||||
updatedSortOrder = (projectsList[projectsList.length - 1].sort_order as number) + 1000;
|
||||
else {
|
||||
const destinationSortingOrder = projectsList[destinationIndex].sort_order as number;
|
||||
const relativeDestinationSortingOrder =
|
||||
sortIndex < destinationIndex
|
||||
? (projectsList[destinationIndex + 1].sort_order as number)
|
||||
: (projectsList[destinationIndex - 1].sort_order as number);
|
||||
|
||||
updatedSortOrder = (destinationSortingOrder + relativeDestinationSortingOrder) / 2;
|
||||
}
|
||||
|
||||
const currentProject = this.projectsMap?.[workspaceSlug]?.[projectId];
|
||||
|
||||
runInAction(() => {
|
||||
this.projectsMap = {
|
||||
...this.projectsMap,
|
||||
[workspaceSlug]: {
|
||||
...this.projectsMap[workspaceSlug],
|
||||
[projectId]: { ...currentProject, sort_order: updatedSortOrder },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return updatedSortOrder;
|
||||
} catch (error) {
|
||||
console.log("failed to update sort order of the projects");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
updateProjectView = async (workspaceSlug: string, projectId: string, viewProps: any) => {
|
||||
try {
|
||||
const response = await this.projectService.setProjectView(workspaceSlug, projectId, viewProps);
|
||||
await this.fetchProjects(workspaceSlug);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to update sort order of the projects");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
createProject = async (workspaceSlug: string, data: any) => {
|
||||
try {
|
||||
const response = await this.projectService.createProject(workspaceSlug, data);
|
||||
runInAction(() => {
|
||||
this.projectsMap = {
|
||||
...this.projectsMap,
|
||||
[workspaceSlug]: { ...this.projectsMap[workspaceSlug], [response.id]: response },
|
||||
};
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to create project from project store");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateProject = async (workspaceSlug: string, projectId: string, data: Partial<IProject>) => {
|
||||
try {
|
||||
const currentProject = this.projectsMap?.[workspaceSlug]?.[projectId];
|
||||
|
||||
runInAction(() => {
|
||||
this.projectsMap = {
|
||||
...this.projectsMap,
|
||||
[workspaceSlug]: { ...this.projectsMap[workspaceSlug], [projectId]: { ...currentProject, ...data } },
|
||||
};
|
||||
});
|
||||
|
||||
const response = await this.projectService.updateProject(workspaceSlug, projectId, data);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to create project from project store");
|
||||
|
||||
this.fetchProjects(workspaceSlug);
|
||||
this.fetchProjectDetails(workspaceSlug, projectId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
deleteProject = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const workspaceProjects = { ...this.projectsMap[workspaceSlug] };
|
||||
|
||||
delete workspaceProjects[projectId];
|
||||
|
||||
runInAction(() => {
|
||||
this.projectsMap = {
|
||||
...this.projectsMap,
|
||||
[workspaceSlug]: { ...workspaceProjects },
|
||||
};
|
||||
});
|
||||
|
||||
await this.projectService.deleteProject(workspaceSlug, projectId);
|
||||
await this.fetchProjects(workspaceSlug);
|
||||
} catch (error) {
|
||||
console.log("Failed to delete project from project store");
|
||||
this.fetchProjects(workspaceSlug);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
import { enableStaticRendering } from "mobx-react-lite";
|
||||
// root stores
|
||||
import { AppRootStore } from "./application";
|
||||
import { ProjectRootStore } from "./project";
|
||||
import { CycleStore } from "./cycle.store";
|
||||
import { ProjectViewsStore } from "./project-view.store";
|
||||
import { ModulesStore } from "./module.store";
|
||||
|
||||
enableStaticRendering(typeof window === "undefined");
|
||||
|
||||
@ -15,16 +19,16 @@ export class RootStore {
|
||||
|
||||
constructor() {
|
||||
this.app = new AppRootStore();
|
||||
this.user = new UserRootStore();
|
||||
this.workspace = new WorkspaceRootStore();
|
||||
this.project = new ProjectRootStore();
|
||||
this.cycle = new CycleRootStore();
|
||||
this.module = new ModuleRootStore();
|
||||
this.projectView = new ProjectViewRootStore();
|
||||
this.page = new PageRootStore();
|
||||
this.issue = new IssueRootStore();
|
||||
// independent stores
|
||||
this.label = new labelStore();
|
||||
this.state = new stateStore();
|
||||
// this.user = new UserRootStore();
|
||||
// this.workspace = new WorkspaceRootStore();
|
||||
this.project = new ProjectRootStore(this);
|
||||
this.cycle = new CycleStore(this);
|
||||
this.module = new ModulesStore(this);
|
||||
this.projectView = new ProjectViewsStore(this);
|
||||
// this.page = new PageRootStore();
|
||||
// this.issue = new IssueRootStore();
|
||||
// // independent stores
|
||||
// this.label = new labelStore();
|
||||
// this.state = new stateStore();
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { action, computed, observable, makeObservable, runInAction } from "mobx"
|
||||
import { ProjectService } from "services/project";
|
||||
import { ModuleService } from "services/module.service";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
|
||||
import { IIssue, IModule, ILinkDetails } from "types";
|
||||
import {
|
||||
IIssueGroupWithSubGroupsStructure,
|
||||
@ -11,6 +11,7 @@ import {
|
||||
IIssueUnGroupedStructure,
|
||||
} from "../issue/issue.store";
|
||||
import { IBlockUpdateData } from "components/gantt-chart";
|
||||
import { RootStore } from "store/root.store";
|
||||
|
||||
export interface IModuleStore {
|
||||
// states
|
||||
|
Loading…
Reference in New Issue
Block a user