overleaf/services/web/frontend/js/features/group-management/components/managed-users/managed-user-dropdown-button.tsx
Alexandre Bourdin 0ae6adb4d6 Merge pull request #14498 from overleaf/ab-fix-managed-user-admin
[web] Do not show Delete user button for managed group admin

GitOrigin-RevId: 4fcb120e6feec51c218cce7f381925eb12680afd
2023-08-28 08:04:18 +00:00

221 lines
6 KiB
TypeScript

import {
useState,
type ComponentProps,
useCallback,
type Dispatch,
type SetStateAction,
} from 'react'
import { useTranslation } from 'react-i18next'
import { Dropdown, MenuItem } from 'react-bootstrap'
import { User } from '../../../../../../types/group-management/user'
import useAsync from '../../../../shared/hooks/use-async'
import {
type FetchError,
postJSON,
} from '../../../../infrastructure/fetch-json'
import Icon from '../../../../shared/components/icon'
import { ManagedUserAlert } from '../../utils/types'
import { useGroupMembersContext } from '../../context/group-members-context'
type resendInviteResponse = {
success: boolean
}
type ManagedUserDropdownButtonProps = {
user: User
openOffboardingModalForUser: (user: User) => void
groupId: string
setManagedUserAlert: Dispatch<SetStateAction<ManagedUserAlert>>
}
export default function ManagedUserDropdownButton({
user,
openOffboardingModalForUser,
groupId,
setManagedUserAlert,
}: ManagedUserDropdownButtonProps) {
const { t } = useTranslation()
const { removeMember } = useGroupMembersContext()
const [isOpened, setIsOpened] = useState(false)
const {
runAsync: runResendManagedUserInviteAsync,
isLoading: isResendingManagedUserInvite,
} = useAsync<resendInviteResponse>()
const {
runAsync: runResendGroupInviteAsync,
isLoading: isResendingGroupInvite,
} = useAsync<resendInviteResponse>()
const userNotManaged =
!user.isEntityAdmin && !user.invite && !user.enrollment?.managedBy
const userPending = user.invite
const handleResendManagedUserInvite = useCallback(
async user => {
try {
const result = await runResendManagedUserInviteAsync(
postJSON(
`/manage/groups/${groupId}/resendManagedUserInvite/${user._id}`
)
)
if (result.success) {
setManagedUserAlert({
variant: 'resendManagedUserInviteSuccess',
email: user.email,
})
setIsOpened(false)
}
} catch (err) {
if ((err as FetchError)?.response?.status === 429) {
setManagedUserAlert({
variant: 'resendInviteTooManyRequests',
email: user.email,
})
} else {
setManagedUserAlert({
variant: 'resendManagedUserInviteFailed',
email: user.email,
})
}
setIsOpened(false)
}
},
[setManagedUserAlert, groupId, runResendManagedUserInviteAsync]
)
const handleResendGroupInvite = useCallback(
async user => {
try {
await runResendGroupInviteAsync(
postJSON(`/manage/groups/${groupId}/resendInvite/`, {
body: {
email: user.email,
},
})
)
setManagedUserAlert({
variant: 'resendGroupInviteSuccess',
email: user.email,
})
setIsOpened(false)
} catch (err) {
if ((err as FetchError)?.response?.status === 429) {
setManagedUserAlert({
variant: 'resendInviteTooManyRequests',
email: user.email,
})
} else {
setManagedUserAlert({
variant: 'resendGroupInviteFailed',
email: user.email,
})
}
setIsOpened(false)
}
},
[setManagedUserAlert, groupId, runResendGroupInviteAsync]
)
const onResendManagedUserInviteClick = () => {
handleResendManagedUserInvite(user)
}
const onResendGroupInviteClick = () => {
handleResendGroupInvite(user)
}
const onDeleteUserClick = () => {
openOffboardingModalForUser(user)
}
const onRemoveFromGroup = () => {
removeMember(user)
}
return (
<span className="managed-user-actions">
<Dropdown
id={`managed-user-dropdown-${user.email}`}
open={isOpened}
onToggle={open => setIsOpened(open)}
>
<Dropdown.Toggle
bsStyle={null}
className="btn btn-link action-btn"
noCaret
>
<i
className="fa fa-ellipsis-v"
aria-hidden="true"
aria-label={t('actions')}
/>
</Dropdown.Toggle>
<Dropdown.Menu className="dropdown-menu-right managed-user-dropdown-menu">
{userPending ? (
<MenuItemButton onClick={onResendGroupInviteClick}>
{t('resend_group_invite')}
{isResendingGroupInvite ? (
<Icon type="spinner" spin style={{ marginLeft: '5px' }} />
) : null}
</MenuItemButton>
) : null}
{userNotManaged ? (
<MenuItemButton onClick={onResendManagedUserInviteClick}>
{t('resend_managed_user_invite')}
{isResendingManagedUserInvite ? (
<Icon type="spinner" spin style={{ marginLeft: '5px' }} />
) : null}
</MenuItemButton>
) : null}
{user.isEntityAdmin ? (
<MenuItem data-testid="no-actions-available">
<span className="text-muted">{t('no_actions')}</span>
</MenuItem>
) : user.enrollment?.managedBy ? (
<MenuItemButton
className="delete-user-action"
data-testid="delete-user-action"
onClick={onDeleteUserClick}
>
{t('delete_user')}
</MenuItemButton>
) : (
<MenuItemButton
onClick={onRemoveFromGroup}
className="delete-user-action"
data-testid="remove-user-action"
>
{t('remove_from_group')}
</MenuItemButton>
)}
</Dropdown.Menu>
</Dropdown>
</span>
)
}
function MenuItemButton({
children,
onClick,
className,
...buttonProps
}: ComponentProps<'button'>) {
return (
<li role="presentation" className={className}>
<button
className="managed-user-menu-item-button"
role="menuitem"
onClick={onClick}
{...buttonProps}
>
{children}
</button>
</li>
)
}