import { useState } from "react"; import { useRouter } from "next/router"; import Link from "next/link"; import { observer } from "mobx-react-lite"; // hooks import { useEventTracker, useMember, useProject, useUser } from "hooks/store"; import useToast from "hooks/use-toast"; // components import { ConfirmProjectMemberRemove } from "components/project"; // ui import { CustomSelect, Tooltip } from "@plane/ui"; // icons import { ChevronDown, Dot, XCircle } from "lucide-react"; // constants import { ROLE } from "constants/workspace"; import { EUserProjectRoles } from "constants/project"; import { PROJECT_MEMBER_LEAVE } from "constants/event-tracker"; 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(); // toast alert const { setToastAlert } = useToast(); // 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) => setToastAlert({ 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) => setToastAlert({ 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; setToastAlert({ 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) && ( )}
); });