From 34e4b6e2ff6c6d8ea4a6abcdb6bcedd04ae5208d Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Mon, 18 Dec 2023 14:29:53 +0530 Subject: [PATCH] chore: setup inbox store and implement router store --- web/hooks/store/use-inbox.ts | 11 + web/layouts/auth-layout/workspace-wrapper.tsx | 7 +- web/lib/mobx/store-provider.tsx | 26 ++ web/lib/wrappers/store-wrapper.tsx | 25 +- web/lib/wrappers/store-wrapper_legacy.tsx | 101 ------- web/store/application/router.store.ts | 18 +- web/store/inbox/inbox.store.ts | 134 +++++++++ web/store/inbox/inbox_filter.store.ts | 135 +++++++++ web/store/inbox/inbox_issue.store.ts | 256 ++++++++++++++++++ web/store/inbox/index.ts | 33 +++ web/store/root.store.ts | 3 + web/store/user/user-membership.store.ts | 10 +- 12 files changed, 628 insertions(+), 131 deletions(-) create mode 100644 web/hooks/store/use-inbox.ts create mode 100644 web/lib/mobx/store-provider.tsx delete mode 100644 web/lib/wrappers/store-wrapper_legacy.tsx create mode 100644 web/store/inbox/inbox.store.ts create mode 100644 web/store/inbox/inbox_filter.store.ts create mode 100644 web/store/inbox/inbox_issue.store.ts create mode 100644 web/store/inbox/index.ts diff --git a/web/hooks/store/use-inbox.ts b/web/hooks/store/use-inbox.ts new file mode 100644 index 000000000..7792c5726 --- /dev/null +++ b/web/hooks/store/use-inbox.ts @@ -0,0 +1,11 @@ +import { useContext } from "react"; +// mobx store +import { StoreContext } from "contexts/store-context"; +// types +import { IInboxRootStore } from "store/inbox"; + +export const useInbox = (): IInboxRootStore => { + const context = useContext(StoreContext); + if (context === undefined) throw new Error("useInbox must be used within StoreProvider"); + return context.inboxRoot; +}; diff --git a/web/layouts/auth-layout/workspace-wrapper.tsx b/web/layouts/auth-layout/workspace-wrapper.tsx index 4ad66e255..8dc1f50c1 100644 --- a/web/layouts/auth-layout/workspace-wrapper.tsx +++ b/web/layouts/auth-layout/workspace-wrapper.tsx @@ -52,17 +52,12 @@ export const WorkspaceAuthWrapper: FC = observer((props) workspaceSlug ? () => membership.fetchUserWorkspaceProjectsRole(workspaceSlug.toString()) : null ); - console.log("workspaceMemberInfo", membership.workspaceMemberInfo); - console.log("currentWorkspaceMemberInfo", membership.currentWorkspaceMemberInfo); - console.log("hasPermissionToCurrentWorkspace", membership.hasPermissionToCurrentWorkspace); - // while data is being loaded if (!membership.currentWorkspaceMemberInfo && membership.hasPermissionToCurrentWorkspace === undefined) { return (
- {/* */} - Not allowed +
); diff --git a/web/lib/mobx/store-provider.tsx b/web/lib/mobx/store-provider.tsx new file mode 100644 index 000000000..aa9e3f1e5 --- /dev/null +++ b/web/lib/mobx/store-provider.tsx @@ -0,0 +1,26 @@ +import { createContext, useContext } from "react"; +import { RootStore } from "store/root.store"; +// mobx store + +let rootStore: RootStore = new RootStore(); + +export const MobxStoreContext = createContext(rootStore); + +const initializeStore = () => { + const _rootStore: RootStore = rootStore ?? new RootStore(); + if (typeof window === "undefined") return _rootStore; + if (!rootStore) rootStore = _rootStore; + return _rootStore; +}; + +export const MobxStoreProvider = ({ children }: any) => { + const store: RootStore = initializeStore(); + return {children}; +}; + +// hook +export const useMobxStore = () => { + const context = useContext(MobxStoreContext); + if (context === undefined) throw new Error("useMobxStore must be used within MobxStoreProvider"); + return context; +}; diff --git a/web/lib/wrappers/store-wrapper.tsx b/web/lib/wrappers/store-wrapper.tsx index 40b846be7..83867f557 100644 --- a/web/lib/wrappers/store-wrapper.tsx +++ b/web/lib/wrappers/store-wrapper.tsx @@ -1,4 +1,5 @@ import { ReactNode, useEffect, useState, FC } from "react"; +import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import useSWR from "swr"; import { useTheme } from "next-themes"; @@ -15,10 +16,13 @@ const StoreWrapper: FC = observer((props) => { const { children } = props; // states const [dom, setDom] = useState(); + // router + const router = useRouter(); // store hooks const { config: { fetchAppConfig }, theme: { sidebarCollapsed, toggleSidebar }, + router: { setQuery }, } = useApplication(); const { currentUser } = useUser(); // fetching application Config @@ -32,9 +36,8 @@ const StoreWrapper: FC = observer((props) => { useEffect(() => { const localValue = localStorage && localStorage.getItem("app_sidebar_collapsed"); const localBoolValue = localValue ? (localValue === "true" ? true : false) : false; - if (localValue && sidebarCollapsed === undefined) { - toggleSidebar(localBoolValue); - } + + if (localValue && sidebarCollapsed === undefined) toggleSidebar(localBoolValue); }, [sidebarCollapsed, currentUser, setTheme, toggleSidebar]); /** @@ -42,16 +45,18 @@ const StoreWrapper: FC = observer((props) => { */ useEffect(() => { if (!currentUser) return; - if (window) { - setDom(window.document?.querySelector("[data-theme='custom']")); - } + if (window) setDom(window.document?.querySelector("[data-theme='custom']")); + setTheme(currentUser?.theme?.theme || "system"); - if (currentUser?.theme?.theme === "custom" && dom) { - applyTheme(currentUser?.theme?.palette, false); - } else unsetCustomCssVariables(); + if (currentUser?.theme?.theme === "custom" && dom) applyTheme(currentUser?.theme?.palette, false); + else unsetCustomCssVariables(); }, [currentUser, setTheme, dom]); - // TODO: set router values + useEffect(() => { + if (!router.query) return; + + setQuery(router.query); + }, [router.query, setQuery]); return <>{children}; }); diff --git a/web/lib/wrappers/store-wrapper_legacy.tsx b/web/lib/wrappers/store-wrapper_legacy.tsx deleted file mode 100644 index cd08acf32..000000000 --- a/web/lib/wrappers/store-wrapper_legacy.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import { ReactNode, useEffect, useState, FC } from "react"; -import { observer } from "mobx-react-lite"; -import useSWR from "swr"; -import { useTheme } from "next-themes"; -import { useRouter } from "next/router"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; -// helpers -import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper"; - -interface IStoreWrapper { - children: ReactNode; -} - -const StoreWrapper: FC = observer((props) => { - const { children } = props; - // router - const router = useRouter(); - const { workspaceSlug, projectId, cycleId, moduleId, globalViewId, viewId, inboxId, webhookId } = router.query; - // store - const { - theme: { sidebarCollapsed, toggleSidebar }, - user: { currentUser }, - workspace: { setWorkspaceSlug }, - project: { setProjectId }, - cycle: { setCycleId }, - module: { setModuleId }, - globalViews: { setGlobalViewId }, - projectViews: { setViewId }, - inbox: { setInboxId }, - webhook: { setCurrentWebhookId }, - appConfig: { fetchAppConfig }, - } = useMobxStore(); - // fetching application Config - useSWR("APP_CONFIG", () => fetchAppConfig(), { revalidateIfStale: false, revalidateOnFocus: false }); - // state - const [dom, setDom] = useState(); - // theme - const { setTheme } = useTheme(); - - /** - * Sidebar collapsed fetching from local storage - */ - useEffect(() => { - const localValue = localStorage && localStorage.getItem("app_sidebar_collapsed"); - const localBoolValue = localValue ? (localValue === "true" ? true : false) : false; - if (localValue && sidebarCollapsed === undefined) { - toggleSidebar(localBoolValue); - } - }, [sidebarCollapsed, currentUser, setTheme, toggleSidebar]); - - /** - * Setting up the theme of the user by fetching it from local storage - */ - useEffect(() => { - if (!currentUser) return; - if (window) { - setDom(window.document?.querySelector("[data-theme='custom']")); - } - setTheme(currentUser?.theme?.theme || "system"); - if (currentUser?.theme?.theme === "custom" && dom) { - applyTheme(currentUser?.theme?.palette, false); - } else unsetCustomCssVariables(); - }, [currentUser, setTheme, dom]); - - /** - * Setting router info to the respective stores. - */ - useEffect(() => { - if (workspaceSlug) setWorkspaceSlug(workspaceSlug.toString()); - - setProjectId(projectId?.toString() ?? null); - setCycleId(cycleId?.toString() ?? null); - setModuleId(moduleId?.toString() ?? null); - setGlobalViewId(globalViewId?.toString() ?? null); - setViewId(viewId?.toString() ?? null); - setInboxId(inboxId?.toString() ?? null); - setCurrentWebhookId(webhookId?.toString() ?? undefined); - }, [ - workspaceSlug, - projectId, - cycleId, - moduleId, - globalViewId, - viewId, - inboxId, - webhookId, - setWorkspaceSlug, - setProjectId, - setCycleId, - setModuleId, - setGlobalViewId, - setViewId, - setInboxId, - setCurrentWebhookId, - ]); - - return <>{children}; -}); - -export default StoreWrapper; diff --git a/web/store/application/router.store.ts b/web/store/application/router.store.ts index 2c0fbdeec..69a24d22c 100644 --- a/web/store/application/router.store.ts +++ b/web/store/application/router.store.ts @@ -1,10 +1,12 @@ -import { action, makeObservable, observable, computed } from "mobx"; +import { action, makeObservable, observable, computed, runInAction } from "mobx"; import { ParsedUrlQuery } from "node:querystring"; export interface IRouterStore { + // observables query: ParsedUrlQuery; + // actions setQuery: (query: ParsedUrlQuery) => void; - + // computed workspaceSlug: string | undefined; projectId: string | undefined; cycleId: string | undefined; @@ -18,13 +20,15 @@ export interface IRouterStore { } export class RouterStore implements IRouterStore { + // observables query: ParsedUrlQuery = {}; constructor() { makeObservable(this, { + // observables query: observable, + // actions setQuery: action, - //computed workspaceSlug: computed, projectId: computed, @@ -39,9 +43,11 @@ export class RouterStore implements IRouterStore { }); } - setQuery(query: ParsedUrlQuery) { - this.query = query; - } + setQuery = (query: ParsedUrlQuery) => { + runInAction(() => { + this.query = query; + }); + }; get workspaceSlug() { return this.query?.workspaceSlug?.toString(); diff --git a/web/store/inbox/inbox.store.ts b/web/store/inbox/inbox.store.ts new file mode 100644 index 000000000..1eeb4bacf --- /dev/null +++ b/web/store/inbox/inbox.store.ts @@ -0,0 +1,134 @@ +import { observable, action, makeObservable, runInAction, computed } from "mobx"; +import { set } from "lodash"; +// services +import { InboxService } from "services/inbox.service"; +// types +import { RootStore } from "store/root.store"; +import { IInbox } from "types"; + +export interface IInboxStore { + // states + loader: boolean; + error: any | null; + // observables + inboxesList: { + [projectId: string]: IInbox[]; + }; + inboxDetails: { + [inboxId: string]: IInbox; + }; + // computed + isInboxEnabled: boolean; + // computed actions + getInboxId: (projectId: string) => string | null; + // actions + fetchInboxesList: (workspaceSlug: string, projectId: string) => Promise; + fetchInboxDetails: (workspaceSlug: string, projectId: string, inboxId: string) => Promise; +} + +export class InboxStore implements IInboxStore { + // states + loader: boolean = false; + error: any | null = null; + // observables + inboxesList: { + [projectId: string]: IInbox[]; + } = {}; + inboxDetails: { + [inboxId: string]: IInbox; + } = {}; + // root store + rootStore; + // services + inboxService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // states + loader: observable.ref, + error: observable.ref, + // observables + inboxesList: observable, + inboxDetails: observable, + // computed + isInboxEnabled: computed, + // computed actions + getInboxId: action, + // actions + fetchInboxesList: action, + }); + + // root store + this.rootStore = _rootStore; + // services + this.inboxService = new InboxService(); + } + + get isInboxEnabled() { + const projectId = this.rootStore.app.router.projectId; + + if (!projectId) return false; + + const projectDetails = this.rootStore.projectRoot.project.currentProjectDetails; + + if (!projectDetails) return false; + + return projectDetails.inbox_view; + } + + getInboxId = (projectId: string) => { + const projectDetails = this.rootStore.projectRoot.project.getProjectById(projectId); + + if (!projectDetails || !projectDetails.inbox_view) return null; + + return this.inboxesList[projectId]?.[0]?.id ?? null; + }; + + fetchInboxesList = async (workspaceSlug: string, projectId: string) => { + try { + runInAction(() => { + this.loader = true; + }); + + const inboxesResponse = await this.inboxService.getInboxes(workspaceSlug, projectId); + + runInAction(() => { + this.loader = false; + set(this.inboxesList, projectId, inboxesResponse); + }); + + return inboxesResponse; + } catch (error) { + runInAction(() => { + this.loader = false; + this.error = error; + }); + + throw error; + } + }; + + fetchInboxDetails = async (workspaceSlug: string, projectId: string, inboxId: string) => { + try { + runInAction(() => { + this.loader = true; + }); + + const inboxDetailsResponse = await this.inboxService.getInboxById(workspaceSlug, projectId, inboxId); + + runInAction(() => { + this.loader = false; + set(this.inboxDetails, inboxId, inboxDetailsResponse); + }); + + return inboxDetailsResponse; + } catch (error) { + runInAction(() => { + this.loader = false; + this.error = error; + }); + + throw error; + } + }; +} diff --git a/web/store/inbox/inbox_filter.store.ts b/web/store/inbox/inbox_filter.store.ts new file mode 100644 index 000000000..30f7e579a --- /dev/null +++ b/web/store/inbox/inbox_filter.store.ts @@ -0,0 +1,135 @@ +import { observable, action, makeObservable, runInAction, computed } from "mobx"; +import { set } from "lodash"; +// services +import { InboxService } from "services/inbox.service"; +// types +import { RootStore } from "store/root.store"; +import { IInbox, IInboxFilterOptions, IInboxQueryParams } from "types"; +import { EUserWorkspaceRoles } from "constants/workspace"; +import { EUserProjectRoles } from "constants/project"; + +export interface IInboxFiltersStore { + // states + loader: boolean; + error: any | null; + // observables + inboxFilters: { + [inboxId: string]: { filters: IInboxFilterOptions }; + }; + // computed + appliedFilters: IInboxQueryParams | null; + // actions + fetchInboxFilters: (workspaceSlug: string, projectId: string, inboxId: string) => Promise; + updateInboxFilters: ( + workspaceSlug: string, + projectId: string, + inboxId: string, + filters: Partial + ) => Promise; +} + +export class InboxFiltersStore implements IInboxFiltersStore { + // states + loader: boolean = false; + error: any | null = null; + // observables + inboxFilters: { + [inboxId: string]: { filters: IInboxFilterOptions }; + } = {}; + // root store + rootStore; + // services + inboxService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // states + loader: observable.ref, + error: observable.ref, + // observables + inboxFilters: observable, + // computed + appliedFilters: computed, + // actions + fetchInboxFilters: action, + updateInboxFilters: action, + }); + + this.rootStore = _rootStore; + this.inboxService = new InboxService(); + } + + get appliedFilters(): IInboxQueryParams | null { + const inboxId = this.rootStore.app.router.inboxId; + + if (!inboxId) return null; + + const filtersList = this.inboxFilters[inboxId]?.filters; + + if (!filtersList) return null; + + const filteredRouteParams: IInboxQueryParams = { + priority: filtersList.priority ? filtersList.priority.join(",") : null, + inbox_status: filtersList.inbox_status ? filtersList.inbox_status.join(",") : null, + }; + + return filteredRouteParams; + } + + fetchInboxFilters = async (workspaceSlug: string, projectId: string, inboxId: string) => { + try { + runInAction(() => { + this.loader = true; + }); + + const issuesResponse = await this.inboxService.getInboxById(workspaceSlug, projectId, inboxId); + + runInAction(() => { + this.loader = false; + set(this.inboxFilters, [inboxId], issuesResponse.view_props); + }); + + return issuesResponse; + } catch (error) { + runInAction(() => { + this.loader = false; + this.error = error; + }); + + throw error; + } + }; + + updateInboxFilters = async ( + workspaceSlug: string, + projectId: string, + inboxId: string, + filters: Partial + ) => { + const newViewProps = { + ...this.inboxFilters[inboxId], + filters: { + ...this.inboxFilters[inboxId]?.filters, + ...filters, + }, + }; + + try { + runInAction(() => { + set(this.inboxFilters, [inboxId], newViewProps); + }); + + const userRole = this.rootStore.user.membership?.currentProjectRole || EUserProjectRoles.GUEST; + if (userRole > EUserWorkspaceRoles.VIEWER) + await this.inboxService.patchInbox(workspaceSlug, projectId, inboxId, { view_props: newViewProps }); + } catch (error) { + runInAction(() => { + this.error = error; + }); + + this.fetchInboxFilters(workspaceSlug, projectId, inboxId); + + throw error; + } + }; +} diff --git a/web/store/inbox/inbox_issue.store.ts b/web/store/inbox/inbox_issue.store.ts new file mode 100644 index 000000000..084b2764a --- /dev/null +++ b/web/store/inbox/inbox_issue.store.ts @@ -0,0 +1,256 @@ +import { observable, action, makeObservable, runInAction, autorun } from "mobx"; +import { set } from "lodash"; +// services +import { InboxService } from "services/inbox.service"; +// types +import { RootStore } from "store/root.store"; +import { IInboxIssue, IIssue, TInboxStatus } from "types"; +// constants +import { INBOX_ISSUE_SOURCE } from "constants/inbox"; + +export interface IInboxIssuesStore { + // states + loader: boolean; + error: any | null; + // observables + issueMap: Record; + // computed actions + getIssueById: (issueId: string) => IInboxIssue | null; + // actions + fetchIssues: (workspaceSlug: string, projectId: string, inboxId: string) => Promise; + fetchIssueDetails: ( + workspaceSlug: string, + projectId: string, + inboxId: string, + issueId: string + ) => Promise; + createIssue: ( + workspaceSlug: string, + projectId: string, + inboxId: string, + data: Partial + ) => Promise; + updateIssue: ( + workspaceSlug: string, + projectId: string, + inboxId: string, + issueId: string, + data: Partial + ) => Promise; + updateIssueStatus: ( + workspaceSlug: string, + projectId: string, + inboxId: string, + issueId: string, + data: TInboxStatus + ) => Promise; + deleteIssue: (workspaceSlug: string, projectId: string, inboxId: string, issueId: string) => Promise; +} + +export class InboxIssuesStore implements IInboxIssuesStore { + // states + loader: boolean = false; + error: any | null = null; + // observables + issueMap: Record = {}; + // root store + rootStore; + // services + inboxService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // states + loader: observable.ref, + error: observable.ref, + // observables + issueMap: observable, + // computed actions + getIssueById: action, + // actions + fetchIssues: action, + fetchIssueDetails: action, + createIssue: action, + updateIssue: action, + updateIssueStatus: action, + deleteIssue: action, + }); + + // root store + this.rootStore = _rootStore; + // services + this.inboxService = new InboxService(); + + autorun(() => { + const routerStore = this.rootStore.app.router; + + const workspaceSlug = routerStore?.workspaceSlug; + const projectId = routerStore?.projectId; + const inboxId = routerStore?.inboxId; + + if (workspaceSlug && projectId && inboxId && this.rootStore.inboxRoot.inboxFilters.inboxFilters[inboxId]) + this.fetchIssues(workspaceSlug, projectId, inboxId); + }); + } + + getIssueById = (issueId: string): IInboxIssue | null => this.issueMap[issueId] ?? null; + + fetchIssues = async (workspaceSlug: string, projectId: string, inboxId: string) => { + try { + runInAction(() => { + this.loader = true; + }); + + const queryParams = this.rootStore.inboxRoot.inboxFilters.appliedFilters ?? undefined; + + const issuesResponse = await this.inboxService.getInboxIssues(workspaceSlug, projectId, inboxId, queryParams); + + runInAction(() => { + this.loader = false; + issuesResponse.forEach((issue) => { + set(this.issueMap, issue.issue_inbox?.[0].id, issue); + }); + }); + + return issuesResponse; + } catch (error) { + runInAction(() => { + this.loader = false; + this.error = error; + }); + + throw error; + } + }; + + fetchIssueDetails = async (workspaceSlug: string, projectId: string, inboxId: string, issueId: string) => { + try { + runInAction(() => { + this.loader = true; + }); + + const issueResponse = await this.inboxService.getInboxIssueById(workspaceSlug, projectId, inboxId, issueId); + + runInAction(() => { + this.loader = false; + set(this.issueMap, issueId, issueResponse); + }); + + return issueResponse; + } catch (error) { + runInAction(() => { + this.loader = false; + this.error = error; + }); + + throw error; + } + }; + + createIssue = async (workspaceSlug: string, projectId: string, inboxId: string, data: Partial) => { + const payload = { + issue: { + name: data.name, + description: data.description, + description_html: data.description_html, + priority: data.priority, + }, + source: INBOX_ISSUE_SOURCE, + }; + + try { + const response = await this.inboxService.createInboxIssue(workspaceSlug, projectId, inboxId, payload); + + runInAction(() => { + set(this.issueMap, response.issue_inbox?.[0].id, response); + }); + + return response; + } catch (error) { + runInAction(() => { + this.error = error; + }); + + throw error; + } + }; + + updateIssue = async ( + workspaceSlug: string, + projectId: string, + inboxId: string, + issueId: string, + data: Partial + ) => { + const issueDetails = this.rootStore.inboxRoot.inboxIssues.getIssueById(issueId); + + try { + runInAction(() => { + set(this.issueMap, issueId, { + ...issueDetails, + ...data, + }); + }); + + await this.inboxService.patchInboxIssue(workspaceSlug, projectId, inboxId, issueId, { issue: data }); + } catch (error) { + runInAction(() => { + this.error = error; + }); + + this.rootStore.inboxRoot.inboxIssues.fetchIssues(workspaceSlug, projectId, inboxId); + this.fetchIssueDetails(workspaceSlug, projectId, inboxId, issueId); + + throw error; + } + }; + + updateIssueStatus = async ( + workspaceSlug: string, + projectId: string, + inboxId: string, + issueId: string, + data: TInboxStatus + ) => { + const issueDetails = this.rootStore.inboxRoot.inboxIssues.getIssueById(issueId); + + try { + runInAction(() => { + set(this.issueMap, [issueId, "issue_inbox", 0], { + ...issueDetails?.issue_inbox?.[0], + ...data, + }); + }); + + await this.inboxService.markInboxStatus(workspaceSlug, projectId, inboxId, issueId, data); + } catch (error) { + runInAction(() => { + this.error = error; + }); + + this.rootStore.inboxRoot.inboxIssues.fetchIssues(workspaceSlug, projectId, inboxId); + this.fetchIssueDetails(workspaceSlug, projectId, inboxId, issueId); + + throw error; + } + }; + + deleteIssue = async (workspaceSlug: string, projectId: string, inboxId: string, issueId: string) => { + try { + runInAction(() => { + delete this.issueMap[issueId]; + }); + + await this.inboxService.deleteInboxIssue(workspaceSlug, projectId, inboxId, issueId); + } catch (error) { + runInAction(() => { + this.error = error; + }); + + this.rootStore.inboxRoot.inboxIssues.fetchIssues(workspaceSlug, projectId, inboxId); + this.fetchIssueDetails(workspaceSlug, projectId, inboxId, issueId); + + throw error; + } + }; +} diff --git a/web/store/inbox/index.ts b/web/store/inbox/index.ts new file mode 100644 index 000000000..97c05c550 --- /dev/null +++ b/web/store/inbox/index.ts @@ -0,0 +1,33 @@ +import { makeAutoObservable } from "mobx"; +// types +import { RootStore } from "store/root.store"; +import { IInboxIssuesStore, InboxIssuesStore } from "./inbox_issue.store"; +import { IInboxFiltersStore, InboxFiltersStore } from "./inbox_filter.store"; +import { IInboxStore, InboxStore } from "./inbox.store"; + +export interface IInboxRootStore { + // sub-stores + inbox: IInboxStore; + inboxFilters: IInboxFiltersStore; + inboxIssues: IInboxIssuesStore; +} + +export class InboxRootStore implements IInboxRootStore { + // root store + rootStore: RootStore; + // sub-stores + inbox: IInboxStore; + inboxFilters: IInboxFiltersStore; + inboxIssues: IInboxIssuesStore; + + constructor(_rootStore: RootStore) { + makeAutoObservable(this, {}); + + // root store + this.rootStore = _rootStore; + // sub-stores + this.inbox = new InboxStore(_rootStore); + this.inboxFilters = new InboxFiltersStore(_rootStore); + this.inboxIssues = new InboxIssuesStore(_rootStore); + } +} diff --git a/web/store/root.store.ts b/web/store/root.store.ts index 1899ce44e..e97dd5523 100644 --- a/web/store/root.store.ts +++ b/web/store/root.store.ts @@ -12,6 +12,7 @@ import { IStateStore, StateStore } from "./state.store"; import { IPageStore, PageStore } from "./page.store"; import { ILabelRootStore, LabelRootStore } from "./label"; import { IMemberRootStore, MemberRootStore } from "./member"; +import { IInboxRootStore, InboxRootStore } from "./inbox"; enableStaticRendering(typeof window === "undefined"); @@ -22,6 +23,7 @@ export class RootStore { projectRoot: IProjectRootStore; labelRoot: ILabelRootStore; memberRoot: IMemberRootStore; + inboxRoot: IInboxRootStore; cycle: ICycleStore; module: IModuleStore; projectView: IProjectViewStore; @@ -36,6 +38,7 @@ export class RootStore { this.projectRoot = new ProjectRootStore(this); this.labelRoot = new LabelRootStore(this); this.memberRoot = new MemberRootStore(this); + this.inboxRoot = new InboxRootStore(this); // independent stores this.state = new StateStore(this); this.issue = new IssueRootStore(this); diff --git a/web/store/user/user-membership.store.ts b/web/store/user/user-membership.store.ts index f758de586..c5d64ee52 100644 --- a/web/store/user/user-membership.store.ts +++ b/web/store/user/user-membership.store.ts @@ -7,6 +7,7 @@ import { WorkspaceService } from "services/workspace.service"; // interfaces import { IWorkspaceMemberMe, IProjectMember, IUserProjectsRole } from "types"; import { RootStore } from "../root.store"; +// constants import { EUserProjectRoles } from "constants/project"; import { EUserWorkspaceRoles } from "constants/workspace"; @@ -128,15 +129,8 @@ export class UserMembershipStore implements IUserMembershipStore { try { const response = await this.workspaceService.workspaceMemberMe(workspaceSlug); - console.log("response", response); - - let memberInfo = this.workspaceMemberInfo; - if (!memberInfo) memberInfo = {}; - memberInfo[workspaceSlug] = { ...response }; - runInAction(() => { - this.workspaceMemberInfo = memberInfo; - // set(this.workspaceMemberInfo, [workspaceSlug], response); + set(this.workspaceMemberInfo, [workspaceSlug], response); set(this.hasPermissionToWorkspace, [workspaceSlug], true); });