chore: user stores

This commit is contained in:
Aaryan Khandelwal 2023-12-18 12:31:57 +05:30
parent e629977ad6
commit 7dd7de40b7
11 changed files with 90 additions and 64 deletions

View File

@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
import { mutate } from "swr"; import { mutate } from "swr";
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
// hooks // hooks
import { useApplication, useUser, useWorkspace } from "hooks/store"; import { useApplication, useProject, useUser, useWorkspace } from "hooks/store";
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useLocalStorage from "hooks/use-local-storage"; import useLocalStorage from "hooks/use-local-storage";
@ -73,7 +73,6 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
}; };
// store hooks // store hooks
const { const {
project: projectStore,
projectIssues: projectIssueStore, projectIssues: projectIssueStore,
viewIssues: projectViewIssueStore, viewIssues: projectViewIssueStore,
workspaceProfileIssues: profileIssueStore, workspaceProfileIssues: profileIssueStore,
@ -85,6 +84,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
} = useApplication(); } = useApplication();
const { currentUser } = useUser(); const { currentUser } = useUser();
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const { workspaceProjects } = useProject();
const issueStores = { const issueStores = {
[EProjectStore.PROJECT]: { [EProjectStore.PROJECT]: {
@ -116,8 +116,6 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
const { store: currentIssueStore, viewId, dataIdToUpdate } = issueStores[currentStore]; const { store: currentIssueStore, viewId, dataIdToUpdate } = issueStores[currentStore];
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined;
const { setValue: setValueInLocalStorage, clearValue: clearLocalStorageValue } = useLocalStorage<any>( const { setValue: setValueInLocalStorage, clearValue: clearLocalStorageValue } = useLocalStorage<any>(
"draftedIssue", "draftedIssue",
{} {}
@ -213,9 +211,9 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
// if data is not present, set active project to the project // if data is not present, set active project to the project
// in the url. This has the least priority. // in the url. This has the least priority.
if (projects && projects.length > 0 && !activeProject) if (workspaceProjects && workspaceProjects.length > 0 && !activeProject)
setActiveProject(projects?.find((p) => p.id === projectId)?.id ?? projects?.[0].id ?? null); setActiveProject(projectId ?? workspaceProjects?.[0] ?? null);
}, [data, projectId, projects, isOpen, activeProject]); }, [data, projectId, workspaceProjects, isOpen, activeProject]);
const addIssueToCycle = async (issue: IIssue, cycleId: string) => { const addIssueToCycle = async (issue: IIssue, cycleId: string) => {
if (!workspaceSlug || !activeProject) return; if (!workspaceSlug || !activeProject) return;
@ -382,7 +380,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
if (onSubmit) await onSubmit(payload); if (onSubmit) await onSubmit(payload);
}; };
if (!projects || projects.length === 0) return null; if (!workspaceProjects || workspaceProjects.length === 0) return null;
return ( return (
<> <>

View File

@ -7,6 +7,7 @@ import {
useApplication, useApplication,
useCycle, useCycle,
useLabel, useLabel,
useMember,
useModule, useModule,
useProject, useProject,
useProjectState, useProjectState,
@ -29,7 +30,6 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
const { children } = props; const { children } = props;
// store // store
const { const {
projectMember: { fetchProjectMembers },
projectEstimates: { fetchProjectEstimates }, projectEstimates: { fetchProjectEstimates },
inbox: { fetchInboxesList, isInboxEnabled }, inbox: { fetchInboxesList, isInboxEnabled },
} = useMobxStore(); } = useMobxStore();
@ -43,6 +43,9 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
const { fetchAllCycles } = useCycle(); const { fetchAllCycles } = useCycle();
const { fetchModules } = useModule(); const { fetchModules } = useModule();
const { fetchViews } = useProjectView(); const { fetchViews } = useProjectView();
const {
project: { fetchProjectMembers },
} = useMember();
const { fetchProjectStates } = useProjectState(); const { fetchProjectStates } = useProjectState();
const { const {
project: { fetchProjectLabels }, project: { fetchProjectLabels },

View File

@ -4,8 +4,7 @@ import Link from "next/link";
import useSWR from "swr"; import useSWR from "swr";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
// hooks // hooks
import { useLabel, useProject, useUser } from "hooks/store"; import { useLabel, useMember, useProject, useUser } from "hooks/store";
import { useMobxStore } from "lib/mobx/store-provider";
// icons // icons
import { Button, Spinner } from "@plane/ui"; import { Button, Spinner } from "@plane/ui";
@ -16,13 +15,11 @@ export interface IWorkspaceAuthWrapper {
export const WorkspaceAuthWrapper: FC<IWorkspaceAuthWrapper> = observer((props) => { export const WorkspaceAuthWrapper: FC<IWorkspaceAuthWrapper> = observer((props) => {
const { children } = props; const { children } = props;
// store hooks // store hooks
const { const { membership } = useUser();
workspaceMember: { fetchWorkspaceMembers, fetchWorkspaceUserProjectsRole },
} = useMobxStore();
const {
membership: { currentWorkspaceMemberInfo, hasPermissionToCurrentWorkspace, fetchUserWorkspaceInfo },
} = useUser();
const { fetchProjects } = useProject(); const { fetchProjects } = useProject();
const {
workspace: { fetchWorkspaceMembers },
} = useMember();
const { const {
workspace: { fetchWorkspaceLabels }, workspace: { fetchWorkspaceLabels },
} = useLabel(); } = useLabel();
@ -32,7 +29,7 @@ export const WorkspaceAuthWrapper: FC<IWorkspaceAuthWrapper> = observer((props)
// fetching user workspace information // fetching user workspace information
useSWR( useSWR(
workspaceSlug ? `WORKSPACE_MEMBERS_ME_${workspaceSlug}` : null, workspaceSlug ? `WORKSPACE_MEMBERS_ME_${workspaceSlug}` : null,
workspaceSlug ? () => fetchUserWorkspaceInfo(workspaceSlug.toString()) : null workspaceSlug ? () => membership.fetchUserWorkspaceInfo(workspaceSlug.toString()) : null
); );
// fetching workspace projects // fetching workspace projects
useSWR( useSWR(
@ -52,21 +49,29 @@ export const WorkspaceAuthWrapper: FC<IWorkspaceAuthWrapper> = observer((props)
// fetch workspace user projects role // fetch workspace user projects role
useSWR( useSWR(
workspaceSlug ? `WORKSPACE_PROJECTS_ROLE_${workspaceSlug}` : null, 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 // while data is being loaded
if (!currentWorkspaceMemberInfo && hasPermissionToCurrentWorkspace === undefined) { if (!membership.currentWorkspaceMemberInfo && membership.hasPermissionToCurrentWorkspace === undefined) {
return ( return (
<div className="grid h-screen place-items-center bg-custom-background-100 p-4"> <div className="grid h-screen place-items-center bg-custom-background-100 p-4">
<div className="flex flex-col items-center gap-3 text-center"> <div className="flex flex-col items-center gap-3 text-center">
<Spinner /> {/* <Spinner /> */}
Not allowed
</div> </div>
</div> </div>
); );
} }
// while user does not have access to view that workspace // while user does not have access to view that workspace
if (hasPermissionToCurrentWorkspace !== undefined && hasPermissionToCurrentWorkspace === false) { if (
membership.hasPermissionToCurrentWorkspace !== undefined &&
membership.hasPermissionToCurrentWorkspace === false
) {
return ( return (
<div className={`h-screen w-full overflow-hidden bg-custom-background-100`}> <div className={`h-screen w-full overflow-hidden bg-custom-background-100`}>
<div className="grid h-full place-items-center p-4"> <div className="grid h-full place-items-center p-4">

View File

@ -1,4 +1,4 @@
import { computed, observable, makeObservable } from "mobx"; import { observable, makeObservable, action } from "mobx";
import { RootStore } from "../root.store"; import { RootStore } from "../root.store";
// types // types
import { IIssueLabel } from "types"; import { IIssueLabel } from "types";
@ -29,7 +29,7 @@ export class LabelRootStore implements ILabelRootStore {
// observables // observables
labelMap: observable, labelMap: observable,
// computed actions // computed actions
getLabelById: computed, getLabelById: action,
}); });
// root store // root store

View File

@ -56,7 +56,7 @@ export class ProjectLabelStore implements IProjectLabelStore {
// root store // root store
this.rootStore = _rootStore; this.rootStore = _rootStore;
this.labelMap = this.rootStore.labelRoot.labelMap; this.labelMap = this.rootStore.labelRoot?.labelMap;
// services // services
this.issueLabelService = new IssueLabelService(); this.issueLabelService = new IssueLabelService();
} }

View File

@ -31,7 +31,7 @@ export class WorkspaceLabelStore implements IWorkspaceLabelStore {
// root store // root store
this.rootStore = _rootStore; this.rootStore = _rootStore;
this.labelMap = this.rootStore.labelRoot.labelMap; this.labelMap = this.rootStore.labelRoot?.labelMap;
// services // services
this.issueLabelService = new IssueLabelService(); this.issueLabelService = new IssueLabelService();
} }

View File

@ -9,8 +9,8 @@ export interface IMemberRootStore {
// observables // observables
memberMap: Record<string, IUserLite>; memberMap: Record<string, IUserLite>;
// sub-stores // sub-stores
workspaceMember: IWorkspaceMemberStore; workspace: IWorkspaceMemberStore;
projectMember: IProjectMemberStore; project: IProjectMemberStore;
} }
export class MemberRootStore implements IMemberRootStore { export class MemberRootStore implements IMemberRootStore {
@ -19,8 +19,8 @@ export class MemberRootStore implements IMemberRootStore {
// root store // root store
rootStore: RootStore; rootStore: RootStore;
// sub-stores // sub-stores
workspaceMember: IWorkspaceMemberStore; workspace: IWorkspaceMemberStore;
projectMember: IProjectMemberStore; project: IProjectMemberStore;
constructor(_rootStore: RootStore) { constructor(_rootStore: RootStore) {
makeObservable(this, { makeObservable(this, {
@ -31,7 +31,7 @@ export class MemberRootStore implements IMemberRootStore {
// root store // root store
this.rootStore = _rootStore; this.rootStore = _rootStore;
// sub-stores // sub-stores
this.workspaceMember = new WorkspaceMemberStore(_rootStore); this.workspace = new WorkspaceMemberStore(_rootStore);
this.projectMember = new ProjectMemberStore(_rootStore); this.project = new ProjectMemberStore(_rootStore);
} }
} }

View File

@ -53,7 +53,7 @@ export class ProjectMemberStore implements IProjectMemberStore {
// root store // root store
this.rootStore = _rootStore; this.rootStore = _rootStore;
this.memberMap = this.rootStore.memberRoot.memberMap; this.memberMap = this.rootStore.memberRoot?.memberMap;
// services // services
this.projectMemberService = new ProjectMemberService(); this.projectMemberService = new ProjectMemberService();
} }

View File

@ -53,7 +53,7 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
// root store // root store
this.rootStore = _rootStore; this.rootStore = _rootStore;
this.memberMap = this.rootStore.memberRoot.memberMap; this.memberMap = this.rootStore.memberRoot?.memberMap;
// services // services
this.workspaceService = new WorkspaceService(); this.workspaceService = new WorkspaceService();
} }

View File

@ -1,16 +1,17 @@
// mobx
import { action, observable, runInAction, makeObservable, computed } from "mobx"; import { action, observable, runInAction, makeObservable, computed } from "mobx";
import { set } from "lodash";
// services // services
import { ProjectMemberService } from "services/project"; import { ProjectMemberService } from "services/project";
import { UserService } from "services/user.service"; import { UserService } from "services/user.service";
import { WorkspaceService } from "services/workspace.service"; import { WorkspaceService } from "services/workspace.service";
// interfaces // interfaces
import { IWorkspaceMemberMe, IProjectMember } from "types"; import { IWorkspaceMemberMe, IProjectMember, IUserProjectsRole } from "types";
import { RootStore } from "../root.store"; import { RootStore } from "../root.store";
import { EUserProjectRoles } from "constants/project"; import { EUserProjectRoles } from "constants/project";
import { EUserWorkspaceRoles } from "constants/workspace"; import { EUserWorkspaceRoles } from "constants/workspace";
export interface IUserMembershipStore { export interface IUserMembershipStore {
// observables
workspaceMemberInfo: { workspaceMemberInfo: {
[workspaceSlug: string]: IWorkspaceMemberMe; [workspaceSlug: string]: IWorkspaceMemberMe;
}; };
@ -23,7 +24,8 @@ export interface IUserMembershipStore {
hasPermissionToProject: { hasPermissionToProject: {
[projectId: string]: boolean | null; [projectId: string]: boolean | null;
}; };
workspaceProjectsRole: { [workspaceSlug: string]: IUserProjectsRole };
// computed
currentProjectMemberInfo: IProjectMember | undefined; currentProjectMemberInfo: IProjectMember | undefined;
currentWorkspaceMemberInfo: IWorkspaceMemberMe | undefined; currentWorkspaceMemberInfo: IWorkspaceMemberMe | undefined;
currentProjectRole: EUserProjectRoles | undefined; currentProjectRole: EUserProjectRoles | undefined;
@ -31,13 +33,14 @@ export interface IUserMembershipStore {
hasPermissionToCurrentWorkspace: boolean | undefined; hasPermissionToCurrentWorkspace: boolean | undefined;
hasPermissionToCurrentProject: boolean | undefined; hasPermissionToCurrentProject: boolean | undefined;
// actions
fetchUserWorkspaceInfo: (workspaceSlug: string) => Promise<IWorkspaceMemberMe>; fetchUserWorkspaceInfo: (workspaceSlug: string) => Promise<IWorkspaceMemberMe>;
fetchUserProjectInfo: (workspaceSlug: string, projectId: string) => Promise<IProjectMember>; fetchUserProjectInfo: (workspaceSlug: string, projectId: string) => Promise<IProjectMember>;
leaveWorkspace: (workspaceSlug: string) => Promise<void>; leaveWorkspace: (workspaceSlug: string) => Promise<void>;
joinProject: (workspaceSlug: string, projectIds: string[]) => Promise<any>; joinProject: (workspaceSlug: string, projectIds: string[]) => Promise<any>;
leaveProject: (workspaceSlug: string, projectId: string) => Promise<void>; leaveProject: (workspaceSlug: string, projectId: string) => Promise<void>;
fetchUserWorkspaceProjectsRole: (workspaceSlug: string) => Promise<IUserProjectsRole>;
} }
export class UserMembershipStore implements IUserMembershipStore { export class UserMembershipStore implements IUserMembershipStore {
@ -53,6 +56,7 @@ export class UserMembershipStore implements IUserMembershipStore {
hasPermissionToProject: { hasPermissionToProject: {
[projectId: string]: boolean; [projectId: string]: boolean;
} = {}; } = {};
workspaceProjectsRole: { [workspaceSlug: string]: IUserProjectsRole } = {};
// stores // stores
router; router;
// services // services
@ -62,24 +66,26 @@ export class UserMembershipStore implements IUserMembershipStore {
constructor(_rootStore: RootStore) { constructor(_rootStore: RootStore) {
makeObservable(this, { makeObservable(this, {
// observable // observables
workspaceMemberInfo: observable.ref, workspaceMemberInfo: observable,
hasPermissionToWorkspace: observable.ref, hasPermissionToWorkspace: observable,
projectMemberInfo: observable.ref, projectMemberInfo: observable,
hasPermissionToProject: observable.ref, hasPermissionToProject: observable,
// action workspaceProjectsRole: observable,
// computed
currentWorkspaceMemberInfo: computed,
currentWorkspaceRole: computed,
currentProjectMemberInfo: computed,
currentProjectRole: computed,
hasPermissionToCurrentWorkspace: computed,
hasPermissionToCurrentProject: computed,
// actions
fetchUserWorkspaceInfo: action, fetchUserWorkspaceInfo: action,
fetchUserProjectInfo: action, fetchUserProjectInfo: action,
leaveWorkspace: action, leaveWorkspace: action,
joinProject: action, joinProject: action,
leaveProject: action, leaveProject: action,
// computed fetchUserWorkspaceProjectsRole: action,
currentProjectMemberInfo: computed,
currentWorkspaceMemberInfo: computed,
currentProjectRole: computed,
currentWorkspaceRole: computed,
hasPermissionToCurrentWorkspace: computed,
hasPermissionToCurrentProject: computed,
}); });
this.router = _rootStore.app.router; this.router = _rootStore.app.router;
// services // services
@ -122,23 +128,23 @@ export class UserMembershipStore implements IUserMembershipStore {
try { try {
const response = await this.workspaceService.workspaceMemberMe(workspaceSlug); const response = await this.workspaceService.workspaceMemberMe(workspaceSlug);
console.log("response", response);
let memberInfo = this.workspaceMemberInfo;
if (!memberInfo) memberInfo = {};
memberInfo[workspaceSlug] = { ...response };
runInAction(() => { runInAction(() => {
this.workspaceMemberInfo = { this.workspaceMemberInfo = memberInfo;
...this.workspaceMemberInfo, // set(this.workspaceMemberInfo, [workspaceSlug], response);
[workspaceSlug]: response, set(this.hasPermissionToWorkspace, [workspaceSlug], true);
};
this.hasPermissionToWorkspace = {
...this.hasPermissionToWorkspace,
[workspaceSlug]: true,
};
}); });
// console.log("this.workspaceMemberInfo", this.workspaceMemberInfo);
return response; return response;
} catch (error) { } catch (error) {
runInAction(() => { runInAction(() => {
this.hasPermissionToWorkspace = { set(this.hasPermissionToWorkspace, [workspaceSlug], false);
...this.hasPermissionToWorkspace,
[workspaceSlug]: false,
};
}); });
throw error; throw error;
} }
@ -223,4 +229,17 @@ export class UserMembershipStore implements IUserMembershipStore {
throw error; 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;
}
};
} }

View File

@ -1,3 +1,4 @@
import { EUserProjectRoles } from "constants/project";
import { IIssueActivity, IIssueLite, TStateGroups } from "."; import { IIssueActivity, IIssueLite, TStateGroups } from ".";
export interface IUser { export interface IUser {
@ -162,7 +163,7 @@ export interface IUserProfileProjectSegregation {
} }
export interface IUserProjectsRole { export interface IUserProjectsRole {
[project_id: string]: number; [project_id: string]: EUserProjectRoles;
} }
// export interface ICurrentUser { // export interface ICurrentUser {