From 7dd7de40b7dd698d2bb984f728078c49f70b50cc Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Mon, 18 Dec 2023 12:31:57 +0530 Subject: [PATCH] chore: user stores --- web/components/issues/modal.tsx | 14 ++-- web/layouts/auth-layout/project-wrapper.tsx | 5 +- web/layouts/auth-layout/workspace-wrapper.tsx | 31 ++++---- web/store/label/index.ts | 4 +- web/store/label/project-label.store.ts | 2 +- web/store/label/workspace-label.store.ts | 2 +- web/store/member/index.ts | 12 +-- web/store/member/project-member.store.ts | 2 +- web/store/member/workspace-member.store.ts | 2 +- web/store/user/user-membership.store.ts | 77 ++++++++++++------- web/types/users.d.ts | 3 +- 11 files changed, 90 insertions(+), 64 deletions(-) diff --git a/web/components/issues/modal.tsx b/web/components/issues/modal.tsx index 697366632..f55d7e3a0 100644 --- a/web/components/issues/modal.tsx +++ b/web/components/issues/modal.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite"; import { mutate } from "swr"; import { Dialog, Transition } from "@headlessui/react"; // hooks -import { useApplication, useUser, useWorkspace } from "hooks/store"; +import { useApplication, useProject, useUser, useWorkspace } from "hooks/store"; import { useMobxStore } from "lib/mobx/store-provider"; import useToast from "hooks/use-toast"; import useLocalStorage from "hooks/use-local-storage"; @@ -73,7 +73,6 @@ export const CreateUpdateIssueModal: React.FC = observer((prop }; // store hooks const { - project: projectStore, projectIssues: projectIssueStore, viewIssues: projectViewIssueStore, workspaceProfileIssues: profileIssueStore, @@ -85,6 +84,7 @@ export const CreateUpdateIssueModal: React.FC = observer((prop } = useApplication(); const { currentUser } = useUser(); const { currentWorkspace } = useWorkspace(); + const { workspaceProjects } = useProject(); const issueStores = { [EProjectStore.PROJECT]: { @@ -116,8 +116,6 @@ export const CreateUpdateIssueModal: React.FC = observer((prop const { store: currentIssueStore, viewId, dataIdToUpdate } = issueStores[currentStore]; - const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined; - const { setValue: setValueInLocalStorage, clearValue: clearLocalStorageValue } = useLocalStorage( "draftedIssue", {} @@ -213,9 +211,9 @@ export const CreateUpdateIssueModal: React.FC = observer((prop // if data is not present, set active project to the project // in the url. This has the least priority. - if (projects && projects.length > 0 && !activeProject) - setActiveProject(projects?.find((p) => p.id === projectId)?.id ?? projects?.[0].id ?? null); - }, [data, projectId, projects, isOpen, activeProject]); + if (workspaceProjects && workspaceProjects.length > 0 && !activeProject) + setActiveProject(projectId ?? workspaceProjects?.[0] ?? null); + }, [data, projectId, workspaceProjects, isOpen, activeProject]); const addIssueToCycle = async (issue: IIssue, cycleId: string) => { if (!workspaceSlug || !activeProject) return; @@ -382,7 +380,7 @@ export const CreateUpdateIssueModal: React.FC = observer((prop if (onSubmit) await onSubmit(payload); }; - if (!projects || projects.length === 0) return null; + if (!workspaceProjects || workspaceProjects.length === 0) return null; return ( <> diff --git a/web/layouts/auth-layout/project-wrapper.tsx b/web/layouts/auth-layout/project-wrapper.tsx index 8c4d4e53f..04e8aa9ac 100644 --- a/web/layouts/auth-layout/project-wrapper.tsx +++ b/web/layouts/auth-layout/project-wrapper.tsx @@ -7,6 +7,7 @@ import { useApplication, useCycle, useLabel, + useMember, useModule, useProject, useProjectState, @@ -29,7 +30,6 @@ export const ProjectAuthWrapper: FC = observer((props) => { const { children } = props; // store const { - projectMember: { fetchProjectMembers }, projectEstimates: { fetchProjectEstimates }, inbox: { fetchInboxesList, isInboxEnabled }, } = useMobxStore(); @@ -43,6 +43,9 @@ export const ProjectAuthWrapper: FC = observer((props) => { const { fetchAllCycles } = useCycle(); const { fetchModules } = useModule(); const { fetchViews } = useProjectView(); + const { + project: { fetchProjectMembers }, + } = useMember(); const { fetchProjectStates } = useProjectState(); const { project: { fetchProjectLabels }, diff --git a/web/layouts/auth-layout/workspace-wrapper.tsx b/web/layouts/auth-layout/workspace-wrapper.tsx index b73ca3a22..4ad66e255 100644 --- a/web/layouts/auth-layout/workspace-wrapper.tsx +++ b/web/layouts/auth-layout/workspace-wrapper.tsx @@ -4,8 +4,7 @@ import Link from "next/link"; import useSWR from "swr"; import { observer } from "mobx-react-lite"; // hooks -import { useLabel, useProject, useUser } from "hooks/store"; -import { useMobxStore } from "lib/mobx/store-provider"; +import { useLabel, useMember, useProject, useUser } from "hooks/store"; // icons import { Button, Spinner } from "@plane/ui"; @@ -16,13 +15,11 @@ export interface IWorkspaceAuthWrapper { export const WorkspaceAuthWrapper: FC = observer((props) => { const { children } = props; // store hooks - const { - workspaceMember: { fetchWorkspaceMembers, fetchWorkspaceUserProjectsRole }, - } = useMobxStore(); - const { - membership: { currentWorkspaceMemberInfo, hasPermissionToCurrentWorkspace, fetchUserWorkspaceInfo }, - } = useUser(); + const { membership } = useUser(); const { fetchProjects } = useProject(); + const { + workspace: { fetchWorkspaceMembers }, + } = useMember(); const { workspace: { fetchWorkspaceLabels }, } = useLabel(); @@ -32,7 +29,7 @@ export const WorkspaceAuthWrapper: FC = observer((props) // fetching user workspace information useSWR( workspaceSlug ? `WORKSPACE_MEMBERS_ME_${workspaceSlug}` : null, - workspaceSlug ? () => fetchUserWorkspaceInfo(workspaceSlug.toString()) : null + workspaceSlug ? () => membership.fetchUserWorkspaceInfo(workspaceSlug.toString()) : null ); // fetching workspace projects useSWR( @@ -52,21 +49,29 @@ export const WorkspaceAuthWrapper: FC = observer((props) // fetch workspace user projects role useSWR( workspaceSlug ? `WORKSPACE_PROJECTS_ROLE_${workspaceSlug}` : null, - workspaceSlug ? () => fetchWorkspaceUserProjectsRole(workspaceSlug.toString()) : null + 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 (!currentWorkspaceMemberInfo && hasPermissionToCurrentWorkspace === undefined) { + if (!membership.currentWorkspaceMemberInfo && membership.hasPermissionToCurrentWorkspace === undefined) { return (
- + {/* */} + Not allowed
); } // while user does not have access to view that workspace - if (hasPermissionToCurrentWorkspace !== undefined && hasPermissionToCurrentWorkspace === false) { + if ( + membership.hasPermissionToCurrentWorkspace !== undefined && + membership.hasPermissionToCurrentWorkspace === false + ) { return (
diff --git a/web/store/label/index.ts b/web/store/label/index.ts index 350667e6b..ee89b0458 100644 --- a/web/store/label/index.ts +++ b/web/store/label/index.ts @@ -1,4 +1,4 @@ -import { computed, observable, makeObservable } from "mobx"; +import { observable, makeObservable, action } from "mobx"; import { RootStore } from "../root.store"; // types import { IIssueLabel } from "types"; @@ -29,7 +29,7 @@ export class LabelRootStore implements ILabelRootStore { // observables labelMap: observable, // computed actions - getLabelById: computed, + getLabelById: action, }); // root store diff --git a/web/store/label/project-label.store.ts b/web/store/label/project-label.store.ts index bfdfab001..25a692739 100644 --- a/web/store/label/project-label.store.ts +++ b/web/store/label/project-label.store.ts @@ -56,7 +56,7 @@ export class ProjectLabelStore implements IProjectLabelStore { // root store this.rootStore = _rootStore; - this.labelMap = this.rootStore.labelRoot.labelMap; + this.labelMap = this.rootStore.labelRoot?.labelMap; // services this.issueLabelService = new IssueLabelService(); } diff --git a/web/store/label/workspace-label.store.ts b/web/store/label/workspace-label.store.ts index 3a1b9d5b7..c75934d07 100644 --- a/web/store/label/workspace-label.store.ts +++ b/web/store/label/workspace-label.store.ts @@ -31,7 +31,7 @@ export class WorkspaceLabelStore implements IWorkspaceLabelStore { // root store this.rootStore = _rootStore; - this.labelMap = this.rootStore.labelRoot.labelMap; + this.labelMap = this.rootStore.labelRoot?.labelMap; // services this.issueLabelService = new IssueLabelService(); } diff --git a/web/store/member/index.ts b/web/store/member/index.ts index a8f615607..770b7582b 100644 --- a/web/store/member/index.ts +++ b/web/store/member/index.ts @@ -9,8 +9,8 @@ export interface IMemberRootStore { // observables memberMap: Record; // sub-stores - workspaceMember: IWorkspaceMemberStore; - projectMember: IProjectMemberStore; + workspace: IWorkspaceMemberStore; + project: IProjectMemberStore; } export class MemberRootStore implements IMemberRootStore { @@ -19,8 +19,8 @@ export class MemberRootStore implements IMemberRootStore { // root store rootStore: RootStore; // sub-stores - workspaceMember: IWorkspaceMemberStore; - projectMember: IProjectMemberStore; + workspace: IWorkspaceMemberStore; + project: IProjectMemberStore; constructor(_rootStore: RootStore) { makeObservable(this, { @@ -31,7 +31,7 @@ export class MemberRootStore implements IMemberRootStore { // root store this.rootStore = _rootStore; // sub-stores - this.workspaceMember = new WorkspaceMemberStore(_rootStore); - this.projectMember = new ProjectMemberStore(_rootStore); + this.workspace = new WorkspaceMemberStore(_rootStore); + this.project = new ProjectMemberStore(_rootStore); } } diff --git a/web/store/member/project-member.store.ts b/web/store/member/project-member.store.ts index 49f052987..072a4ea96 100644 --- a/web/store/member/project-member.store.ts +++ b/web/store/member/project-member.store.ts @@ -53,7 +53,7 @@ export class ProjectMemberStore implements IProjectMemberStore { // root store this.rootStore = _rootStore; - this.memberMap = this.rootStore.memberRoot.memberMap; + this.memberMap = this.rootStore.memberRoot?.memberMap; // services this.projectMemberService = new ProjectMemberService(); } diff --git a/web/store/member/workspace-member.store.ts b/web/store/member/workspace-member.store.ts index e534e4daf..89311854e 100644 --- a/web/store/member/workspace-member.store.ts +++ b/web/store/member/workspace-member.store.ts @@ -53,7 +53,7 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore { // root store this.rootStore = _rootStore; - this.memberMap = this.rootStore.memberRoot.memberMap; + this.memberMap = this.rootStore.memberRoot?.memberMap; // services this.workspaceService = new WorkspaceService(); } diff --git a/web/store/user/user-membership.store.ts b/web/store/user/user-membership.store.ts index 54f7914af..f758de586 100644 --- a/web/store/user/user-membership.store.ts +++ b/web/store/user/user-membership.store.ts @@ -1,16 +1,17 @@ -// mobx import { action, observable, runInAction, makeObservable, computed } from "mobx"; +import { set } from "lodash"; // services import { ProjectMemberService } from "services/project"; import { UserService } from "services/user.service"; import { WorkspaceService } from "services/workspace.service"; // interfaces -import { IWorkspaceMemberMe, IProjectMember } from "types"; +import { IWorkspaceMemberMe, IProjectMember, IUserProjectsRole } from "types"; import { RootStore } from "../root.store"; import { EUserProjectRoles } from "constants/project"; import { EUserWorkspaceRoles } from "constants/workspace"; export interface IUserMembershipStore { + // observables workspaceMemberInfo: { [workspaceSlug: string]: IWorkspaceMemberMe; }; @@ -23,7 +24,8 @@ export interface IUserMembershipStore { hasPermissionToProject: { [projectId: string]: boolean | null; }; - + workspaceProjectsRole: { [workspaceSlug: string]: IUserProjectsRole }; + // computed currentProjectMemberInfo: IProjectMember | undefined; currentWorkspaceMemberInfo: IWorkspaceMemberMe | undefined; currentProjectRole: EUserProjectRoles | undefined; @@ -31,13 +33,14 @@ export interface IUserMembershipStore { hasPermissionToCurrentWorkspace: boolean | undefined; hasPermissionToCurrentProject: boolean | undefined; - + // actions fetchUserWorkspaceInfo: (workspaceSlug: string) => Promise; fetchUserProjectInfo: (workspaceSlug: string, projectId: string) => Promise; leaveWorkspace: (workspaceSlug: string) => Promise; joinProject: (workspaceSlug: string, projectIds: string[]) => Promise; leaveProject: (workspaceSlug: string, projectId: string) => Promise; + fetchUserWorkspaceProjectsRole: (workspaceSlug: string) => Promise; } export class UserMembershipStore implements IUserMembershipStore { @@ -53,6 +56,7 @@ export class UserMembershipStore implements IUserMembershipStore { hasPermissionToProject: { [projectId: string]: boolean; } = {}; + workspaceProjectsRole: { [workspaceSlug: string]: IUserProjectsRole } = {}; // stores router; // services @@ -62,24 +66,26 @@ export class UserMembershipStore implements IUserMembershipStore { constructor(_rootStore: RootStore) { makeObservable(this, { - // observable - workspaceMemberInfo: observable.ref, - hasPermissionToWorkspace: observable.ref, - projectMemberInfo: observable.ref, - hasPermissionToProject: observable.ref, - // action + // observables + workspaceMemberInfo: observable, + hasPermissionToWorkspace: observable, + projectMemberInfo: observable, + hasPermissionToProject: observable, + workspaceProjectsRole: observable, + // computed + currentWorkspaceMemberInfo: computed, + currentWorkspaceRole: computed, + currentProjectMemberInfo: computed, + currentProjectRole: computed, + hasPermissionToCurrentWorkspace: computed, + hasPermissionToCurrentProject: computed, + // actions fetchUserWorkspaceInfo: action, fetchUserProjectInfo: action, leaveWorkspace: action, joinProject: action, leaveProject: action, - // computed - currentProjectMemberInfo: computed, - currentWorkspaceMemberInfo: computed, - currentProjectRole: computed, - currentWorkspaceRole: computed, - hasPermissionToCurrentWorkspace: computed, - hasPermissionToCurrentProject: computed, + fetchUserWorkspaceProjectsRole: action, }); this.router = _rootStore.app.router; // services @@ -122,23 +128,23 @@ 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 = { - ...this.workspaceMemberInfo, - [workspaceSlug]: response, - }; - this.hasPermissionToWorkspace = { - ...this.hasPermissionToWorkspace, - [workspaceSlug]: true, - }; + this.workspaceMemberInfo = memberInfo; + // set(this.workspaceMemberInfo, [workspaceSlug], response); + set(this.hasPermissionToWorkspace, [workspaceSlug], true); }); + + // console.log("this.workspaceMemberInfo", this.workspaceMemberInfo); return response; } catch (error) { runInAction(() => { - this.hasPermissionToWorkspace = { - ...this.hasPermissionToWorkspace, - [workspaceSlug]: false, - }; + set(this.hasPermissionToWorkspace, [workspaceSlug], false); }); throw error; } @@ -223,4 +229,17 @@ export class UserMembershipStore implements IUserMembershipStore { throw error; } }; + + fetchUserWorkspaceProjectsRole = async (workspaceSlug: string) => { + try { + const response = await this.workspaceService.getWorkspaceUserProjectsRole(workspaceSlug); + + runInAction(() => { + set(this.workspaceProjectsRole, [workspaceSlug], response); + }); + return response; + } catch (error) { + throw error; + } + }; } diff --git a/web/types/users.d.ts b/web/types/users.d.ts index 0cf8951ee..cdeee90cc 100644 --- a/web/types/users.d.ts +++ b/web/types/users.d.ts @@ -1,3 +1,4 @@ +import { EUserProjectRoles } from "constants/project"; import { IIssueActivity, IIssueLite, TStateGroups } from "."; export interface IUser { @@ -162,7 +163,7 @@ export interface IUserProfileProjectSegregation { } export interface IUserProjectsRole { - [project_id: string]: number; + [project_id: string]: EUserProjectRoles; } // export interface ICurrentUser {