import { useState } from "react"; import { observer } from "mobx-react-lite"; import Link from "next/link"; import { useRouter } from "next/router"; // icons import { ChevronDown, Dot, XCircle } from "lucide-react"; // ui import { CustomSelect, Tooltip, TOAST_TYPE, setToast } from "@plane/ui"; // components import { ConfirmProjectMemberRemove } from "components/project"; // constants import { PROJECT_MEMBER_LEAVE } from "constants/event-tracker"; import { EUserProjectRoles } from "constants/project"; import { ROLE } from "constants/workspace"; // hooks import { useEventTracker, useMember, useProject, useUser } from "hooks/store"; type Props = { userId: string; }; export const ProjectMemberListItem: React.FC = observer((props) => { const { userId } = props; // states const [removeMemberModal, setRemoveMemberModal] = useState(false); // router const router = useRouter(); const { workspaceSlug, projectId } = router.query; // store hooks const { currentUser, membership: { currentProjectRole, leaveProject }, } = useUser(); const { fetchProjects } = useProject(); const { project: { removeMemberFromProject, getProjectMemberDetails, updateMember }, } = useMember(); const { captureEvent } = useEventTracker(); // derived values const isAdmin = currentProjectRole === EUserProjectRoles.ADMIN; const userDetails = getProjectMemberDetails(userId); const handleRemove = async () => { if (!workspaceSlug || !projectId || !userDetails) return; if (userDetails.member?.id === currentUser?.id) { await leaveProject(workspaceSlug.toString(), projectId.toString()) .then(async () => { captureEvent(PROJECT_MEMBER_LEAVE, { state: "SUCCESS", element: "Project settings members page", }); await fetchProjects(workspaceSlug.toString()); router.push(`/${workspaceSlug}/projects`); }) .catch((err) => setToast({ type: TOAST_TYPE.ERROR, title: "Error", message: err?.error || "Something went wrong. Please try again.", }) ); } else await removeMemberFromProject(workspaceSlug.toString(), projectId.toString(), userDetails.member?.id).catch( (err) => setToast({ type: TOAST_TYPE.ERROR, title: "Error", message: err?.error || "Something went wrong. Please try again.", }) ); }; if (!userDetails) return null; return ( <> setRemoveMemberModal(false)} data={userDetails.member} onSubmit={handleRemove} />
{userDetails.member?.avatar && userDetails.member?.avatar !== "" ? ( {userDetails.member?.display_name ) : ( {(userDetails.member?.display_name ?? userDetails.member?.email ?? "?")[0]} )}
{userDetails.member?.first_name} {userDetails.member?.last_name}

{userDetails.member?.display_name}

{isAdmin && ( <>

{userDetails.member?.email}

)}
{ROLE[userDetails.role]} {userDetails.member?.id !== currentUser?.id && ( )}
} value={userDetails.role} onChange={(value: EUserProjectRoles) => { if (!workspaceSlug || !projectId) return; updateMember(workspaceSlug.toString(), projectId.toString(), userDetails.member?.id, { role: value, }).catch((err) => { const error = err.error; const errorString = Array.isArray(error) ? error[0] : error; setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: errorString ?? "An error occurred while updating member role. Please try again.", }); }); }} disabled={ userDetails.member?.id === currentUser?.id || !currentProjectRole || currentProjectRole < userDetails.role } placement="bottom-end" > {Object.keys(ROLE).map((key) => { if (currentProjectRole && !isAdmin && currentProjectRole < parseInt(key)) return null; return ( <>{ROLE[parseInt(key) as keyof typeof ROLE]} ); })} {(isAdmin || userDetails.member?.id === currentUser?.id) && ( )}
); });