mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: store changes
This commit is contained in:
parent
9d909d2953
commit
2068f54f1d
@ -11,7 +11,7 @@ export interface IAppConfigStore {
|
||||
fetchAppConfig: () => Promise<any>;
|
||||
}
|
||||
|
||||
class AppConfigStore implements IAppConfigStore {
|
||||
export class AppConfigStore implements IAppConfigStore {
|
||||
// observables
|
||||
envConfig: IAppConfig | null = null;
|
||||
|
||||
@ -43,5 +43,3 @@ class AppConfigStore implements IAppConfigStore {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default AppConfigStore;
|
||||
|
@ -0,0 +1,198 @@
|
||||
import { observable, action, makeObservable, computed } from "mobx";
|
||||
// types
|
||||
import { RootStore } from "../root.store";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
import { PageService } from "services/page.service";
|
||||
|
||||
export enum EProjectStore {
|
||||
PROJECT = "ProjectStore",
|
||||
PROJECT_VIEW = "ProjectViewStore",
|
||||
PROFILE = "ProfileStore",
|
||||
MODULE = "ModuleStore",
|
||||
CYCLE = "CycleStore",
|
||||
}
|
||||
|
||||
export interface ModalData {
|
||||
store: EProjectStore;
|
||||
viewId: string;
|
||||
}
|
||||
|
||||
export interface ICommandPaletteStore {
|
||||
isCommandPaletteOpen: boolean;
|
||||
isShortcutModalOpen: boolean;
|
||||
isCreateProjectModalOpen: boolean;
|
||||
isCreateCycleModalOpen: boolean;
|
||||
isCreateModuleModalOpen: boolean;
|
||||
isCreateViewModalOpen: boolean;
|
||||
isCreatePageModalOpen: boolean;
|
||||
isCreateIssueModalOpen: boolean;
|
||||
isDeleteIssueModalOpen: boolean;
|
||||
isBulkDeleteIssueModalOpen: boolean;
|
||||
|
||||
// computed
|
||||
isAnyModalOpen: boolean;
|
||||
|
||||
toggleCommandPaletteModal: (value?: boolean) => void;
|
||||
toggleShortcutModal: (value?: boolean) => void;
|
||||
toggleCreateProjectModal: (value?: boolean) => void;
|
||||
toggleCreateCycleModal: (value?: boolean) => void;
|
||||
toggleCreateViewModal: (value?: boolean) => void;
|
||||
toggleCreatePageModal: (value?: boolean) => void;
|
||||
toggleCreateIssueModal: (value?: boolean, storeType?: EProjectStore) => void;
|
||||
toggleCreateModuleModal: (value?: boolean) => void;
|
||||
toggleDeleteIssueModal: (value?: boolean) => void;
|
||||
toggleBulkDeleteIssueModal: (value?: boolean) => void;
|
||||
|
||||
createIssueStoreType: EProjectStore;
|
||||
}
|
||||
|
||||
export class CommandPaletteStore implements ICommandPaletteStore {
|
||||
isCommandPaletteOpen: boolean = false;
|
||||
isShortcutModalOpen: boolean = false;
|
||||
isCreateProjectModalOpen: boolean = false;
|
||||
isCreateCycleModalOpen: boolean = false;
|
||||
isCreateModuleModalOpen: boolean = false;
|
||||
isCreateViewModalOpen: boolean = false;
|
||||
isCreatePageModalOpen: boolean = false;
|
||||
isCreateIssueModalOpen: boolean = false;
|
||||
isDeleteIssueModalOpen: boolean = false;
|
||||
isBulkDeleteIssueModalOpen: boolean = false;
|
||||
// root store
|
||||
rootStore;
|
||||
// service
|
||||
projectService;
|
||||
pageService;
|
||||
|
||||
createIssueStoreType: EProjectStore = EProjectStore.PROJECT;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
isCommandPaletteOpen: observable.ref,
|
||||
isShortcutModalOpen: observable.ref,
|
||||
isCreateProjectModalOpen: observable.ref,
|
||||
isCreateCycleModalOpen: observable.ref,
|
||||
isCreateModuleModalOpen: observable.ref,
|
||||
isCreateViewModalOpen: observable.ref,
|
||||
isCreatePageModalOpen: observable.ref,
|
||||
isCreateIssueModalOpen: observable.ref,
|
||||
isDeleteIssueModalOpen: observable.ref,
|
||||
isBulkDeleteIssueModalOpen: observable.ref,
|
||||
// computed
|
||||
isAnyModalOpen: computed,
|
||||
// projectPages: computed,
|
||||
// action
|
||||
toggleCommandPaletteModal: action,
|
||||
toggleShortcutModal: action,
|
||||
toggleCreateProjectModal: action,
|
||||
toggleCreateCycleModal: action,
|
||||
toggleCreateViewModal: action,
|
||||
toggleCreatePageModal: action,
|
||||
toggleCreateIssueModal: action,
|
||||
toggleCreateModuleModal: action,
|
||||
toggleDeleteIssueModal: action,
|
||||
toggleBulkDeleteIssueModal: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
this.projectService = new ProjectService();
|
||||
this.pageService = new PageService();
|
||||
}
|
||||
|
||||
get isAnyModalOpen() {
|
||||
return Boolean(
|
||||
this.isCreateIssueModalOpen ||
|
||||
this.isCreateCycleModalOpen ||
|
||||
this.isCreatePageModalOpen ||
|
||||
this.isCreateProjectModalOpen ||
|
||||
this.isCreateModuleModalOpen ||
|
||||
this.isCreateViewModalOpen ||
|
||||
this.isShortcutModalOpen ||
|
||||
this.isBulkDeleteIssueModalOpen ||
|
||||
this.isDeleteIssueModalOpen
|
||||
);
|
||||
}
|
||||
|
||||
toggleCommandPaletteModal = (value?: boolean) => {
|
||||
if (value !== undefined) {
|
||||
this.isCommandPaletteOpen = value;
|
||||
} else {
|
||||
this.isCommandPaletteOpen = !this.isCommandPaletteOpen;
|
||||
}
|
||||
};
|
||||
|
||||
toggleShortcutModal = (value?: boolean) => {
|
||||
if (value !== undefined) {
|
||||
this.isShortcutModalOpen = value;
|
||||
} else {
|
||||
this.isShortcutModalOpen = !this.isShortcutModalOpen;
|
||||
}
|
||||
};
|
||||
|
||||
toggleCreateProjectModal = (value?: boolean) => {
|
||||
if (value !== undefined) {
|
||||
this.isCreateProjectModalOpen = value;
|
||||
} else {
|
||||
this.isCreateProjectModalOpen = !this.isCreateProjectModalOpen;
|
||||
}
|
||||
};
|
||||
|
||||
toggleCreateCycleModal = (value?: boolean) => {
|
||||
if (value !== undefined) {
|
||||
this.isCreateCycleModalOpen = value;
|
||||
} else {
|
||||
this.isCreateCycleModalOpen = !this.isCreateCycleModalOpen;
|
||||
}
|
||||
};
|
||||
|
||||
toggleCreateViewModal = (value?: boolean) => {
|
||||
if (value !== undefined) {
|
||||
this.isCreateViewModalOpen = value;
|
||||
} else {
|
||||
this.isCreateViewModalOpen = !this.isCreateViewModalOpen;
|
||||
}
|
||||
};
|
||||
|
||||
toggleCreatePageModal = (value?: boolean) => {
|
||||
if (value !== undefined) {
|
||||
this.isCreatePageModalOpen = value;
|
||||
} else {
|
||||
this.isCreatePageModalOpen = !this.isCreatePageModalOpen;
|
||||
}
|
||||
};
|
||||
|
||||
toggleCreateIssueModal = (value?: boolean, storeType?: EProjectStore) => {
|
||||
if (value !== undefined) {
|
||||
this.isCreateIssueModalOpen = value;
|
||||
this.createIssueStoreType = storeType || EProjectStore.PROJECT;
|
||||
} else {
|
||||
this.isCreateIssueModalOpen = !this.isCreateIssueModalOpen;
|
||||
this.createIssueStoreType = EProjectStore.PROJECT;
|
||||
}
|
||||
};
|
||||
|
||||
toggleDeleteIssueModal = (value?: boolean) => {
|
||||
if (value !== undefined) {
|
||||
this.isDeleteIssueModalOpen = value;
|
||||
} else {
|
||||
this.isDeleteIssueModalOpen = !this.isDeleteIssueModalOpen;
|
||||
}
|
||||
};
|
||||
|
||||
toggleCreateModuleModal = (value?: boolean) => {
|
||||
if (value !== undefined) {
|
||||
this.isCreateModuleModalOpen = value;
|
||||
} else {
|
||||
this.isCreateModuleModalOpen = !this.isCreateModuleModalOpen;
|
||||
}
|
||||
};
|
||||
|
||||
toggleBulkDeleteIssueModal = (value?: boolean) => {
|
||||
if (value !== undefined) {
|
||||
this.isBulkDeleteIssueModalOpen = value;
|
||||
} else {
|
||||
this.isBulkDeleteIssueModalOpen = !this.isBulkDeleteIssueModalOpen;
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
import { action, makeObservable, observable } from "mobx";
|
||||
import posthog from "posthog-js";
|
||||
// stores
|
||||
import { RootStore } from "../root.store";
|
||||
|
||||
export interface IEventTrackerStore {
|
||||
trackElement: string;
|
||||
setTrackElement: (element: string) => void;
|
||||
postHogEventTracker: (
|
||||
eventName: string,
|
||||
payload: object | [] | null,
|
||||
group?: { isGrouping: boolean | null; groupType: string | null; gorupId: string | null } | null
|
||||
) => void;
|
||||
}
|
||||
|
||||
export class EventTrackerStore implements IEventTrackerStore {
|
||||
trackElement: string = "";
|
||||
rootStore;
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
trackElement: observable,
|
||||
setTrackElement: action,
|
||||
postHogEventTracker: action,
|
||||
});
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
setTrackElement = (element: string) => {
|
||||
this.trackElement = element;
|
||||
};
|
||||
|
||||
postHogEventTracker = (
|
||||
eventName: string,
|
||||
payload: object | [] | null,
|
||||
group?: { isGrouping: boolean | null; groupType: string | null; gorupId: string | null } | null
|
||||
) => {
|
||||
try {
|
||||
let extras: any = {
|
||||
workspace_name: this.rootStore.workspace.currentWorkspace?.name ?? "",
|
||||
workspace_id: this.rootStore.workspace.currentWorkspace?.id ?? "",
|
||||
workspace_slug: this.rootStore.workspace.currentWorkspace?.slug ?? "",
|
||||
project_name: this.rootStore.project.currentProjectDetails?.name ?? "",
|
||||
project_id: this.rootStore.project.currentProjectDetails?.id ?? "",
|
||||
project_identifier: this.rootStore.project.currentProjectDetails?.identifier ?? "",
|
||||
};
|
||||
if (["PROJECT_CREATED", "PROJECT_UPDATED"].includes(eventName)) {
|
||||
const project_details: any = payload as object;
|
||||
extras = {
|
||||
...extras,
|
||||
project_name: project_details?.name ?? "",
|
||||
project_id: project_details?.id ?? "",
|
||||
project_identifier: project_details?.identifier ?? "",
|
||||
};
|
||||
}
|
||||
|
||||
if (group && group!.isGrouping === true) {
|
||||
posthog?.group(group!.groupType!, group!.gorupId!, {
|
||||
date: new Date(),
|
||||
workspace_id: group!.gorupId,
|
||||
});
|
||||
posthog?.capture(eventName, {
|
||||
...payload,
|
||||
extras: extras,
|
||||
element: this.trackElement ?? "",
|
||||
});
|
||||
} else {
|
||||
posthog?.capture(eventName, {
|
||||
...payload,
|
||||
extras: extras,
|
||||
element: this.trackElement ?? "",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
this.setTrackElement("");
|
||||
};
|
||||
}
|
@ -1,17 +1,25 @@
|
||||
import { RootStore } from "../root.store";
|
||||
import { AppConfigStore } from "./app-config.store";
|
||||
import { CommandPaletteStore } from "./command-palette.store";
|
||||
import { EventTrackerStore } from "./event-tracker.store";
|
||||
import { InstanceStore } from "./instance.store";
|
||||
import { RouterStore } from "./router.store";
|
||||
import { ThemeStore } from "./theme.store";
|
||||
|
||||
export class AppRootStore {
|
||||
config;
|
||||
commandPalette;
|
||||
eventTracker;
|
||||
instance;
|
||||
theme;
|
||||
config: AppConfigStore;
|
||||
commandPalette: CommandPaletteStore;
|
||||
eventTracker: EventTrackerStore;
|
||||
instance: InstanceStore;
|
||||
theme: ThemeStore;
|
||||
router: RouterStore;
|
||||
|
||||
constructor(rootStore: RootStore) {
|
||||
this.config = new ConfigStore(rootStore);
|
||||
this.config = new AppConfigStore(rootStore);
|
||||
this.commandPalette = new CommandPaletteStore(rootStore);
|
||||
this.eventTracker = new EventTrackerStore(rootStore);
|
||||
this.instance = new InstanceStore(rootStore);
|
||||
this.theme = new ThemeStore(rootStore);
|
||||
this.router = new RouterStore();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,178 @@
|
||||
import { observable, action, computed, makeObservable, runInAction } from "mobx";
|
||||
// store
|
||||
import { RootStore } from "../root.store";
|
||||
// types
|
||||
import { IInstance, IInstanceConfiguration, IFormattedInstanceConfiguration, IInstanceAdmin } from "types/instance";
|
||||
// services
|
||||
import { InstanceService } from "services/instance.service";
|
||||
|
||||
export interface IInstanceStore {
|
||||
loader: boolean;
|
||||
error: any | null;
|
||||
// issues
|
||||
instance: IInstance | null;
|
||||
instanceAdmins: IInstanceAdmin[] | null;
|
||||
configurations: IInstanceConfiguration[] | null;
|
||||
// computed
|
||||
formattedConfig: IFormattedInstanceConfiguration | null;
|
||||
// action
|
||||
fetchInstanceInfo: () => Promise<IInstance>;
|
||||
fetchInstanceAdmins: () => Promise<IInstanceAdmin[]>;
|
||||
updateInstanceInfo: (data: Partial<IInstance>) => Promise<IInstance>;
|
||||
fetchInstanceConfigurations: () => Promise<any>;
|
||||
updateInstanceConfigurations: (data: Partial<IFormattedInstanceConfiguration>) => Promise<IInstanceConfiguration[]>;
|
||||
}
|
||||
|
||||
export class InstanceStore implements IInstanceStore {
|
||||
loader: boolean = false;
|
||||
error: any | null = null;
|
||||
instance: IInstance | null = null;
|
||||
instanceAdmins: IInstanceAdmin[] | null = null;
|
||||
configurations: IInstanceConfiguration[] | null = null;
|
||||
// service
|
||||
instanceService;
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
loader: observable.ref,
|
||||
error: observable.ref,
|
||||
instance: observable,
|
||||
instanceAdmins: observable,
|
||||
configurations: observable,
|
||||
// computed
|
||||
formattedConfig: computed,
|
||||
// actions
|
||||
fetchInstanceInfo: action,
|
||||
fetchInstanceAdmins: action,
|
||||
updateInstanceInfo: action,
|
||||
fetchInstanceConfigurations: action,
|
||||
updateInstanceConfigurations: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
this.instanceService = new InstanceService();
|
||||
}
|
||||
|
||||
/**
|
||||
* computed value for instance configurations data for forms.
|
||||
* @returns configurations in the form of {key, value} pair.
|
||||
*/
|
||||
get formattedConfig() {
|
||||
if (!this.configurations) return null;
|
||||
|
||||
return this.configurations?.reduce((formData: IFormattedInstanceConfiguration, config) => {
|
||||
formData[config.key] = config.value;
|
||||
return formData;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch instance info from API
|
||||
*/
|
||||
fetchInstanceInfo = async () => {
|
||||
try {
|
||||
const instance = await this.instanceService.getInstanceInfo();
|
||||
runInAction(() => {
|
||||
this.instance = instance;
|
||||
});
|
||||
return instance;
|
||||
} catch (error) {
|
||||
console.log("Error while fetching the instance info");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* fetch instance admins from API
|
||||
*/
|
||||
fetchInstanceAdmins = async () => {
|
||||
try {
|
||||
const instanceAdmins = await this.instanceService.getInstanceAdmins();
|
||||
runInAction(() => {
|
||||
this.instanceAdmins = instanceAdmins;
|
||||
});
|
||||
return instanceAdmins;
|
||||
} catch (error) {
|
||||
console.log("Error while fetching the instance admins");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* update instance info
|
||||
* @param data
|
||||
*/
|
||||
updateInstanceInfo = async (data: Partial<IInstance>) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.loader = true;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
const response = await this.instanceService.updateInstanceInfo(data);
|
||||
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
this.instance = response;
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* fetch instace configurations from API
|
||||
*/
|
||||
fetchInstanceConfigurations = async () => {
|
||||
try {
|
||||
const configurations = await this.instanceService.getInstanceConfigurations();
|
||||
runInAction(() => {
|
||||
this.configurations = configurations;
|
||||
});
|
||||
return configurations;
|
||||
} catch (error) {
|
||||
console.log("Error while fetching the instance configurations");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* update instance configurations
|
||||
* @param data
|
||||
*/
|
||||
updateInstanceConfigurations = async (data: Partial<IFormattedInstanceConfiguration>) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.loader = true;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
const response = await this.instanceService.updateInstanceConfigurations(data);
|
||||
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
this.configurations = this.configurations ? [...this.configurations, ...response] : response;
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
21
web/store/application/router.store.ts
Normal file
21
web/store/application/router.store.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { action, makeObservable, observable } from "mobx";
|
||||
|
||||
export interface IRouterStore {
|
||||
query: any;
|
||||
setQuery: (query: any) => void;
|
||||
}
|
||||
|
||||
export class RouterStore implements IRouterStore {
|
||||
query = {};
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
query: observable,
|
||||
setQuery: action,
|
||||
});
|
||||
}
|
||||
|
||||
setQuery(query: any) {
|
||||
this.query = query;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
// mobx
|
||||
import { action, observable, makeObservable } from "mobx";
|
||||
// helper
|
||||
import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
|
||||
|
||||
export interface IThemeStore {
|
||||
theme: string | null;
|
||||
sidebarCollapsed: boolean | undefined;
|
||||
toggleSidebar: (collapsed?: boolean) => void;
|
||||
setTheme: (theme: any) => void;
|
||||
}
|
||||
|
||||
export class ThemeStore implements IThemeStore {
|
||||
sidebarCollapsed: boolean | undefined = undefined;
|
||||
theme: string | null = null;
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: any | null = null) {
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
sidebarCollapsed: observable.ref,
|
||||
theme: observable.ref,
|
||||
// action
|
||||
toggleSidebar: action,
|
||||
setTheme: action,
|
||||
// computed
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
toggleSidebar = (collapsed?: boolean) => {
|
||||
if (collapsed === undefined) {
|
||||
this.sidebarCollapsed = !this.sidebarCollapsed;
|
||||
} else {
|
||||
this.sidebarCollapsed = collapsed;
|
||||
}
|
||||
localStorage.setItem("app_sidebar_collapsed", this.sidebarCollapsed.toString());
|
||||
};
|
||||
|
||||
setTheme = async (_theme: { theme: any }) => {
|
||||
try {
|
||||
const currentTheme: string = _theme?.theme?.theme?.toString();
|
||||
|
||||
// updating the local storage theme value
|
||||
localStorage.setItem("theme", currentTheme);
|
||||
// updating the mobx theme value
|
||||
this.theme = currentTheme;
|
||||
|
||||
// applying the theme to platform if the selected theme is custom
|
||||
if (currentTheme === "custom") {
|
||||
const themeSettings = this.rootStore.user.currentUserSettings || null;
|
||||
applyTheme(
|
||||
themeSettings?.theme?.palette !== ",,,,"
|
||||
? themeSettings?.theme?.palette
|
||||
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
|
||||
themeSettings?.theme?.darkPalette
|
||||
);
|
||||
} else unsetCustomCssVariables();
|
||||
} catch (error) {
|
||||
console.error("setting user theme error", error);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { enableStaticRendering } from "mobx-react-lite";
|
||||
// root stores
|
||||
import { AppRootStore } from "./application";
|
||||
import { UserStore } from "./user";
|
||||
|
||||
enableStaticRendering(typeof window === "undefined");
|
||||
|
||||
@ -14,8 +15,8 @@ export class RootStore {
|
||||
projectView;
|
||||
|
||||
constructor() {
|
||||
this.app = new AppRootStore();
|
||||
this.user = new UserRootStore();
|
||||
this.app = new AppRootStore(this);
|
||||
this.user = new UserStore(this);
|
||||
this.workspace = new WorkspaceRootStore();
|
||||
this.project = new ProjectRootStore();
|
||||
this.cycle = new CycleRootStore();
|
||||
|
252
web/store/user/index.ts
Normal file
252
web/store/user/index.ts
Normal file
@ -0,0 +1,252 @@
|
||||
import { action, observable, runInAction, makeObservable, computed } from "mobx";
|
||||
// services
|
||||
import { UserService } from "services/user.service";
|
||||
import { AuthService } from "services/auth.service";
|
||||
// interfaces
|
||||
import { IUser, IUserSettings } from "types/users";
|
||||
// store
|
||||
import { RootStore } from "../root.store";
|
||||
import { UserMembershipStore } from "./user-membership.store";
|
||||
|
||||
export interface IUserStore {
|
||||
loader: boolean;
|
||||
currentUserError: any;
|
||||
|
||||
isUserLoggedIn: boolean | null;
|
||||
currentUser: IUser | null;
|
||||
isUserInstanceAdmin: boolean | null;
|
||||
currentUserSettings: IUserSettings | null;
|
||||
|
||||
dashboardInfo: any;
|
||||
|
||||
fetchCurrentUser: () => Promise<IUser>;
|
||||
fetchCurrentUserInstanceAdminStatus: () => Promise<boolean>;
|
||||
fetchCurrentUserSettings: () => Promise<IUserSettings>;
|
||||
|
||||
fetchUserDashboardInfo: (workspaceSlug: string, month: number) => Promise<any>;
|
||||
|
||||
updateUserOnBoard: () => Promise<void>;
|
||||
updateTourCompleted: () => Promise<void>;
|
||||
updateCurrentUser: (data: Partial<IUser>) => Promise<IUser>;
|
||||
updateCurrentUserTheme: (theme: string) => Promise<IUser>;
|
||||
|
||||
deactivateAccount: () => Promise<void>;
|
||||
signOut: () => Promise<void>;
|
||||
|
||||
membership: UserMembershipStore;
|
||||
}
|
||||
|
||||
export class UserStore implements IUserStore {
|
||||
loader: boolean = false;
|
||||
currentUserError: any = null;
|
||||
|
||||
isUserLoggedIn: boolean | null = null;
|
||||
currentUser: IUser | null = null;
|
||||
isUserInstanceAdmin: boolean | null = null;
|
||||
currentUserSettings: IUserSettings | null = null;
|
||||
|
||||
dashboardInfo: any = null;
|
||||
membership: UserMembershipStore;
|
||||
|
||||
// root store
|
||||
rootStore;
|
||||
// services
|
||||
userService;
|
||||
authService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
loader: observable.ref,
|
||||
isUserLoggedIn: observable.ref,
|
||||
currentUser: observable,
|
||||
isUserInstanceAdmin: observable.ref,
|
||||
currentUserSettings: observable,
|
||||
dashboardInfo: observable,
|
||||
// action
|
||||
fetchCurrentUser: action,
|
||||
fetchCurrentUserInstanceAdminStatus: action,
|
||||
fetchCurrentUserSettings: action,
|
||||
fetchUserDashboardInfo: action,
|
||||
updateUserOnBoard: action,
|
||||
updateTourCompleted: action,
|
||||
updateCurrentUser: action,
|
||||
updateCurrentUserTheme: action,
|
||||
deactivateAccount: action,
|
||||
signOut: action,
|
||||
});
|
||||
this.rootStore = _rootStore;
|
||||
this.userService = new UserService();
|
||||
this.authService = new AuthService();
|
||||
this.membership = new UserMembershipStore(_rootStore);
|
||||
}
|
||||
|
||||
fetchCurrentUser = async () => {
|
||||
try {
|
||||
const response = await this.userService.currentUser();
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
this.currentUserError = null;
|
||||
this.currentUser = response;
|
||||
this.isUserLoggedIn = true;
|
||||
});
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.currentUserError = error;
|
||||
this.isUserLoggedIn = false;
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchCurrentUserInstanceAdminStatus = async () => {
|
||||
try {
|
||||
const response = await this.userService.currentUserInstanceAdminStatus();
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
this.isUserInstanceAdmin = response.is_instance_admin;
|
||||
});
|
||||
}
|
||||
return response.is_instance_admin;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.isUserInstanceAdmin = false;
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchCurrentUserSettings = async () => {
|
||||
try {
|
||||
const response = await this.userService.currentUserSettings();
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
this.currentUserSettings = response;
|
||||
});
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchUserDashboardInfo = async (workspaceSlug: string, month: number) => {
|
||||
try {
|
||||
const response = await this.userService.userWorkspaceDashboard(workspaceSlug, month);
|
||||
runInAction(() => {
|
||||
this.dashboardInfo = response;
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateUserOnBoard = async () => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.currentUser = {
|
||||
...this.currentUser,
|
||||
is_onboarded: true,
|
||||
} as IUser;
|
||||
});
|
||||
|
||||
const user = this.currentUser ?? undefined;
|
||||
|
||||
if (!user) return;
|
||||
|
||||
await this.userService.updateUserOnBoard();
|
||||
} catch (error) {
|
||||
this.fetchCurrentUser();
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateTourCompleted = async () => {
|
||||
try {
|
||||
if (this.currentUser) {
|
||||
runInAction(() => {
|
||||
this.currentUser = {
|
||||
...this.currentUser,
|
||||
is_tour_completed: true,
|
||||
} as IUser;
|
||||
});
|
||||
|
||||
const response = await this.userService.updateUserTourCompleted();
|
||||
|
||||
return response;
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateCurrentUser = async (data: Partial<IUser>) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.currentUser = {
|
||||
...this.currentUser,
|
||||
...data,
|
||||
} as IUser;
|
||||
});
|
||||
|
||||
const response = await this.userService.updateUser(data);
|
||||
|
||||
runInAction(() => {
|
||||
this.currentUser = response;
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchCurrentUser();
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateCurrentUserTheme = async (theme: string) => {
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.currentUser = {
|
||||
...this.currentUser,
|
||||
theme: {
|
||||
...this.currentUser?.theme,
|
||||
theme,
|
||||
},
|
||||
} as IUser;
|
||||
});
|
||||
const response = await this.userService.updateUser({
|
||||
theme: { ...this.currentUser?.theme, theme },
|
||||
} as IUser);
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
deactivateAccount = async () => {
|
||||
try {
|
||||
await this.userService.deactivateAccount();
|
||||
this.currentUserError = null;
|
||||
this.currentUser = null;
|
||||
this.isUserLoggedIn = false;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
signOut = async () => {
|
||||
try {
|
||||
await this.authService.signOut();
|
||||
runInAction(() => {
|
||||
this.currentUserError = null;
|
||||
this.currentUser = null;
|
||||
this.isUserLoggedIn = false;
|
||||
});
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
229
web/store/user/user-membership.store.ts
Normal file
229
web/store/user/user-membership.store.ts
Normal file
@ -0,0 +1,229 @@
|
||||
// mobx
|
||||
import { action, observable, runInAction, makeObservable, computed } from "mobx";
|
||||
// services
|
||||
import { ProjectMemberService, ProjectService } from "services/project";
|
||||
import { UserService } from "services/user.service";
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
import { AuthService } from "services/auth.service";
|
||||
// interfaces
|
||||
import { IUser, IUserSettings } from "types/users";
|
||||
import { IWorkspaceMemberMe, IProjectMember, TUserProjectRole, TUserWorkspaceRole } from "types";
|
||||
import { RootStore } from "../root.store";
|
||||
|
||||
export interface IUserMembershipStore {
|
||||
workspaceMemberInfo: {
|
||||
[workspaceSlug: string]: IWorkspaceMemberMe;
|
||||
};
|
||||
hasPermissionToWorkspace: {
|
||||
[workspaceSlug: string]: boolean | null;
|
||||
};
|
||||
projectMemberInfo: {
|
||||
[projectId: string]: IProjectMember;
|
||||
};
|
||||
hasPermissionToProject: {
|
||||
[projectId: string]: boolean | null;
|
||||
};
|
||||
|
||||
currentProjectMemberInfo: IProjectMember | undefined;
|
||||
currentWorkspaceMemberInfo: IWorkspaceMemberMe | undefined;
|
||||
currentProjectRole: TUserProjectRole | undefined;
|
||||
currentWorkspaceRole: TUserWorkspaceRole | undefined;
|
||||
|
||||
hasPermissionToCurrentWorkspace: boolean | undefined;
|
||||
hasPermissionToCurrentProject: boolean | undefined;
|
||||
|
||||
fetchUserWorkspaceInfo: (workspaceSlug: string) => Promise<IWorkspaceMemberMe>;
|
||||
fetchUserProjectInfo: (workspaceSlug: string, projectId: string) => Promise<IProjectMember>;
|
||||
|
||||
leaveWorkspace: (workspaceSlug: string) => Promise<void>;
|
||||
joinProject: (workspaceSlug: string, projectIds: string[]) => Promise<any>;
|
||||
leaveProject: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export class UserMembershipStore implements IUserMembershipStore {
|
||||
workspaceMemberInfo: {
|
||||
[workspaceSlug: string]: IWorkspaceMemberMe;
|
||||
} = {};
|
||||
hasPermissionToWorkspace: {
|
||||
[workspaceSlug: string]: boolean;
|
||||
} = {};
|
||||
projectMemberInfo: {
|
||||
[projectId: string]: IProjectMember;
|
||||
} = {};
|
||||
hasPermissionToProject: {
|
||||
[projectId: string]: boolean;
|
||||
} = {};
|
||||
// root store
|
||||
rootStore;
|
||||
// services
|
||||
userService;
|
||||
workspaceService;
|
||||
projectService;
|
||||
projectMemberService;
|
||||
authService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
workspaceMemberInfo: observable.ref,
|
||||
hasPermissionToWorkspace: observable.ref,
|
||||
projectMemberInfo: observable.ref,
|
||||
hasPermissionToProject: observable.ref,
|
||||
// action
|
||||
fetchUserWorkspaceInfo: action,
|
||||
fetchUserProjectInfo: action,
|
||||
leaveWorkspace: action,
|
||||
joinProject: action,
|
||||
leaveProject: action,
|
||||
// computed
|
||||
currentProjectMemberInfo: computed,
|
||||
currentWorkspaceMemberInfo: computed,
|
||||
currentProjectRole: computed,
|
||||
currentWorkspaceRole: computed,
|
||||
hasPermissionToCurrentWorkspace: computed,
|
||||
hasPermissionToCurrentProject: computed,
|
||||
});
|
||||
this.rootStore = _rootStore;
|
||||
this.userService = new UserService();
|
||||
this.workspaceService = new WorkspaceService();
|
||||
this.projectService = new ProjectService();
|
||||
this.projectMemberService = new ProjectMemberService();
|
||||
this.authService = new AuthService();
|
||||
}
|
||||
|
||||
get currentWorkspaceMemberInfo() {
|
||||
if (!this.rootStore.workspace.workspaceSlug) return;
|
||||
return this.workspaceMemberInfo[this.rootStore.workspace.workspaceSlug];
|
||||
}
|
||||
|
||||
get currentWorkspaceRole() {
|
||||
if (!this.rootStore.workspace.workspaceSlug) return;
|
||||
return this.workspaceMemberInfo[this.rootStore.workspace.workspaceSlug]?.role;
|
||||
}
|
||||
|
||||
get currentProjectMemberInfo() {
|
||||
if (!this.rootStore.project.projectId) return;
|
||||
return this.projectMemberInfo[this.rootStore.project.projectId];
|
||||
}
|
||||
|
||||
get currentProjectRole() {
|
||||
if (!this.rootStore.project.projectId) return;
|
||||
return this.projectMemberInfo[this.rootStore.project.projectId]?.role;
|
||||
}
|
||||
|
||||
get hasPermissionToCurrentWorkspace() {
|
||||
if (!this.rootStore.workspace.workspaceSlug) return;
|
||||
return this.hasPermissionToWorkspace[this.rootStore.workspace.workspaceSlug];
|
||||
}
|
||||
|
||||
get hasPermissionToCurrentProject() {
|
||||
if (!this.rootStore.project.projectId) return;
|
||||
return this.hasPermissionToProject[this.rootStore.project.projectId];
|
||||
}
|
||||
|
||||
fetchUserWorkspaceInfo = async (workspaceSlug: string) => {
|
||||
try {
|
||||
const response = await this.workspaceService.workspaceMemberMe(workspaceSlug);
|
||||
|
||||
runInAction(() => {
|
||||
this.workspaceMemberInfo = {
|
||||
...this.workspaceMemberInfo,
|
||||
[workspaceSlug]: response,
|
||||
};
|
||||
this.hasPermissionToWorkspace = {
|
||||
...this.hasPermissionToWorkspace,
|
||||
[workspaceSlug]: true,
|
||||
};
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.hasPermissionToWorkspace = {
|
||||
...this.hasPermissionToWorkspace,
|
||||
[workspaceSlug]: false,
|
||||
};
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchUserProjectInfo = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const response = await this.projectMemberService.projectMemberMe(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
this.projectMemberInfo = {
|
||||
...this.projectMemberInfo,
|
||||
[projectId]: response,
|
||||
};
|
||||
this.hasPermissionToProject = {
|
||||
...this.hasPermissionToProject,
|
||||
[projectId]: true,
|
||||
};
|
||||
});
|
||||
return response;
|
||||
} catch (error: any) {
|
||||
runInAction(() => {
|
||||
this.hasPermissionToProject = {
|
||||
...this.hasPermissionToProject,
|
||||
[projectId]: false,
|
||||
};
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
leaveWorkspace = async (workspaceSlug: string) => {
|
||||
try {
|
||||
await this.userService.leaveWorkspace(workspaceSlug);
|
||||
|
||||
runInAction(() => {
|
||||
delete this.workspaceMemberInfo[workspaceSlug];
|
||||
delete this.hasPermissionToWorkspace[workspaceSlug];
|
||||
});
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
joinProject = async (workspaceSlug: string, projectIds: string[]) => {
|
||||
const newPermissions: { [projectId: string]: boolean } = {};
|
||||
projectIds.forEach((projectId) => {
|
||||
newPermissions[projectId] = true;
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await this.userService.joinProject(workspaceSlug, projectIds);
|
||||
|
||||
runInAction(() => {
|
||||
this.hasPermissionToProject = {
|
||||
...this.hasPermissionToProject,
|
||||
...newPermissions,
|
||||
};
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
leaveProject = async (workspaceSlug: string, projectId: string) => {
|
||||
const newPermissions: { [projectId: string]: boolean } = {};
|
||||
newPermissions[projectId] = false;
|
||||
|
||||
try {
|
||||
await this.userService.leaveProject(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
this.hasPermissionToProject = {
|
||||
...this.hasPermissionToProject,
|
||||
...newPermissions,
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user