import { FC, useState } from "react"; import { observer } from "mobx-react"; import Link from "next/link"; import { useRouter } from "next/router"; // lucide icons import { ChevronDown, Dot, XCircle } from "lucide-react"; // ui import { CustomSelect, TOAST_TYPE, Tooltip, setToast } from "@plane/ui"; // components import { ConfirmWorkspaceMemberRemove } from "@/components/workspace"; // constants import { WORKSPACE_MEMBER_lEAVE } from "@/constants/event-tracker"; import { EUserWorkspaceRoles, ROLE } from "@/constants/workspace"; // hooks import { useEventTracker, useMember, useUser } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; type Props = { memberId: string; }; export const WorkspaceMembersListItem: FC = observer((props) => { const { memberId } = props; // states const [removeMemberModal, setRemoveMemberModal] = useState(false); // router const router = useRouter(); const { workspaceSlug } = router.query; // store hooks const { // currentUser, // currentUserSettings, membership: { currentWorkspaceRole, leaveWorkspace }, } = useUser(); const { data: currentUser } = useUser(); const { workspace: { updateMember, removeMemberFromWorkspace, getWorkspaceMemberDetails }, } = useMember(); const { captureEvent } = useEventTracker(); const { isMobile } = usePlatformOS(); // derived values const memberDetails = getWorkspaceMemberDetails(memberId); const handleLeaveWorkspace = async () => { if (!workspaceSlug || !currentUser) return; await leaveWorkspace(workspaceSlug.toString()) .then(() => { captureEvent(WORKSPACE_MEMBER_lEAVE, { state: "SUCCESS", element: "Workspace settings members page", }); router.push("/profile"); }) .catch((err: any) => setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: err?.error || "Something went wrong. Please try again.", }) ); }; const handleRemoveMember = async () => { if (!workspaceSlug || !memberDetails) return; await removeMemberFromWorkspace(workspaceSlug.toString(), memberDetails.member.id).catch((err) => setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: err?.error || "Something went wrong. Please try again.", }) ); }; const handleRemove = async () => { if (memberDetails?.member.id === currentUser?.id) await handleLeaveWorkspace(); else await handleRemoveMember(); }; if (!memberDetails) return null; // is the member current logged in user const isCurrentUser = memberDetails?.member.id === currentUser?.id; // is the current logged in user admin const isAdmin = currentWorkspaceRole === EUserWorkspaceRoles.ADMIN; // role change access- // 1. user cannot change their own role // 2. only admin or member can change role // 3. user cannot change role of higher role const hasRoleChangeAccess = currentWorkspaceRole && !isCurrentUser && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentWorkspaceRole) && memberDetails.role <= currentWorkspaceRole; return ( <> setRemoveMemberModal(false)} userDetails={{ id: memberDetails.member.id, display_name: `${memberDetails.member.display_name}`, }} onSubmit={handleRemove} />
{memberDetails.member.avatar && memberDetails.member.avatar.trim() !== "" ? ( {memberDetails.member.display_name ) : ( {(memberDetails.member.email ?? memberDetails.member.display_name ?? "?")[0]} )}
{memberDetails.member.first_name} {memberDetails.member.last_name}

{memberDetails.member.display_name}

{isAdmin && ( <>

{memberDetails.member.email}

)}
{ROLE[memberDetails.role]} {hasRoleChangeAccess && ( )}
} value={memberDetails.role} onChange={(value: EUserWorkspaceRoles) => { if (!workspaceSlug || !value) return; updateMember(workspaceSlug.toString(), memberDetails.member.id, { role: value, }).catch(() => { setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: "An error occurred while updating member role. Please try again.", }); }); }} disabled={!hasRoleChangeAccess} placement="bottom-end" > {Object.keys(ROLE).map((key) => { if (currentWorkspaceRole && currentWorkspaceRole !== 20 && currentWorkspaceRole < parseInt(key)) return null; return ( <>{ROLE[parseInt(key) as keyof typeof ROLE]} ); })}
); });