diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -1678,6 +1678,56 @@ return result; } +function useAvailableThreadMemberActions( + memberInfo: RelativeMemberInfo, + threadInfo: ThreadInfo, + canEdit: ?boolean = true, +): $ReadOnlyArray<'change_role' | 'remove_user'> { + const canRemoveMembers = useThreadHasPermission( + threadInfo, + threadPermissions.REMOVE_MEMBERS, + ); + const canChangeRoles = useThreadHasPermission( + threadInfo, + threadPermissions.CHANGE_ROLE, + ); + + return React.useMemo(() => { + const role = memberInfo.role; + if (!canEdit || !role) { + return []; + } + + const result = []; + + if ( + canChangeRoles && + memberInfo.username && + threadHasAdminRole(threadInfo) + ) { + result.push('change_role'); + } + + if ( + canRemoveMembers && + !memberInfo.isViewer && + (canChangeRoles || roleIsDefaultRole(threadInfo.roles[role])) + ) { + result.push('remove_user'); + } + + return result; + }, [ + canChangeRoles, + canEdit, + canRemoveMembers, + memberInfo.isViewer, + memberInfo.role, + memberInfo.username, + threadInfo, + ]); +} + function patchThreadInfoToIncludeMentionedMembersOfParent( threadInfo: ThreadInfo, parentThreadInfo: ThreadInfo, @@ -1959,6 +2009,7 @@ useThreadListSearch, removeMemberFromThread, getAvailableThreadMemberActions, + useAvailableThreadMemberActions, threadMembersWithoutAddedAdmin, patchThreadInfoToIncludeMentionedMembersOfParent, threadInfoInsideCommunity, diff --git a/web/modals/threads/members/member.react.js b/web/modals/threads/members/member.react.js --- a/web/modals/threads/members/member.react.js +++ b/web/modals/threads/members/member.react.js @@ -6,8 +6,8 @@ import { useModalContext } from 'lib/components/modal-provider.react.js'; import SWMansionIcon from 'lib/components/swmansion-icon.react.js'; import { - getAvailableThreadMemberActions, removeMemberFromThread, + useAvailableThreadMemberActions, } from 'lib/shared/thread-utils.js'; import { stringForUser } from 'lib/shared/user-utils.js'; import type { SetState } from 'lib/types/hook-types.js'; @@ -74,9 +74,14 @@ ); }, [memberInfo, pushModal, threadInfo]); + const availableThreadMemberActions = useAvailableThreadMemberActions( + memberInfo, + threadInfo, + ); + const menuItems = React.useMemo( () => - getAvailableThreadMemberActions(memberInfo, threadInfo).map(action => { + availableThreadMemberActions.map(action => { if (action === 'change_role') { return (