forked from github/plane
fix: workspace members store added and implemented across the app (#2732)
* fix: minor changes * fix: workspace members store added and implemnted across the app
This commit is contained in:
parent
556b2d2617
commit
a6567bbce4
@ -41,6 +41,7 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
|||||||
globalViewFilters: globalViewFiltersStore,
|
globalViewFilters: globalViewFiltersStore,
|
||||||
workspaceFilter: workspaceFilterStore,
|
workspaceFilter: workspaceFilterStore,
|
||||||
workspace: workspaceStore,
|
workspace: workspaceStore,
|
||||||
|
workspaceMember: { workspaceMembers },
|
||||||
project: projectStore,
|
project: projectStore,
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
@ -145,7 +146,7 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
|||||||
handleFiltersUpdate={handleFiltersUpdate}
|
handleFiltersUpdate={handleFiltersUpdate}
|
||||||
layoutDisplayFiltersOptions={ISSUE_DISPLAY_FILTERS_BY_LAYOUT.my_issues.spreadsheet}
|
layoutDisplayFiltersOptions={ISSUE_DISPLAY_FILTERS_BY_LAYOUT.my_issues.spreadsheet}
|
||||||
labels={workspaceStore.workspaceLabels ?? undefined}
|
labels={workspaceStore.workspaceLabels ?? undefined}
|
||||||
members={workspaceStore.workspaceMembers?.map((m) => m.member) ?? undefined}
|
members={workspaceMembers?.map((m) => m.member) ?? undefined}
|
||||||
projects={workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined}
|
projects={workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
|
@ -22,6 +22,7 @@ export const GlobalViewsAppliedFiltersRoot = observer(() => {
|
|||||||
globalViewFilters: globalViewFiltersStore,
|
globalViewFilters: globalViewFiltersStore,
|
||||||
project: projectStore,
|
project: projectStore,
|
||||||
workspace: workspaceStore,
|
workspace: workspaceStore,
|
||||||
|
workspaceMember: { workspaceMembers },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const viewDetails = globalViewId ? globalViewsStore.globalViewDetails[globalViewId.toString()] : undefined;
|
const viewDetails = globalViewId ? globalViewsStore.globalViewDetails[globalViewId.toString()] : undefined;
|
||||||
@ -101,7 +102,7 @@ export const GlobalViewsAppliedFiltersRoot = observer(() => {
|
|||||||
handleClearAllFilters={handleClearAllFilters}
|
handleClearAllFilters={handleClearAllFilters}
|
||||||
handleRemoveFilter={handleRemoveFilter}
|
handleRemoveFilter={handleRemoveFilter}
|
||||||
labels={workspaceStore.workspaceLabels ?? undefined}
|
labels={workspaceStore.workspaceLabels ?? undefined}
|
||||||
members={workspaceStore.workspaceMembers?.map((m) => m.member)}
|
members={workspaceMembers?.map((m) => m.member)}
|
||||||
projects={workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined}
|
projects={workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined}
|
||||||
/>
|
/>
|
||||||
{storedFilters && viewDetails && areFiltersDifferent(storedFilters, viewDetails.query_data.filters ?? {}) && (
|
{storedFilters && viewDetails && areFiltersDifferent(storedFilters, viewDetails.query_data.filters ?? {}) && (
|
||||||
|
@ -39,18 +39,19 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
|
|||||||
multiple = false,
|
multiple = false,
|
||||||
noLabelBorder = false,
|
noLabelBorder = false,
|
||||||
} = props;
|
} = props;
|
||||||
|
// store
|
||||||
const { workspace: workspaceStore, project: projectStore } = useMobxStore();
|
const {
|
||||||
|
workspace: workspaceStore,
|
||||||
|
project: projectStore,
|
||||||
|
workspaceMember: { workspaceMembers, fetchWorkspaceMembers },
|
||||||
|
} = useMobxStore();
|
||||||
const workspaceSlug = workspaceStore?.workspaceSlug;
|
const workspaceSlug = workspaceStore?.workspaceSlug;
|
||||||
|
// states
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
||||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState<Boolean>(false);
|
const [isLoading, setIsLoading] = useState<Boolean>(false);
|
||||||
|
|
||||||
const workspaceMembers = workspaceSlug ? workspaceStore?.workspaceMembers : undefined;
|
|
||||||
|
|
||||||
const fetchProjectMembers = () => {
|
const fetchProjectMembers = () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
if (workspaceSlug && projectId)
|
if (workspaceSlug && projectId)
|
||||||
@ -59,10 +60,9 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
|
|||||||
projectStore.fetchProjectMembers(workspaceSlug, projectId).then(() => setIsLoading(false));
|
projectStore.fetchProjectMembers(workspaceSlug, projectId).then(() => setIsLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchWorkspaceMembers = () => {
|
const getWorkspaceMembers = () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
if (workspaceSlug)
|
if (workspaceSlug) workspaceSlug && fetchWorkspaceMembers(workspaceSlug).then(() => setIsLoading(false));
|
||||||
workspaceSlug && workspaceStore.fetchWorkspaceMembers(workspaceSlug).then(() => setIsLoading(false));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const options = (workspaceMembers ?? [])?.map((member) => ({
|
const options = (workspaceMembers ?? [])?.map((member) => ({
|
||||||
@ -151,7 +151,7 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
|
|||||||
className={`flex items-center justify-between gap-1 w-full text-xs ${
|
className={`flex items-center justify-between gap-1 w-full text-xs ${
|
||||||
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
|
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
|
||||||
} ${buttonClassName}`}
|
} ${buttonClassName}`}
|
||||||
onClick={() => !workspaceMembers && fetchWorkspaceMembers()}
|
onClick={() => !workspaceMembers && getWorkspaceMembers()}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
||||||
|
@ -27,6 +27,7 @@ export const GlobalViewLayoutRoot: React.FC<Props> = observer((props) => {
|
|||||||
globalViewFilters: globalViewFiltersStore,
|
globalViewFilters: globalViewFiltersStore,
|
||||||
workspaceFilter: workspaceFilterStore,
|
workspaceFilter: workspaceFilterStore,
|
||||||
workspace: workspaceStore,
|
workspace: workspaceStore,
|
||||||
|
workspaceMember: { workspaceMembers },
|
||||||
issueDetail: issueDetailStore,
|
issueDetail: issueDetailStore,
|
||||||
project: projectStore,
|
project: projectStore,
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
@ -106,7 +107,7 @@ export const GlobalViewLayoutRoot: React.FC<Props> = observer((props) => {
|
|||||||
displayFilters={workspaceFilterStore.workspaceDisplayFilters}
|
displayFilters={workspaceFilterStore.workspaceDisplayFilters}
|
||||||
handleDisplayFilterUpdate={handleDisplayFiltersUpdate}
|
handleDisplayFilterUpdate={handleDisplayFiltersUpdate}
|
||||||
issues={issues}
|
issues={issues}
|
||||||
members={workspaceStore.workspaceMembers ? workspaceStore.workspaceMembers.map((m) => m.member) : undefined}
|
members={workspaceMembers?.map((m) => m.member)}
|
||||||
labels={workspaceStore.workspaceLabels ? workspaceStore.workspaceLabels : undefined}
|
labels={workspaceStore.workspaceLabels ? workspaceStore.workspaceLabels : undefined}
|
||||||
handleIssueAction={() => {}}
|
handleIssueAction={() => {}}
|
||||||
handleUpdateIssue={handleUpdateIssue}
|
handleUpdateIssue={handleUpdateIssue}
|
||||||
|
@ -22,15 +22,12 @@ export const ProjectLayoutRoot: React.FC = observer(() => {
|
|||||||
|
|
||||||
const { issue: issueStore, issueFilter: issueFilterStore } = useMobxStore();
|
const { issue: issueStore, issueFilter: issueFilterStore } = useMobxStore();
|
||||||
|
|
||||||
const { isLoading } = useSWR(
|
useSWR(workspaceSlug && projectId ? `PROJECT_FILTERS_AND_ISSUES_${projectId.toString()}` : null, async () => {
|
||||||
workspaceSlug && projectId ? `PROJECT_FILTERS_AND_ISSUES_${projectId.toString()}` : null,
|
|
||||||
async () => {
|
|
||||||
if (workspaceSlug && projectId) {
|
if (workspaceSlug && projectId) {
|
||||||
await issueFilterStore.fetchUserProjectFilters(workspaceSlug.toString(), projectId.toString());
|
await issueFilterStore.fetchUserProjectFilters(workspaceSlug.toString(), projectId.toString());
|
||||||
await issueStore.fetchIssues(workspaceSlug.toString(), projectId.toString());
|
await issueStore.fetchIssues(workspaceSlug.toString(), projectId.toString());
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { FC } from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { History } from "lucide-react";
|
import { History } from "lucide-react";
|
||||||
// packages
|
// packages
|
||||||
import { Loader, Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { ActivityIcon, ActivityMessage } from "components/core";
|
import { ActivityIcon, ActivityMessage } from "components/core";
|
||||||
import { IssueCommentCard } from "./comment-card";
|
import { IssueCommentCard } from "./comment-card";
|
||||||
|
@ -63,8 +63,10 @@ export interface ICreateProjectForm {
|
|||||||
export const CreateProjectModal: FC<Props> = observer((props) => {
|
export const CreateProjectModal: FC<Props> = observer((props) => {
|
||||||
const { isOpen, onClose, setToFavorite = false, workspaceSlug } = props;
|
const { isOpen, onClose, setToFavorite = false, workspaceSlug } = props;
|
||||||
// store
|
// store
|
||||||
const { project: projectStore, workspace: workspaceStore } = useMobxStore();
|
const {
|
||||||
const workspaceMembers = workspaceStore.members[workspaceSlug] || [];
|
project: projectStore,
|
||||||
|
workspaceMember: { workspaceMembers },
|
||||||
|
} = useMobxStore();
|
||||||
// states
|
// states
|
||||||
const [isChangeInIdentifierRequired, setIsChangeInIdentifierRequired] = useState(true);
|
const [isChangeInIdentifierRequired, setIsChangeInIdentifierRequired] = useState(true);
|
||||||
// toast
|
// toast
|
||||||
@ -370,7 +372,7 @@ export const CreateProjectModal: FC<Props> = observer((props) => {
|
|||||||
<WorkspaceMemberSelect
|
<WorkspaceMemberSelect
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
options={workspaceMembers}
|
options={workspaceMembers || []}
|
||||||
placeholder="Select Lead"
|
placeholder="Select Lead"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -72,9 +72,10 @@ export const ProjectFeaturesList: FC<Props> = observer(() => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
// store
|
// store
|
||||||
const { project: projectStore, user: userStore } = useMobxStore();
|
const {
|
||||||
const { currentUser, currentProjectRole } = userStore;
|
project: { currentProjectDetails, updateProject },
|
||||||
const { currentProjectDetails } = projectStore;
|
user: { currentUser, currentProjectRole },
|
||||||
|
} = useMobxStore();
|
||||||
const isAdmin = currentProjectRole === 20;
|
const isAdmin = currentProjectRole === 20;
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
@ -86,7 +87,7 @@ export const ProjectFeaturesList: FC<Props> = observer(() => {
|
|||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Project feature updated successfully.",
|
message: "Project feature updated successfully.",
|
||||||
});
|
});
|
||||||
projectStore.updateProject(workspaceSlug.toString(), projectId.toString(), formData);
|
updateProject(workspaceSlug.toString(), projectId.toString(), formData);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!currentUser) return <></>;
|
if (!currentUser) return <></>;
|
||||||
|
@ -19,8 +19,9 @@ export const ConfirmWorkspaceMemberRemove: React.FC<Props> = observer((props) =>
|
|||||||
|
|
||||||
const [isRemoving, setIsRemoving] = useState(false);
|
const [isRemoving, setIsRemoving] = useState(false);
|
||||||
|
|
||||||
const { user: userStore } = useMobxStore();
|
const {
|
||||||
const user = userStore.currentUser;
|
user: { currentUser },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose();
|
onClose();
|
||||||
@ -69,10 +70,10 @@ export const ConfirmWorkspaceMemberRemove: React.FC<Props> = observer((props) =>
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-custom-text-100">
|
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-custom-text-100">
|
||||||
{user?.id === data?.memberId ? "Leave workspace?" : `Remove ${data?.display_name}?`}
|
{currentUser?.id === data?.memberId ? "Leave workspace?" : `Remove ${data?.display_name}?`}
|
||||||
</Dialog.Title>
|
</Dialog.Title>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
{user?.id === data?.memberId ? (
|
{currentUser?.id === data?.memberId ? (
|
||||||
<p className="text-sm text-custom-text-200">
|
<p className="text-sm text-custom-text-200">
|
||||||
Are you sure you want to leave the workspace? You will no longer have access to this
|
Are you sure you want to leave the workspace? You will no longer have access to this
|
||||||
workspace. This action cannot be undone.
|
workspace. This action cannot be undone.
|
||||||
|
@ -1,28 +1,19 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { mutate } from "swr";
|
|
||||||
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
// services
|
|
||||||
import { WorkspaceService } from "services/workspace.service";
|
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, CustomSelect, Input } from "@plane/ui";
|
import { Button, CustomSelect, Input } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Plus, X } from "lucide-react";
|
import { Plus, X } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
import { IUser, TUserWorkspaceRole } from "types";
|
import { IWorkspaceBulkInviteFormData, TUserWorkspaceRole } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { ROLE } from "constants/workspace";
|
import { ROLE } from "constants/workspace";
|
||||||
// fetch-keys
|
|
||||||
import { WORKSPACE_INVITATIONS } from "constants/fetch-keys";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
workspaceSlug: string;
|
onSubmit: (data: IWorkspaceBulkInviteFormData) => Promise<void> | undefined;
|
||||||
user: IUser | undefined;
|
|
||||||
onSuccess?: () => Promise<void>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type EmailRole = {
|
type EmailRole = {
|
||||||
@ -43,11 +34,10 @@ const defaultValues: FormValues = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const workspaceService = new WorkspaceService();
|
|
||||||
|
|
||||||
export const SendWorkspaceInvitationModal: React.FC<Props> = (props) => {
|
export const SendWorkspaceInvitationModal: React.FC<Props> = (props) => {
|
||||||
const { isOpen, onClose, workspaceSlug, user, onSuccess } = props;
|
const { isOpen, onClose, onSubmit } = props;
|
||||||
|
|
||||||
|
// form info
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
reset,
|
reset,
|
||||||
@ -60,8 +50,6 @@ export const SendWorkspaceInvitationModal: React.FC<Props> = (props) => {
|
|||||||
name: "emails",
|
name: "emails",
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose();
|
onClose();
|
||||||
|
|
||||||
@ -71,31 +59,29 @@ export const SendWorkspaceInvitationModal: React.FC<Props> = (props) => {
|
|||||||
}, 350);
|
}, 350);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = async (formData: FormValues) => {
|
// const onSubmit = async (formData: FormValues) => {
|
||||||
if (!workspaceSlug) return;
|
// if (!workspaceSlug) return;
|
||||||
|
|
||||||
await workspaceService
|
// return workspaceService
|
||||||
.inviteWorkspace(workspaceSlug, formData, user)
|
// .inviteWorkspace(workspaceSlug, formData, user)
|
||||||
.then(async () => {
|
|
||||||
if (onSuccess) await onSuccess();
|
|
||||||
|
|
||||||
handleClose();
|
// .then(async () => {
|
||||||
|
// if (onSuccess) await onSuccess();
|
||||||
setToastAlert({
|
// handleClose();
|
||||||
type: "success",
|
// setToastAlert({
|
||||||
title: "Success!",
|
// type: "success",
|
||||||
message: "Invitations sent successfully.",
|
// title: "Success!",
|
||||||
});
|
// message: "Invitations sent successfully.",
|
||||||
})
|
// });
|
||||||
.catch((err) =>
|
// })
|
||||||
setToastAlert({
|
// .catch((err) =>
|
||||||
type: "error",
|
// setToastAlert({
|
||||||
title: "Error!",
|
// type: "error",
|
||||||
message: `${err.error ?? "Something went wrong. Please try again."}`,
|
// title: "Error!",
|
||||||
})
|
// message: `${err.error ?? "Something went wrong. Please try again."}`,
|
||||||
)
|
// })
|
||||||
.finally(() => mutate(WORKSPACE_INVITATIONS));
|
// );
|
||||||
};
|
// };
|
||||||
|
|
||||||
const appendField = () => {
|
const appendField = () => {
|
||||||
append({ email: "", role: 15 });
|
append({ email: "", role: 15 });
|
||||||
|
@ -3,8 +3,6 @@ import Link from "next/link";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
// mobx store
|
// mobx store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// services
|
|
||||||
import { WorkspaceService } from "services/workspace.service";
|
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
@ -33,17 +31,16 @@ type Props = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// services
|
|
||||||
const workspaceService = new WorkspaceService();
|
|
||||||
|
|
||||||
export const WorkspaceMembersListItem: FC<Props> = (props) => {
|
export const WorkspaceMembersListItem: FC<Props> = (props) => {
|
||||||
const { member } = props;
|
const { member } = props;
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// store
|
// store
|
||||||
const { workspace: workspaceStore, user: userStore } = useMobxStore();
|
const {
|
||||||
const { currentWorkspaceMemberInfo, currentWorkspaceRole } = userStore;
|
workspaceMember: { removeMember, updateMember, deleteWorkspaceInvitation },
|
||||||
|
user: { currentWorkspaceMemberInfo, currentWorkspaceRole },
|
||||||
|
} = useMobxStore();
|
||||||
const isAdmin = currentWorkspaceRole === 20;
|
const isAdmin = currentWorkspaceRole === 20;
|
||||||
// states
|
// states
|
||||||
const [removeMemberModal, setRemoveMemberModal] = useState(false);
|
const [removeMemberModal, setRemoveMemberModal] = useState(false);
|
||||||
@ -54,7 +51,7 @@ export const WorkspaceMembersListItem: FC<Props> = (props) => {
|
|||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
if (member.member)
|
if (member.member)
|
||||||
await workspaceStore.removeMember(workspaceSlug.toString(), member.id).catch((err) => {
|
await removeMember(workspaceSlug.toString(), member.id).catch((err) => {
|
||||||
const error = err?.error;
|
const error = err?.error;
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
@ -63,8 +60,7 @@ export const WorkspaceMembersListItem: FC<Props> = (props) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
else
|
else
|
||||||
await workspaceService
|
await deleteWorkspaceInvitation(workspaceSlug.toString(), member.id)
|
||||||
.deleteWorkspaceInvitations(workspaceSlug.toString(), member.id)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
@ -157,11 +153,9 @@ export const WorkspaceMembersListItem: FC<Props> = (props) => {
|
|||||||
onChange={(value: TUserWorkspaceRole | undefined) => {
|
onChange={(value: TUserWorkspaceRole | undefined) => {
|
||||||
if (!workspaceSlug || !value) return;
|
if (!workspaceSlug || !value) return;
|
||||||
|
|
||||||
workspaceStore
|
updateMember(workspaceSlug.toString(), member.id, {
|
||||||
.updateMember(workspaceSlug.toString(), member.id, {
|
|
||||||
role: value,
|
role: value,
|
||||||
})
|
}).catch(() => {
|
||||||
.catch(() => {
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
@ -1,64 +1,45 @@
|
|||||||
|
import { FC } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
// mobx store
|
// mobx store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// services
|
|
||||||
import { WorkspaceService } from "services/workspace.service";
|
|
||||||
// components
|
// components
|
||||||
import { WorkspaceMembersListItem } from "components/workspace";
|
import { WorkspaceMembersListItem } from "components/workspace";
|
||||||
// ui
|
// ui
|
||||||
import { Loader } from "@plane/ui";
|
import { Loader } from "@plane/ui";
|
||||||
|
|
||||||
const workspaceService = new WorkspaceService();
|
export const WorkspaceMembersList: FC<{ searchQuery: string }> = observer(({ searchQuery }) => {
|
||||||
export const WorkspaceMembersList: React.FC<{ searchQuery: string }> = observer(({ searchQuery }) => {
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// store
|
// store
|
||||||
const { workspace: workspaceStore, user: userStore } = useMobxStore();
|
const {
|
||||||
const workspaceMembers = workspaceStore.workspaceMembers;
|
workspaceMember: {
|
||||||
const user = userStore.currentWorkspaceMemberInfo;
|
workspaceMembers,
|
||||||
|
workspaceMembersWithInvitations,
|
||||||
|
workspaceMemberInvitations,
|
||||||
|
fetchWorkspaceMemberInvitations,
|
||||||
|
},
|
||||||
|
user: { currentWorkspaceMemberInfo },
|
||||||
|
} = useMobxStore();
|
||||||
// fetching workspace invitations
|
// fetching workspace invitations
|
||||||
const { data: workspaceInvitations } = useSWR(
|
useSWR(
|
||||||
workspaceSlug ? `WORKSPACE_INVITATIONS_${workspaceSlug.toString()}` : null,
|
workspaceSlug ? `WORKSPACE_INVITATIONS_${workspaceSlug.toString()}` : null,
|
||||||
workspaceSlug ? () => workspaceService.workspaceInvitations(workspaceSlug.toString()) : null
|
workspaceSlug ? () => fetchWorkspaceMemberInvitations(workspaceSlug.toString()) : null
|
||||||
);
|
);
|
||||||
|
|
||||||
const members = [
|
const searchedMembers = workspaceMembersWithInvitations?.filter((member: any) => {
|
||||||
...(workspaceInvitations?.map((item) => ({
|
|
||||||
id: item.id,
|
|
||||||
memberId: item.id,
|
|
||||||
avatar: "",
|
|
||||||
first_name: item.email,
|
|
||||||
last_name: "",
|
|
||||||
email: item.email,
|
|
||||||
display_name: item.email,
|
|
||||||
role: item.role,
|
|
||||||
status: item.accepted,
|
|
||||||
member: false,
|
|
||||||
accountCreated: item.accepted,
|
|
||||||
})) || []),
|
|
||||||
...(workspaceMembers?.map((item) => ({
|
|
||||||
id: item.id,
|
|
||||||
memberId: item.member?.id,
|
|
||||||
avatar: item.member?.avatar,
|
|
||||||
first_name: item.member?.first_name,
|
|
||||||
last_name: item.member?.last_name,
|
|
||||||
email: item.member?.email,
|
|
||||||
display_name: item.member?.display_name,
|
|
||||||
role: item.role,
|
|
||||||
status: true,
|
|
||||||
member: true,
|
|
||||||
accountCreated: true,
|
|
||||||
})) || []),
|
|
||||||
];
|
|
||||||
const searchedMembers = members?.filter((member) => {
|
|
||||||
const fullName = `${member.first_name} ${member.last_name}`.toLowerCase();
|
const fullName = `${member.first_name} ${member.last_name}`.toLowerCase();
|
||||||
const displayName = member.display_name.toLowerCase();
|
const displayName = member.display_name.toLowerCase();
|
||||||
return displayName.includes(searchQuery.toLowerCase()) || fullName.includes(searchQuery.toLowerCase());
|
return displayName.includes(searchQuery.toLowerCase()) || fullName.includes(searchQuery.toLowerCase());
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!workspaceMembers || !workspaceInvitations || !user)
|
if (
|
||||||
|
!workspaceMembers ||
|
||||||
|
!workspaceMemberInvitations ||
|
||||||
|
!workspaceMembersWithInvitations ||
|
||||||
|
!currentWorkspaceMemberInfo
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<Loader className="space-y-5">
|
<Loader className="space-y-5">
|
||||||
<Loader.Item height="40px" />
|
<Loader.Item height="40px" />
|
||||||
@ -70,10 +51,10 @@ export const WorkspaceMembersList: React.FC<{ searchQuery: string }> = observer(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="divide-y-[0.5px] divide-custom-border-200">
|
<div className="divide-y-[0.5px] divide-custom-border-200">
|
||||||
{members.length > 0
|
{workspaceMembersWithInvitations.length > 0
|
||||||
? searchedMembers.map((member) => <WorkspaceMembersListItem key={member.id} member={member} />)
|
? searchedMembers?.map((member) => <WorkspaceMembersListItem key={member.id} member={member} />)
|
||||||
: null}
|
: null}
|
||||||
{searchedMembers.length === 0 && (
|
{searchedMembers?.length === 0 && (
|
||||||
<h4 className="text-md text-custom-text-400 text-center mt-20">No matching member</h4>
|
<h4 className="text-md text-custom-text-400 text-center mt-20">No matching member</h4>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState, FC } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Disclosure, Transition } from "@headlessui/react";
|
import { Disclosure, Transition } from "@headlessui/react";
|
||||||
@ -29,7 +29,7 @@ const defaultValues: Partial<IWorkspace> = {
|
|||||||
// services
|
// services
|
||||||
const fileService = new FileService();
|
const fileService = new FileService();
|
||||||
|
|
||||||
export const WorkspaceDetails: React.FC = observer(() => {
|
export const WorkspaceDetails: FC = observer(() => {
|
||||||
// states
|
// states
|
||||||
const [deleteWorkspaceModal, setDeleteWorkspaceModal] = useState(false);
|
const [deleteWorkspaceModal, setDeleteWorkspaceModal] = useState(false);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
@ -37,9 +37,10 @@ export const WorkspaceDetails: React.FC = observer(() => {
|
|||||||
const [isImageRemoving, setIsImageRemoving] = useState(false);
|
const [isImageRemoving, setIsImageRemoving] = useState(false);
|
||||||
const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false);
|
const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false);
|
||||||
// store
|
// store
|
||||||
const { workspace: workspaceStore, user: userStore } = useMobxStore();
|
const {
|
||||||
const activeWorkspace = workspaceStore.currentWorkspace;
|
workspace: { currentWorkspace, updateWorkspace },
|
||||||
const { currentWorkspaceRole } = userStore;
|
user: { currentWorkspaceRole },
|
||||||
|
} = useMobxStore();
|
||||||
const isAdmin = currentWorkspaceRole === 20;
|
const isAdmin = currentWorkspaceRole === 20;
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
@ -52,11 +53,11 @@ export const WorkspaceDetails: React.FC = observer(() => {
|
|||||||
setValue,
|
setValue,
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
} = useForm<IWorkspace>({
|
} = useForm<IWorkspace>({
|
||||||
defaultValues: { ...defaultValues, ...activeWorkspace },
|
defaultValues: { ...defaultValues, ...currentWorkspace },
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = async (formData: IWorkspace) => {
|
const onSubmit = async (formData: IWorkspace) => {
|
||||||
if (!activeWorkspace) return;
|
if (!currentWorkspace) return;
|
||||||
|
|
||||||
const payload: Partial<IWorkspace> = {
|
const payload: Partial<IWorkspace> = {
|
||||||
logo: formData.logo,
|
logo: formData.logo,
|
||||||
@ -64,8 +65,7 @@ export const WorkspaceDetails: React.FC = observer(() => {
|
|||||||
organization_size: formData.organization_size,
|
organization_size: formData.organization_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
await workspaceStore
|
await updateWorkspace(currentWorkspace.slug, payload)
|
||||||
.updateWorkspace(activeWorkspace.slug, payload)
|
|
||||||
.then(() =>
|
.then(() =>
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
@ -77,13 +77,12 @@ export const WorkspaceDetails: React.FC = observer(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = (url: string | null | undefined) => {
|
const handleDelete = (url: string | null | undefined) => {
|
||||||
if (!activeWorkspace || !url) return;
|
if (!currentWorkspace || !url) return;
|
||||||
|
|
||||||
setIsImageRemoving(true);
|
setIsImageRemoving(true);
|
||||||
|
|
||||||
fileService.deleteFile(activeWorkspace.id, url).then(() => {
|
fileService.deleteFile(currentWorkspace.id, url).then(() => {
|
||||||
workspaceStore
|
updateWorkspace(currentWorkspace.slug, { logo: "" })
|
||||||
.updateWorkspace(activeWorkspace.slug, { logo: "" })
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
@ -104,10 +103,10 @@ export const WorkspaceDetails: React.FC = observer(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeWorkspace) reset({ ...activeWorkspace });
|
if (currentWorkspace) reset({ ...currentWorkspace });
|
||||||
}, [activeWorkspace, reset]);
|
}, [currentWorkspace, reset]);
|
||||||
|
|
||||||
if (!activeWorkspace)
|
if (!currentWorkspace)
|
||||||
return (
|
return (
|
||||||
<div className="grid place-items-center h-full w-full px-4 sm:px-0">
|
<div className="grid place-items-center h-full w-full px-4 sm:px-0">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
@ -119,13 +118,13 @@ export const WorkspaceDetails: React.FC = observer(() => {
|
|||||||
<DeleteWorkspaceModal
|
<DeleteWorkspaceModal
|
||||||
isOpen={deleteWorkspaceModal}
|
isOpen={deleteWorkspaceModal}
|
||||||
onClose={() => setDeleteWorkspaceModal(false)}
|
onClose={() => setDeleteWorkspaceModal(false)}
|
||||||
data={activeWorkspace}
|
data={currentWorkspace}
|
||||||
/>
|
/>
|
||||||
<ImageUploadModal
|
<ImageUploadModal
|
||||||
isOpen={isImageUploadModalOpen}
|
isOpen={isImageUploadModalOpen}
|
||||||
onClose={() => setIsImageUploadModalOpen(false)}
|
onClose={() => setIsImageUploadModalOpen(false)}
|
||||||
isRemoving={isImageRemoving}
|
isRemoving={isImageRemoving}
|
||||||
handleDelete={() => handleDelete(activeWorkspace?.logo)}
|
handleDelete={() => handleDelete(currentWorkspace?.logo)}
|
||||||
onSuccess={(imageUrl) => {
|
onSuccess={(imageUrl) => {
|
||||||
setIsImageUploading(true);
|
setIsImageUploading(true);
|
||||||
setValue("logo", imageUrl);
|
setValue("logo", imageUrl);
|
||||||
@ -148,7 +147,7 @@ export const WorkspaceDetails: React.FC = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="relative flex h-14 w-14 items-center justify-center rounded bg-gray-700 p-4 uppercase text-white">
|
<div className="relative flex h-14 w-14 items-center justify-center rounded bg-gray-700 p-4 uppercase text-white">
|
||||||
{activeWorkspace?.name?.charAt(0) ?? "N"}
|
{currentWorkspace?.name?.charAt(0) ?? "N"}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
@ -157,7 +156,7 @@ export const WorkspaceDetails: React.FC = observer(() => {
|
|||||||
<h3 className="text-lg font-semibold leading-6">{watch("name")}</h3>
|
<h3 className="text-lg font-semibold leading-6">{watch("name")}</h3>
|
||||||
<span className="text-sm tracking-tight">{`${
|
<span className="text-sm tracking-tight">{`${
|
||||||
typeof window !== "undefined" && window.location.origin.replace("http://", "").replace("https://", "")
|
typeof window !== "undefined" && window.location.origin.replace("http://", "").replace("https://", "")
|
||||||
}/${activeWorkspace.slug}`}</span>
|
}/${currentWorkspace.slug}`}</span>
|
||||||
<div className="flex item-center gap-2.5">
|
<div className="flex item-center gap-2.5">
|
||||||
<button
|
<button
|
||||||
className="flex items-center gap-1.5 text-xs text-left text-custom-primary-100 font-medium"
|
className="flex items-center gap-1.5 text-xs text-left text-custom-primary-100 font-medium"
|
||||||
@ -246,7 +245,7 @@ export const WorkspaceDetails: React.FC = observer(() => {
|
|||||||
value={`${
|
value={`${
|
||||||
typeof window !== "undefined" &&
|
typeof window !== "undefined" &&
|
||||||
window.location.origin.replace("http://", "").replace("https://", "")
|
window.location.origin.replace("http://", "").replace("https://", "")
|
||||||
}/${activeWorkspace.slug}`}
|
}/${currentWorkspace.slug}`}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
hasError={Boolean(errors.url)}
|
hasError={Boolean(errors.url)}
|
||||||
|
@ -49,16 +49,17 @@ const authService = new AuthService();
|
|||||||
export const WorkspaceSidebarDropdown = observer(() => {
|
export const WorkspaceSidebarDropdown = observer(() => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
// store
|
||||||
const { theme: themeStore, workspace: workspaceStore, user: userStore } = useMobxStore();
|
const {
|
||||||
const { workspaces, currentWorkspace: activeWorkspace } = workspaceStore;
|
theme: { sidebarCollapsed },
|
||||||
const user = userStore.currentUser;
|
workspace: { workspaces, currentWorkspace: activeWorkspace },
|
||||||
|
user: { currentUser, updateCurrentUser },
|
||||||
|
} = useMobxStore();
|
||||||
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const handleWorkspaceNavigation = (workspace: IWorkspace) => {
|
const handleWorkspaceNavigation = (workspace: IWorkspace) => {
|
||||||
userStore
|
updateCurrentUser({
|
||||||
.updateCurrentUser({
|
|
||||||
last_workspace_id: workspace?.id,
|
last_workspace_id: workspace?.id,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -94,7 +95,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
<Menu.Button className="text-custom-sidebar-text-200 rounded-sm text-sm font-medium focus:outline-none w-full h-full truncate">
|
<Menu.Button className="text-custom-sidebar-text-200 rounded-sm text-sm font-medium focus:outline-none w-full h-full truncate">
|
||||||
<div
|
<div
|
||||||
className={`flex items-center gap-x-2 rounded-sm bg-custom-sidebar-background-80 p-1 truncate ${
|
className={`flex items-center gap-x-2 rounded-sm bg-custom-sidebar-background-80 p-1 truncate ${
|
||||||
themeStore.sidebarCollapsed ? "justify-center" : ""
|
sidebarCollapsed ? "justify-center" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="relative grid h-6 w-6 place-items-center rounded bg-gray-700 uppercase text-white flex-shrink-0">
|
<div className="relative grid h-6 w-6 place-items-center rounded bg-gray-700 uppercase text-white flex-shrink-0">
|
||||||
@ -109,7 +110,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!themeStore.sidebarCollapsed && (
|
{!sidebarCollapsed && (
|
||||||
<h4 className="text-custom-text-100 truncate">
|
<h4 className="text-custom-text-100 truncate">
|
||||||
{activeWorkspace?.name ? activeWorkspace.name : "Loading..."}
|
{activeWorkspace?.name ? activeWorkspace.name : "Loading..."}
|
||||||
</h4>
|
</h4>
|
||||||
@ -198,7 +199,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-full flex-col items-start justify-start gap-2 border-t border-custom-sidebar-border-200 px-3 py-2 text-sm">
|
<div className="flex w-full flex-col items-start justify-start gap-2 border-t border-custom-sidebar-border-200 px-3 py-2 text-sm">
|
||||||
{userLinks(workspaceSlug?.toString() ?? "", user?.id ?? "").map((link, index) => (
|
{userLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link, index) => (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key={index}
|
key={index}
|
||||||
as="div"
|
as="div"
|
||||||
@ -224,10 +225,16 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
</Transition>
|
</Transition>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
{!themeStore.sidebarCollapsed && (
|
{!sidebarCollapsed && (
|
||||||
<Menu as="div" className="relative flex-shrink-0">
|
<Menu as="div" className="relative flex-shrink-0">
|
||||||
<Menu.Button className="grid place-items-center outline-none">
|
<Menu.Button className="grid place-items-center outline-none">
|
||||||
<Avatar name={user?.display_name} src={user?.avatar} size={30} shape="square" className="!text-base" />
|
<Avatar
|
||||||
|
name={currentUser?.display_name}
|
||||||
|
src={currentUser?.avatar}
|
||||||
|
size={30}
|
||||||
|
shape="square"
|
||||||
|
className="!text-base"
|
||||||
|
/>
|
||||||
</Menu.Button>
|
</Menu.Button>
|
||||||
|
|
||||||
<Transition
|
<Transition
|
||||||
@ -244,8 +251,8 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
border border-custom-sidebar-border-200 bg-custom-sidebar-background-100 px-1 py-2 divide-y divide-custom-sidebar-border-200 shadow-lg text-xs outline-none"
|
border border-custom-sidebar-border-200 bg-custom-sidebar-background-100 px-1 py-2 divide-y divide-custom-sidebar-border-200 shadow-lg text-xs outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-2.5 pb-2">
|
<div className="flex flex-col gap-2.5 pb-2">
|
||||||
<span className="px-2 text-custom-sidebar-text-200">{user?.email}</span>
|
<span className="px-2 text-custom-sidebar-text-200">{currentUser?.email}</span>
|
||||||
{profileLinks(workspaceSlug?.toString() ?? "", user?.id ?? "").map((link, index) => (
|
{profileLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link, index) => (
|
||||||
<Menu.Item key={index} as="button" type="button">
|
<Menu.Item key={index} as="button" type="button">
|
||||||
<Link href={link.link}>
|
<Link href={link.link}>
|
||||||
<a className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80">
|
<a className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80">
|
||||||
|
@ -31,7 +31,11 @@ export const WorkspaceViewForm: React.FC<Props> = observer((props) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { workspace: workspaceStore, project: projectStore } = useMobxStore();
|
const {
|
||||||
|
workspace: workspaceStore,
|
||||||
|
project: projectStore,
|
||||||
|
workspaceMember: { workspaceMembers },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
@ -143,7 +147,7 @@ export const WorkspaceViewForm: React.FC<Props> = observer((props) => {
|
|||||||
}}
|
}}
|
||||||
layoutDisplayFiltersOptions={ISSUE_DISPLAY_FILTERS_BY_LAYOUT.my_issues.spreadsheet}
|
layoutDisplayFiltersOptions={ISSUE_DISPLAY_FILTERS_BY_LAYOUT.my_issues.spreadsheet}
|
||||||
labels={workspaceStore.workspaceLabels ?? undefined}
|
labels={workspaceStore.workspaceLabels ?? undefined}
|
||||||
members={workspaceStore.workspaceMembers?.map((m) => m.member) ?? undefined}
|
members={workspaceMembers?.map((m) => m.member) ?? undefined}
|
||||||
projects={workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined}
|
projects={workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
@ -157,7 +161,7 @@ export const WorkspaceViewForm: React.FC<Props> = observer((props) => {
|
|||||||
handleClearAllFilters={clearAllFilters}
|
handleClearAllFilters={clearAllFilters}
|
||||||
handleRemoveFilter={() => {}}
|
handleRemoveFilter={() => {}}
|
||||||
labels={workspaceStore.workspaceLabels ?? undefined}
|
labels={workspaceStore.workspaceLabels ?? undefined}
|
||||||
members={workspaceStore.workspaceMembers?.map((m) => m.member) ?? undefined}
|
members={workspaceMembers?.map((m) => m.member) ?? undefined}
|
||||||
states={undefined}
|
states={undefined}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,8 +11,9 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Crisp = observer(() => {
|
const Crisp = observer(() => {
|
||||||
const { user: userStore } = useMobxStore();
|
const {
|
||||||
const { currentUser } = userStore;
|
user: { currentUser },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
const validateCurrentUser = useCallback(() => {
|
const validateCurrentUser = useCallback(() => {
|
||||||
if (currentUser) return currentUser.email;
|
if (currentUser) return currentUser.email;
|
||||||
|
@ -13,19 +13,22 @@ export interface IUserAuthWrapper {
|
|||||||
export const UserAuthWrapper: FC<IUserAuthWrapper> = (props) => {
|
export const UserAuthWrapper: FC<IUserAuthWrapper> = (props) => {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
// store
|
// store
|
||||||
const { user: userStore, workspace: workspaceStore } = useMobxStore();
|
const {
|
||||||
|
user: { fetchCurrentUser, fetchCurrentUserSettings },
|
||||||
|
workspace: { fetchWorkspaces },
|
||||||
|
} = useMobxStore();
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// fetching user information
|
// fetching user information
|
||||||
const { data: currentUser, error } = useSWR("CURRENT_USER_DETAILS", () => userStore.fetchCurrentUser(), {
|
const { data: currentUser, error } = useSWR("CURRENT_USER_DETAILS", () => fetchCurrentUser(), {
|
||||||
shouldRetryOnError: false,
|
shouldRetryOnError: false,
|
||||||
});
|
});
|
||||||
// fetching user settings
|
// fetching user settings
|
||||||
useSWR("CURRENT_USER_SETTINGS", () => userStore.fetchCurrentUserSettings(), {
|
useSWR("CURRENT_USER_SETTINGS", () => fetchCurrentUserSettings(), {
|
||||||
shouldRetryOnError: false,
|
shouldRetryOnError: false,
|
||||||
});
|
});
|
||||||
// fetching all workspaces
|
// fetching all workspaces
|
||||||
useSWR(`USER_WORKSPACES_LIST`, () => workspaceStore.fetchWorkspaces(), {
|
useSWR(`USER_WORKSPACES_LIST`, () => fetchWorkspaces(), {
|
||||||
shouldRetryOnError: false,
|
shouldRetryOnError: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -15,30 +15,35 @@ export interface IWorkspaceAuthWrapper {
|
|||||||
export const WorkspaceAuthWrapper: FC<IWorkspaceAuthWrapper> = observer((props) => {
|
export const WorkspaceAuthWrapper: FC<IWorkspaceAuthWrapper> = observer((props) => {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
// store
|
// store
|
||||||
const { user: userStore, project: projectStore, workspace: workspaceStore } = useMobxStore();
|
const {
|
||||||
const { currentWorkspaceMemberInfo, hasPermissionToCurrentWorkspace } = userStore;
|
user: { currentWorkspaceMemberInfo, hasPermissionToCurrentWorkspace, fetchUserWorkspaceInfo },
|
||||||
|
project: { fetchProjects },
|
||||||
|
workspace: { fetchWorkspaceLabels },
|
||||||
|
workspaceMember: { fetchWorkspaceMembers },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// fetching user workspace information
|
// fetching user workspace information
|
||||||
useSWR(
|
useSWR(
|
||||||
workspaceSlug ? `WORKSPACE_MEMBERS_ME_${workspaceSlug}` : null,
|
workspaceSlug ? `WORKSPACE_MEMBERS_ME_${workspaceSlug}` : null,
|
||||||
workspaceSlug ? () => userStore.fetchUserWorkspaceInfo(workspaceSlug.toString()) : null
|
workspaceSlug ? () => fetchUserWorkspaceInfo(workspaceSlug.toString()) : null
|
||||||
);
|
);
|
||||||
// fetching workspace projects
|
// fetching workspace projects
|
||||||
useSWR(
|
useSWR(
|
||||||
workspaceSlug ? `WORKSPACE_PROJECTS_${workspaceSlug}` : null,
|
workspaceSlug ? `WORKSPACE_PROJECTS_${workspaceSlug}` : null,
|
||||||
workspaceSlug ? () => projectStore.fetchProjects(workspaceSlug.toString()) : null
|
workspaceSlug ? () => fetchProjects(workspaceSlug.toString()) : null
|
||||||
);
|
);
|
||||||
// fetch workspace members
|
// fetch workspace members
|
||||||
useSWR(
|
useSWR(
|
||||||
workspaceSlug ? `WORKSPACE_MEMBERS_${workspaceSlug}` : null,
|
workspaceSlug ? `WORKSPACE_MEMBERS_${workspaceSlug}` : null,
|
||||||
workspaceSlug ? () => workspaceStore.fetchWorkspaceMembers(workspaceSlug.toString()) : null
|
workspaceSlug ? () => fetchWorkspaceMembers(workspaceSlug.toString()) : null
|
||||||
);
|
);
|
||||||
// fetch workspace labels
|
// fetch workspace labels
|
||||||
useSWR(
|
useSWR(
|
||||||
workspaceSlug ? `WORKSPACE_LABELS_${workspaceSlug}` : null,
|
workspaceSlug ? `WORKSPACE_LABELS_${workspaceSlug}` : null,
|
||||||
workspaceSlug ? () => workspaceStore.fetchWorkspaceLabels(workspaceSlug.toString()) : null
|
workspaceSlug ? () => fetchWorkspaceLabels(workspaceSlug.toString()) : null
|
||||||
);
|
);
|
||||||
|
|
||||||
// while data is being loaded
|
// while data is being loaded
|
||||||
|
@ -28,38 +28,36 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// store
|
// store
|
||||||
const { project: projectStore, user: userStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const {
|
||||||
|
project: { workspaceProjects },
|
||||||
const user = userStore.currentUser;
|
user: { currentUser },
|
||||||
const projects = workspaceSlug ? projectStore.projects[workspaceSlug?.toString()] : null;
|
commandPalette: { toggleCreateProjectModal },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
const trackAnalyticsEvent = (tab: string) => {
|
const trackAnalyticsEvent = (tab: string) => {
|
||||||
if (!user) return;
|
if (!currentUser) return;
|
||||||
|
|
||||||
const eventPayload = {
|
const eventPayload = {
|
||||||
workspaceSlug: workspaceSlug?.toString(),
|
workspaceSlug: workspaceSlug?.toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const eventType =
|
const eventType =
|
||||||
tab === "scope_and_demand" ? "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS" : "WORKSPACE_CUSTOM_ANALYTICS";
|
tab === "scope_and_demand" ? "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS" : "WORKSPACE_CUSTOM_ANALYTICS";
|
||||||
|
trackEventService.trackAnalyticsEvent(eventPayload, eventType, currentUser);
|
||||||
trackEventService.trackAnalyticsEvent(eventPayload, eventType, user);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
if (user && workspaceSlug)
|
if (currentUser && workspaceSlug)
|
||||||
trackEventService.trackAnalyticsEvent(
|
trackEventService.trackAnalyticsEvent(
|
||||||
{ workspaceSlug: workspaceSlug?.toString() },
|
{ workspaceSlug: workspaceSlug?.toString() },
|
||||||
"WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS",
|
"WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS",
|
||||||
user
|
currentUser
|
||||||
);
|
);
|
||||||
}, [user, workspaceSlug]);
|
}, [currentUser, workspaceSlug]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{projects && projects.length > 0 ? (
|
{workspaceProjects && workspaceProjects.length > 0 ? (
|
||||||
<div className="h-full flex flex-col overflow-hidden bg-custom-background-100">
|
<div className="h-full flex flex-col overflow-hidden bg-custom-background-100">
|
||||||
<Tab.Group as={Fragment}>
|
<Tab.Group as={Fragment}>
|
||||||
<Tab.List as="div" className="space-x-2 border-b border-custom-border-200 px-5 py-3">
|
<Tab.List as="div" className="space-x-2 border-b border-custom-border-200 px-5 py-3">
|
||||||
@ -96,7 +94,7 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
icon: <Plus className="h-4 w-4" />,
|
icon: <Plus className="h-4 w-4" />,
|
||||||
text: "New Project",
|
text: "New Project",
|
||||||
onClick: () => commandPaletteStore.toggleCreateProjectModal(true),
|
onClick: () => toggleCreateProjectModal(true),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -18,11 +18,13 @@ import { I_THEME_OPTION, THEME_OPTIONS } from "constants/themes";
|
|||||||
import { NextPageWithLayout } from "types/app";
|
import { NextPageWithLayout } from "types/app";
|
||||||
|
|
||||||
const ProfilePreferencesPage: NextPageWithLayout = observer(() => {
|
const ProfilePreferencesPage: NextPageWithLayout = observer(() => {
|
||||||
const { user: userStore } = useMobxStore();
|
const {
|
||||||
|
user: { currentUser, updateCurrentUserTheme },
|
||||||
|
} = useMobxStore();
|
||||||
// states
|
// states
|
||||||
const [currentTheme, setCurrentTheme] = useState<I_THEME_OPTION | null>(null);
|
const [currentTheme, setCurrentTheme] = useState<I_THEME_OPTION | null>(null);
|
||||||
// computed
|
// computed
|
||||||
const userTheme = userStore.currentUser?.theme;
|
const userTheme = currentUser?.theme;
|
||||||
// hooks
|
// hooks
|
||||||
const { setTheme } = useTheme();
|
const { setTheme } = useTheme();
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
@ -38,7 +40,7 @@ const ProfilePreferencesPage: NextPageWithLayout = observer(() => {
|
|||||||
|
|
||||||
const handleThemeChange = (themeOption: I_THEME_OPTION) => {
|
const handleThemeChange = (themeOption: I_THEME_OPTION) => {
|
||||||
setTheme(themeOption.value);
|
setTheme(themeOption.value);
|
||||||
userStore.updateCurrentUserTheme(themeOption.value).catch(() => {
|
updateCurrentUserTheme(themeOption.value).catch(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
title: "Failed to Update the theme",
|
title: "Failed to Update the theme",
|
||||||
type: "error",
|
type: "error",
|
||||||
@ -48,7 +50,7 @@ const ProfilePreferencesPage: NextPageWithLayout = observer(() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{userStore.currentUser ? (
|
{currentUser ? (
|
||||||
<div className="pr-9 py-8 w-full overflow-y-auto">
|
<div className="pr-9 py-8 w-full overflow-y-auto">
|
||||||
<div className="flex items-center py-3.5 border-b border-custom-border-100">
|
<div className="flex items-center py-3.5 border-b border-custom-border-100">
|
||||||
<h3 className="text-xl font-medium">Preferences</h3>
|
<h3 className="text-xl font-medium">Preferences</h3>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { useState, ReactElement } from "react";
|
import { useState, ReactElement } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import useUser from "hooks/use-user";
|
import useToast from "hooks/use-toast";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// layouts
|
// layouts
|
||||||
import { AppLayout } from "layouts/app-layout";
|
import { AppLayout } from "layouts/app-layout";
|
||||||
import { WorkspaceSettingLayout } from "layouts/settings-layout";
|
import { WorkspaceSettingLayout } from "layouts/settings-layout";
|
||||||
@ -14,15 +16,41 @@ import { Button } from "@plane/ui";
|
|||||||
import { Search } from "lucide-react";
|
import { Search } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
import { NextPageWithLayout } from "types/app";
|
import { NextPageWithLayout } from "types/app";
|
||||||
|
import { IWorkspaceBulkInviteFormData } from "types";
|
||||||
|
|
||||||
const WorkspaceMembersSettingsPage: NextPageWithLayout = () => {
|
const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
// store
|
||||||
|
const {
|
||||||
|
workspaceMember: { inviteMembersToWorkspace },
|
||||||
|
} = useMobxStore();
|
||||||
// states
|
// states
|
||||||
const [inviteModal, setInviteModal] = useState(false);
|
const [inviteModal, setInviteModal] = useState(false);
|
||||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||||
// hooks
|
// hooks
|
||||||
const { user } = useUser();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
|
const handleWorkspaceInvite = (data: IWorkspaceBulkInviteFormData) => {
|
||||||
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
|
return inviteMembersToWorkspace(workspaceSlug.toString(), data)
|
||||||
|
.then(async () => {
|
||||||
|
setInviteModal(false);
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success!",
|
||||||
|
message: "Invitations sent successfully.",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) =>
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: `${err.error ?? "Something went wrong. Please try again."}`,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -30,8 +58,7 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = () => {
|
|||||||
<SendWorkspaceInvitationModal
|
<SendWorkspaceInvitationModal
|
||||||
isOpen={inviteModal}
|
isOpen={inviteModal}
|
||||||
onClose={() => setInviteModal(false)}
|
onClose={() => setInviteModal(false)}
|
||||||
workspaceSlug={workspaceSlug.toString()}
|
onSubmit={handleWorkspaceInvite}
|
||||||
user={user}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<section className="pr-9 py-8 w-full overflow-y-auto">
|
<section className="pr-9 py-8 w-full overflow-y-auto">
|
||||||
@ -55,7 +82,7 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = () => {
|
|||||||
</section>
|
</section>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
WorkspaceMembersSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
WorkspaceMembersSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
return (
|
return (
|
||||||
|
@ -18,23 +18,23 @@ import { IWorkspace } from "types";
|
|||||||
import { NextPageWithLayout } from "types/app";
|
import { NextPageWithLayout } from "types/app";
|
||||||
|
|
||||||
const CreateWorkspacePage: NextPageWithLayout = observer(() => {
|
const CreateWorkspacePage: NextPageWithLayout = observer(() => {
|
||||||
|
// router
|
||||||
|
const router = useRouter();
|
||||||
|
// store
|
||||||
|
const {
|
||||||
|
user: { currentUser, updateCurrentUser },
|
||||||
|
} = useMobxStore();
|
||||||
|
// states
|
||||||
const [defaultValues, setDefaultValues] = useState({
|
const [defaultValues, setDefaultValues] = useState({
|
||||||
name: "",
|
name: "",
|
||||||
slug: "",
|
slug: "",
|
||||||
organization_size: "",
|
organization_size: "",
|
||||||
});
|
});
|
||||||
|
// hooks
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const { user: userStore } = useMobxStore();
|
|
||||||
const user = userStore.currentUser;
|
|
||||||
|
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
const onSubmit = async (workspace: IWorkspace) => {
|
const onSubmit = async (workspace: IWorkspace) => {
|
||||||
await userStore
|
await updateCurrentUser({ last_workspace_id: workspace.id }).then(() => router.push(`/${workspace.slug}`));
|
||||||
.updateCurrentUser({ last_workspace_id: workspace.id })
|
|
||||||
.then(() => router.push(`/${workspace.slug}`));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -54,7 +54,7 @@ const CreateWorkspacePage: NextPageWithLayout = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<div className="absolute sm:fixed text-custom-text-100 text-sm right-4 top-1/4 sm:top-12 -translate-y-1/2 sm:translate-y-0 sm:right-16 sm:py-5">
|
<div className="absolute sm:fixed text-custom-text-100 text-sm right-4 top-1/4 sm:top-12 -translate-y-1/2 sm:translate-y-0 sm:right-16 sm:py-5">
|
||||||
{user?.email}
|
{currentUser?.email}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative flex justify-center sm:justify-start sm:items-center h-full px-8 pb-8 sm:p-0 sm:pr-[8.33%] sm:w-10/12 md:w-9/12 lg:w-4/5">
|
<div className="relative flex justify-center sm:justify-start sm:items-center h-full px-8 pb-8 sm:p-0 sm:pr-[8.33%] sm:w-10/12 md:w-9/12 lg:w-4/5">
|
||||||
|
@ -30,9 +30,12 @@ const workspaceService = new WorkspaceService();
|
|||||||
const OnboardingPage: NextPageWithLayout = observer(() => {
|
const OnboardingPage: NextPageWithLayout = observer(() => {
|
||||||
const [step, setStep] = useState<number | null>(null);
|
const [step, setStep] = useState<number | null>(null);
|
||||||
|
|
||||||
const { user: userStore, workspace: workspaceStore } = useMobxStore();
|
const {
|
||||||
|
user: { currentUser, updateCurrentUser, updateUserOnBoard },
|
||||||
|
workspace: workspaceStore,
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
const user = userStore.currentUser ?? undefined;
|
const user = currentUser ?? undefined;
|
||||||
const workspaces = workspaceStore.workspaces;
|
const workspaces = workspaceStore.workspaces;
|
||||||
const userWorkspaces = workspaceStore.workspacesCreateByCurrentUser;
|
const userWorkspaces = workspaceStore.workspacesCreateByCurrentUser;
|
||||||
|
|
||||||
@ -48,7 +51,7 @@ const OnboardingPage: NextPageWithLayout = observer(() => {
|
|||||||
const updateLastWorkspace = async () => {
|
const updateLastWorkspace = async () => {
|
||||||
if (!workspaces) return;
|
if (!workspaces) return;
|
||||||
|
|
||||||
await userStore.updateCurrentUser({
|
await updateCurrentUser({
|
||||||
last_workspace_id: workspaces[0]?.id,
|
last_workspace_id: workspaces[0]?.id,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -64,14 +67,14 @@ const OnboardingPage: NextPageWithLayout = observer(() => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
await userStore.updateCurrentUser(payload);
|
await updateCurrentUser(payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
// complete onboarding
|
// complete onboarding
|
||||||
const finishOnboarding = async () => {
|
const finishOnboarding = async () => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
||||||
await userStore.updateUserOnBoard();
|
await updateUserOnBoard();
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -28,7 +28,7 @@ export interface IProjectStore {
|
|||||||
|
|
||||||
// computed
|
// computed
|
||||||
searchedProjects: IProject[];
|
searchedProjects: IProject[];
|
||||||
workspaceProjects: IProject[];
|
workspaceProjects: IProject[] | null;
|
||||||
projectLabels: IIssueLabels[] | null;
|
projectLabels: IIssueLabels[] | null;
|
||||||
projectMembers: IProjectMember[] | null;
|
projectMembers: IProjectMember[] | null;
|
||||||
projectEstimates: IEstimate[] | null;
|
projectEstimates: IEstimate[] | null;
|
||||||
@ -183,8 +183,10 @@ export class ProjectStore implements IProjectStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get workspaceProjects() {
|
get workspaceProjects() {
|
||||||
if (!this.rootStore.workspace.workspaceSlug) return [];
|
if (!this.rootStore.workspace.workspaceSlug) return null;
|
||||||
return this.projects?.[this.rootStore.workspace.workspaceSlug];
|
const projects = this.projects[this.rootStore.workspace.workspaceSlug];
|
||||||
|
if (!projects) return null;
|
||||||
|
return projects;
|
||||||
}
|
}
|
||||||
|
|
||||||
get currentProjectDetails() {
|
get currentProjectDetails() {
|
||||||
|
@ -19,7 +19,14 @@ import {
|
|||||||
IIssueQuickAddStore,
|
IIssueQuickAddStore,
|
||||||
IssueQuickAddStore,
|
IssueQuickAddStore,
|
||||||
} from "store/issue";
|
} from "store/issue";
|
||||||
import { IWorkspaceFilterStore, IWorkspaceStore, WorkspaceFilterStore, WorkspaceStore } from "store/workspace";
|
import {
|
||||||
|
IWorkspaceFilterStore,
|
||||||
|
IWorkspaceStore,
|
||||||
|
WorkspaceFilterStore,
|
||||||
|
WorkspaceStore,
|
||||||
|
WorkspaceMemberStore,
|
||||||
|
IWorkspaceMemberStore,
|
||||||
|
} from "store/workspace";
|
||||||
import {
|
import {
|
||||||
IProjectPublishStore,
|
IProjectPublishStore,
|
||||||
IProjectStore,
|
IProjectStore,
|
||||||
@ -113,6 +120,7 @@ export class RootStore {
|
|||||||
commandPalette: ICommandPaletteStore;
|
commandPalette: ICommandPaletteStore;
|
||||||
workspace: IWorkspaceStore;
|
workspace: IWorkspaceStore;
|
||||||
workspaceFilter: IWorkspaceFilterStore;
|
workspaceFilter: IWorkspaceFilterStore;
|
||||||
|
workspaceMember: IWorkspaceMemberStore;
|
||||||
|
|
||||||
projectPublish: IProjectPublishStore;
|
projectPublish: IProjectPublishStore;
|
||||||
project: IProjectStore;
|
project: IProjectStore;
|
||||||
@ -176,6 +184,7 @@ export class RootStore {
|
|||||||
|
|
||||||
this.workspace = new WorkspaceStore(this);
|
this.workspace = new WorkspaceStore(this);
|
||||||
this.workspaceFilter = new WorkspaceFilterStore(this);
|
this.workspaceFilter = new WorkspaceFilterStore(this);
|
||||||
|
this.workspaceMember = new WorkspaceMemberStore(this);
|
||||||
|
|
||||||
this.project = new ProjectStore(this);
|
this.project = new ProjectStore(this);
|
||||||
this.projectState = new ProjectStateStore(this);
|
this.projectState = new ProjectStateStore(this);
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export * from "./workspace_filters.store";
|
export * from "./workspace_filters.store";
|
||||||
export * from "./workspace.store";
|
export * from "./workspace.store";
|
||||||
|
export * from "./workspace-member.store";
|
||||||
|
274
web/store/workspace/workspace-member.store.ts
Normal file
274
web/store/workspace/workspace-member.store.ts
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
import { action, computed, observable, makeObservable, runInAction } from "mobx";
|
||||||
|
import { RootStore } from "../root";
|
||||||
|
// types
|
||||||
|
import { IUser, IWorkspaceMember, IWorkspaceMemberInvitation, IWorkspaceBulkInviteFormData } from "types";
|
||||||
|
// services
|
||||||
|
import { WorkspaceService } from "services/workspace.service";
|
||||||
|
|
||||||
|
export interface IWorkspaceMemberStore {
|
||||||
|
// states
|
||||||
|
loader: boolean;
|
||||||
|
error: any | null;
|
||||||
|
|
||||||
|
// observables
|
||||||
|
members: { [workspaceSlug: string]: IWorkspaceMember[] }; // workspaceSlug: members[]
|
||||||
|
memberInvitations: { [workspaceSlug: string]: IWorkspaceMemberInvitation[] };
|
||||||
|
// actions
|
||||||
|
fetchWorkspaceMembers: (workspaceSlug: string) => Promise<void>;
|
||||||
|
fetchWorkspaceMemberInvitations: (workspaceSlug: string) => Promise<IWorkspaceMemberInvitation[]>;
|
||||||
|
updateMember: (workspaceSlug: string, memberId: string, data: Partial<IWorkspaceMember>) => Promise<void>;
|
||||||
|
removeMember: (workspaceSlug: string, memberId: string) => Promise<void>;
|
||||||
|
inviteMembersToWorkspace: (workspaceSlug: string, data: IWorkspaceBulkInviteFormData) => Promise<any>;
|
||||||
|
deleteWorkspaceInvitation: (workspaceSlug: string, memberId: string) => Promise<void>;
|
||||||
|
// computed
|
||||||
|
workspaceMembers: IWorkspaceMember[] | null;
|
||||||
|
workspaceMemberInvitations: IWorkspaceMemberInvitation[] | null;
|
||||||
|
workspaceMembersWithInvitations: any[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WorkspaceMemberStore implements IWorkspaceMemberStore {
|
||||||
|
// states
|
||||||
|
loader: boolean = false;
|
||||||
|
error: any | null = null;
|
||||||
|
// observables
|
||||||
|
members: { [workspaceSlug: string]: IWorkspaceMember[] } = {};
|
||||||
|
memberInvitations: { [workspaceSlug: string]: IWorkspaceMemberInvitation[] } = {};
|
||||||
|
// services
|
||||||
|
workspaceService;
|
||||||
|
// root store
|
||||||
|
rootStore;
|
||||||
|
|
||||||
|
constructor(_rootStore: RootStore) {
|
||||||
|
makeObservable(this, {
|
||||||
|
// states
|
||||||
|
loader: observable.ref,
|
||||||
|
error: observable.ref,
|
||||||
|
|
||||||
|
// observables
|
||||||
|
members: observable.ref,
|
||||||
|
memberInvitations: observable.ref,
|
||||||
|
// actions
|
||||||
|
fetchWorkspaceMembers: action,
|
||||||
|
fetchWorkspaceMemberInvitations: action,
|
||||||
|
updateMember: action,
|
||||||
|
removeMember: action,
|
||||||
|
inviteMembersToWorkspace: action,
|
||||||
|
deleteWorkspaceInvitation: action,
|
||||||
|
// computed
|
||||||
|
workspaceMembers: computed,
|
||||||
|
workspaceMemberInvitations: computed,
|
||||||
|
workspaceMembersWithInvitations: computed,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.rootStore = _rootStore;
|
||||||
|
this.workspaceService = new WorkspaceService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* computed value of workspace members using the workspace slug from the store
|
||||||
|
*/
|
||||||
|
get workspaceMembers() {
|
||||||
|
if (!this.rootStore.workspace.workspaceSlug) return null;
|
||||||
|
const members = this.members?.[this.rootStore.workspace.workspaceSlug];
|
||||||
|
if (!members) return null;
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computed value of workspace member invitations using workspace slug from store
|
||||||
|
*/
|
||||||
|
get workspaceMemberInvitations() {
|
||||||
|
if (!this.rootStore.workspace.workspaceSlug) return null;
|
||||||
|
const invitations = this.memberInvitations?.[this.rootStore.workspace.workspaceSlug];
|
||||||
|
if (!invitations) return null;
|
||||||
|
return invitations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* computed value provides the members information including the invitations.
|
||||||
|
*/
|
||||||
|
get workspaceMembersWithInvitations() {
|
||||||
|
if (!this.workspaceMembers || !this.workspaceMemberInvitations) return null;
|
||||||
|
return [
|
||||||
|
...(this.workspaceMemberInvitations?.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
memberId: item.id,
|
||||||
|
avatar: "",
|
||||||
|
first_name: item.email,
|
||||||
|
last_name: "",
|
||||||
|
email: item.email,
|
||||||
|
display_name: item.email,
|
||||||
|
role: item.role,
|
||||||
|
status: item.accepted,
|
||||||
|
member: false,
|
||||||
|
accountCreated: item.accepted,
|
||||||
|
})) || []),
|
||||||
|
...(this.workspaceMembers?.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
memberId: item.member?.id,
|
||||||
|
avatar: item.member?.avatar,
|
||||||
|
first_name: item.member?.first_name,
|
||||||
|
last_name: item.member?.last_name,
|
||||||
|
email: item.member?.email,
|
||||||
|
display_name: item.member?.display_name,
|
||||||
|
role: item.role,
|
||||||
|
status: true,
|
||||||
|
member: true,
|
||||||
|
accountCreated: true,
|
||||||
|
})) || []),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fetch workspace members using workspace slug
|
||||||
|
* @param workspaceSlug
|
||||||
|
*/
|
||||||
|
fetchWorkspaceMembers = async (workspaceSlug: string) => {
|
||||||
|
try {
|
||||||
|
runInAction(() => {
|
||||||
|
this.loader = true;
|
||||||
|
this.error = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
const membersResponse = await this.workspaceService.fetchWorkspaceMembers(workspaceSlug);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.members = {
|
||||||
|
...this.members,
|
||||||
|
[workspaceSlug]: membersResponse,
|
||||||
|
};
|
||||||
|
this.loader = false;
|
||||||
|
this.error = null;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
runInAction(() => {
|
||||||
|
this.loader = false;
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fetching workspace member invitations
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
fetchWorkspaceMemberInvitations = async (workspaceSlug: string) => {
|
||||||
|
try {
|
||||||
|
const membersInvitations = await this.workspaceService.workspaceInvitations(workspaceSlug);
|
||||||
|
runInAction(() => {
|
||||||
|
this.memberInvitations = {
|
||||||
|
...this.memberInvitations,
|
||||||
|
[workspaceSlug]: membersInvitations,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return membersInvitations;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invite members to the workspace using emails
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
inviteMembersToWorkspace = async (workspaceSlug: string, data: IWorkspaceBulkInviteFormData) => {
|
||||||
|
try {
|
||||||
|
await this.workspaceService.inviteWorkspace(workspaceSlug, data, this.rootStore.user.currentUser as IUser);
|
||||||
|
await this.fetchWorkspaceMemberInvitations(workspaceSlug);
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete the workspace invitation
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param memberId
|
||||||
|
*/
|
||||||
|
deleteWorkspaceInvitation = async (workspaceSlug: string, memberId: string) => {
|
||||||
|
try {
|
||||||
|
runInAction(() => {
|
||||||
|
this.memberInvitations = {
|
||||||
|
...this.memberInvitations,
|
||||||
|
[workspaceSlug]: [...this.memberInvitations[workspaceSlug].filter((inv) => inv.id !== memberId)],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
await this.workspaceService.deleteWorkspaceInvitations(workspaceSlug.toString(), memberId);
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update workspace member using workspace slug and member id and data
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param memberId
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
updateMember = async (workspaceSlug: string, memberId: string, data: Partial<IWorkspaceMember>) => {
|
||||||
|
const members = this.members?.[workspaceSlug];
|
||||||
|
members?.map((m) => (m.id === memberId ? { ...m, ...data } : m));
|
||||||
|
|
||||||
|
try {
|
||||||
|
runInAction(() => {
|
||||||
|
this.loader = true;
|
||||||
|
this.error = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.workspaceService.updateWorkspaceMember(workspaceSlug, memberId, data);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.loader = false;
|
||||||
|
this.error = null;
|
||||||
|
this.members = {
|
||||||
|
...this.members,
|
||||||
|
[workspaceSlug]: members,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
runInAction(() => {
|
||||||
|
this.loader = false;
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove workspace member using workspace slug and member id
|
||||||
|
* @param workspaceSlug
|
||||||
|
* @param memberId
|
||||||
|
*/
|
||||||
|
removeMember = async (workspaceSlug: string, memberId: string) => {
|
||||||
|
const members = this.members?.[workspaceSlug];
|
||||||
|
members?.filter((m) => m.id !== memberId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
runInAction(() => {
|
||||||
|
this.loader = true;
|
||||||
|
this.error = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.workspaceService.deleteWorkspaceMember(workspaceSlug, memberId);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.loader = false;
|
||||||
|
this.error = null;
|
||||||
|
this.members = {
|
||||||
|
...this.members,
|
||||||
|
[workspaceSlug]: members,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
runInAction(() => {
|
||||||
|
this.loader = false;
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -16,7 +16,6 @@ export interface IWorkspaceStore {
|
|||||||
workspaceSlug: string | null;
|
workspaceSlug: string | null;
|
||||||
workspaces: IWorkspace[] | undefined;
|
workspaces: IWorkspace[] | undefined;
|
||||||
labels: { [workspaceSlug: string]: IIssueLabels[] }; // workspaceSlug: labels[]
|
labels: { [workspaceSlug: string]: IIssueLabels[] }; // workspaceSlug: labels[]
|
||||||
members: { [workspaceSlug: string]: IWorkspaceMember[] }; // workspaceSlug: members[]
|
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
setWorkspaceSlug: (workspaceSlug: string) => void;
|
setWorkspaceSlug: (workspaceSlug: string) => void;
|
||||||
@ -24,22 +23,16 @@ export interface IWorkspaceStore {
|
|||||||
getWorkspaceLabelById: (workspaceSlug: string, labelId: string) => IIssueLabels | null;
|
getWorkspaceLabelById: (workspaceSlug: string, labelId: string) => IIssueLabels | null;
|
||||||
fetchWorkspaces: () => Promise<IWorkspace[]>;
|
fetchWorkspaces: () => Promise<IWorkspace[]>;
|
||||||
fetchWorkspaceLabels: (workspaceSlug: string) => Promise<void>;
|
fetchWorkspaceLabels: (workspaceSlug: string) => Promise<void>;
|
||||||
fetchWorkspaceMembers: (workspaceSlug: string) => Promise<void>;
|
|
||||||
|
|
||||||
// workspace write operations
|
// workspace write operations
|
||||||
createWorkspace: (data: Partial<IWorkspace>) => Promise<IWorkspace>;
|
createWorkspace: (data: Partial<IWorkspace>) => Promise<IWorkspace>;
|
||||||
updateWorkspace: (workspaceSlug: string, data: Partial<IWorkspace>) => Promise<IWorkspace>;
|
updateWorkspace: (workspaceSlug: string, data: Partial<IWorkspace>) => Promise<IWorkspace>;
|
||||||
deleteWorkspace: (workspaceSlug: string) => Promise<void>;
|
deleteWorkspace: (workspaceSlug: string) => Promise<void>;
|
||||||
|
|
||||||
// members write operations
|
|
||||||
updateMember: (workspaceSlug: string, memberId: string, data: Partial<IWorkspaceMember>) => Promise<void>;
|
|
||||||
removeMember: (workspaceSlug: string, memberId: string) => Promise<void>;
|
|
||||||
|
|
||||||
// computed
|
// computed
|
||||||
currentWorkspace: IWorkspace | null;
|
currentWorkspace: IWorkspace | null;
|
||||||
workspacesCreateByCurrentUser: IWorkspace[] | null;
|
workspacesCreateByCurrentUser: IWorkspace[] | null;
|
||||||
workspaceLabels: IIssueLabels[] | null;
|
workspaceLabels: IIssueLabels[] | null;
|
||||||
workspaceMembers: IWorkspaceMember[] | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkspaceStore implements IWorkspaceStore {
|
export class WorkspaceStore implements IWorkspaceStore {
|
||||||
@ -72,7 +65,6 @@ export class WorkspaceStore implements IWorkspaceStore {
|
|||||||
workspaceSlug: observable.ref,
|
workspaceSlug: observable.ref,
|
||||||
workspaces: observable.ref,
|
workspaces: observable.ref,
|
||||||
labels: observable.ref,
|
labels: observable.ref,
|
||||||
members: observable.ref,
|
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
setWorkspaceSlug: action,
|
setWorkspaceSlug: action,
|
||||||
@ -80,21 +72,15 @@ export class WorkspaceStore implements IWorkspaceStore {
|
|||||||
getWorkspaceLabelById: action,
|
getWorkspaceLabelById: action,
|
||||||
fetchWorkspaces: action,
|
fetchWorkspaces: action,
|
||||||
fetchWorkspaceLabels: action,
|
fetchWorkspaceLabels: action,
|
||||||
fetchWorkspaceMembers: action,
|
|
||||||
|
|
||||||
// workspace write operations
|
// workspace write operations
|
||||||
createWorkspace: action,
|
createWorkspace: action,
|
||||||
updateWorkspace: action,
|
updateWorkspace: action,
|
||||||
deleteWorkspace: action,
|
deleteWorkspace: action,
|
||||||
|
|
||||||
// members write operations
|
|
||||||
updateMember: action,
|
|
||||||
removeMember: action,
|
|
||||||
|
|
||||||
// computed
|
// computed
|
||||||
currentWorkspace: computed,
|
currentWorkspace: computed,
|
||||||
workspaceLabels: computed,
|
workspaceLabels: computed,
|
||||||
workspaceMembers: computed,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rootStore = _rootStore;
|
this.rootStore = _rootStore;
|
||||||
@ -135,15 +121,6 @@ export class WorkspaceStore implements IWorkspaceStore {
|
|||||||
return _labels && Object.keys(_labels).length > 0 ? _labels : [];
|
return _labels && Object.keys(_labels).length > 0 ? _labels : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* computed value of workspace members using the workspace slug from the store
|
|
||||||
*/
|
|
||||||
get workspaceMembers() {
|
|
||||||
if (!this.workspaceSlug) return [];
|
|
||||||
const _members = this.members?.[this.workspaceSlug];
|
|
||||||
return _members && Object.keys(_members).length > 0 ? _members : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set workspace slug in the store
|
* set workspace slug in the store
|
||||||
* @param workspaceSlug
|
* @param workspaceSlug
|
||||||
@ -224,35 +201,6 @@ export class WorkspaceStore implements IWorkspaceStore {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* fetch workspace members using workspace slug
|
|
||||||
* @param workspaceSlug
|
|
||||||
*/
|
|
||||||
fetchWorkspaceMembers = async (workspaceSlug: string) => {
|
|
||||||
try {
|
|
||||||
runInAction(() => {
|
|
||||||
this.loader = true;
|
|
||||||
this.error = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
const membersResponse = await this.workspaceService.fetchWorkspaceMembers(workspaceSlug);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
this.members = {
|
|
||||||
...this.members,
|
|
||||||
[workspaceSlug]: membersResponse,
|
|
||||||
};
|
|
||||||
this.loader = false;
|
|
||||||
this.error = null;
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
runInAction(() => {
|
|
||||||
this.loader = false;
|
|
||||||
this.error = error;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create workspace using the workspace data
|
* create workspace using the workspace data
|
||||||
* @param data
|
* @param data
|
||||||
@ -351,75 +299,4 @@ export class WorkspaceStore implements IWorkspaceStore {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* update workspace member using workspace slug and member id and data
|
|
||||||
* @param workspaceSlug
|
|
||||||
* @param memberId
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
updateMember = async (workspaceSlug: string, memberId: string, data: Partial<IWorkspaceMember>) => {
|
|
||||||
const members = this.members?.[workspaceSlug];
|
|
||||||
members?.map((m) => (m.id === memberId ? { ...m, ...data } : m));
|
|
||||||
|
|
||||||
try {
|
|
||||||
runInAction(() => {
|
|
||||||
this.loader = true;
|
|
||||||
this.error = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.workspaceService.updateWorkspaceMember(workspaceSlug, memberId, data);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
this.loader = false;
|
|
||||||
this.error = null;
|
|
||||||
this.members = {
|
|
||||||
...this.members,
|
|
||||||
[workspaceSlug]: members,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
runInAction(() => {
|
|
||||||
this.loader = false;
|
|
||||||
this.error = error;
|
|
||||||
});
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* remove workspace member using workspace slug and member id
|
|
||||||
* @param workspaceSlug
|
|
||||||
* @param memberId
|
|
||||||
*/
|
|
||||||
removeMember = async (workspaceSlug: string, memberId: string) => {
|
|
||||||
const members = this.members?.[workspaceSlug];
|
|
||||||
members?.filter((m) => m.id !== memberId);
|
|
||||||
|
|
||||||
try {
|
|
||||||
runInAction(() => {
|
|
||||||
this.loader = true;
|
|
||||||
this.error = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.workspaceService.deleteWorkspaceMember(workspaceSlug, memberId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
this.loader = false;
|
|
||||||
this.error = null;
|
|
||||||
this.members = {
|
|
||||||
...this.members,
|
|
||||||
[workspaceSlug]: members,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
runInAction(() => {
|
|
||||||
this.loader = false;
|
|
||||||
this.error = error;
|
|
||||||
});
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user