2023-08-22 17:38:37 -04:00
|
|
|
import {
|
|
|
|
useState,
|
|
|
|
type ComponentProps,
|
|
|
|
useCallback,
|
|
|
|
type Dispatch,
|
|
|
|
type SetStateAction,
|
|
|
|
} from 'react'
|
|
|
|
import { useTranslation } from 'react-i18next'
|
2023-06-30 04:30:20 -04:00
|
|
|
import { Dropdown, MenuItem } from 'react-bootstrap'
|
|
|
|
import { User } from '../../../../../../types/group-management/user'
|
2023-10-27 09:11:34 -04:00
|
|
|
import useAsync from '@/shared/hooks/use-async'
|
|
|
|
import { type FetchError, postJSON } from '@/infrastructure/fetch-json'
|
|
|
|
import Icon from '@/shared/components/icon'
|
2024-03-27 11:45:09 -04:00
|
|
|
import { GroupUserAlert } from '../../utils/types'
|
2023-08-22 09:30:34 -04:00
|
|
|
import { useGroupMembersContext } from '../../context/group-members-context'
|
2023-10-25 07:09:54 -04:00
|
|
|
import getMeta from '@/utils/meta'
|
2023-11-23 08:53:38 -05:00
|
|
|
|
2023-08-23 14:53:01 -04:00
|
|
|
type resendInviteResponse = {
|
2023-08-22 17:38:37 -04:00
|
|
|
success: boolean
|
|
|
|
}
|
|
|
|
|
2023-06-30 04:30:20 -04:00
|
|
|
type ManagedUserDropdownButtonProps = {
|
|
|
|
user: User
|
2023-07-13 04:50:43 -04:00
|
|
|
openOffboardingModalForUser: (user: User) => void
|
2024-04-03 10:12:09 -04:00
|
|
|
openUnlinkUserModal: (user: User) => void
|
2023-08-22 17:38:37 -04:00
|
|
|
groupId: string
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert: Dispatch<SetStateAction<GroupUserAlert>>
|
2023-06-30 04:30:20 -04:00
|
|
|
}
|
|
|
|
|
2023-10-27 09:11:34 -04:00
|
|
|
export default function DropdownButton({
|
2023-06-30 04:30:20 -04:00
|
|
|
user,
|
2023-07-13 04:50:43 -04:00
|
|
|
openOffboardingModalForUser,
|
2024-04-03 10:12:09 -04:00
|
|
|
openUnlinkUserModal,
|
2023-08-22 17:38:37 -04:00
|
|
|
groupId,
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert,
|
2023-06-30 04:30:20 -04:00
|
|
|
}: ManagedUserDropdownButtonProps) {
|
|
|
|
const { t } = useTranslation()
|
2023-08-22 09:30:34 -04:00
|
|
|
const { removeMember } = useGroupMembersContext()
|
2023-08-22 17:38:37 -04:00
|
|
|
const [isOpened, setIsOpened] = useState(false)
|
|
|
|
const {
|
|
|
|
runAsync: runResendManagedUserInviteAsync,
|
|
|
|
isLoading: isResendingManagedUserInvite,
|
2023-08-23 14:53:01 -04:00
|
|
|
} = useAsync<resendInviteResponse>()
|
2023-10-25 07:09:54 -04:00
|
|
|
const {
|
|
|
|
runAsync: runResendLinkSSOInviteAsync,
|
|
|
|
isLoading: isResendingSSOLinkInvite,
|
|
|
|
} = useAsync<resendInviteResponse>()
|
2023-08-23 14:53:01 -04:00
|
|
|
const {
|
|
|
|
runAsync: runResendGroupInviteAsync,
|
|
|
|
isLoading: isResendingGroupInvite,
|
|
|
|
} = useAsync<resendInviteResponse>()
|
2023-08-22 17:38:37 -04:00
|
|
|
|
2023-11-23 08:53:38 -05:00
|
|
|
const managedUsersActive = getMeta('ol-managedUsersActive')
|
|
|
|
const groupSSOActive = getMeta('ol-groupSSOActive')
|
2023-08-23 14:53:01 -04:00
|
|
|
|
2023-11-23 08:53:38 -05:00
|
|
|
const userPending = user.invite
|
|
|
|
const isGroupSSOLinked =
|
|
|
|
!userPending && user.enrollment?.sso?.some(sso => sso.groupId === groupId)
|
|
|
|
const isUserManaged = !userPending && user.enrollment?.managedBy === groupId
|
2023-11-06 09:26:22 -05:00
|
|
|
|
2023-08-22 17:38:37 -04:00
|
|
|
const handleResendManagedUserInvite = useCallback(
|
|
|
|
async user => {
|
|
|
|
try {
|
|
|
|
const result = await runResendManagedUserInviteAsync(
|
|
|
|
postJSON(
|
|
|
|
`/manage/groups/${groupId}/resendManagedUserInvite/${user._id}`
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
if (result.success) {
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert({
|
2023-08-22 17:38:37 -04:00
|
|
|
variant: 'resendManagedUserInviteSuccess',
|
|
|
|
email: user.email,
|
|
|
|
})
|
|
|
|
setIsOpened(false)
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
if ((err as FetchError)?.response?.status === 429) {
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert({
|
2023-08-23 14:53:01 -04:00
|
|
|
variant: 'resendInviteTooManyRequests',
|
2023-08-22 17:38:37 -04:00
|
|
|
email: user.email,
|
|
|
|
})
|
|
|
|
} else {
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert({
|
2023-08-22 17:38:37 -04:00
|
|
|
variant: 'resendManagedUserInviteFailed',
|
|
|
|
email: user.email,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
setIsOpened(false)
|
|
|
|
}
|
|
|
|
},
|
2024-03-27 11:45:09 -04:00
|
|
|
[setGroupUserAlert, groupId, runResendManagedUserInviteAsync]
|
2023-08-22 17:38:37 -04:00
|
|
|
)
|
|
|
|
|
2023-10-25 07:09:54 -04:00
|
|
|
const handleResendLinkSSOInviteAsync = useCallback(
|
|
|
|
async user => {
|
|
|
|
try {
|
|
|
|
const result = await runResendLinkSSOInviteAsync(
|
|
|
|
postJSON(`/manage/groups/${groupId}/resendSSOLinkInvite/${user._id}`)
|
|
|
|
)
|
|
|
|
|
|
|
|
if (result.success) {
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert({
|
2023-10-25 07:09:54 -04:00
|
|
|
variant: 'resendSSOLinkInviteSuccess',
|
|
|
|
email: user.email,
|
|
|
|
})
|
|
|
|
setIsOpened(false)
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
if ((err as FetchError)?.response?.status === 429) {
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert({
|
2023-10-25 07:09:54 -04:00
|
|
|
variant: 'resendInviteTooManyRequests',
|
|
|
|
email: user.email,
|
|
|
|
})
|
|
|
|
} else {
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert({
|
2023-10-25 07:09:54 -04:00
|
|
|
variant: 'resendSSOLinkInviteFailed',
|
|
|
|
email: user.email,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
setIsOpened(false)
|
|
|
|
}
|
|
|
|
},
|
2024-03-27 11:45:09 -04:00
|
|
|
[setGroupUserAlert, groupId, runResendLinkSSOInviteAsync]
|
2023-10-25 07:09:54 -04:00
|
|
|
)
|
|
|
|
|
2023-08-23 14:53:01 -04:00
|
|
|
const handleResendGroupInvite = useCallback(
|
|
|
|
async user => {
|
|
|
|
try {
|
|
|
|
await runResendGroupInviteAsync(
|
|
|
|
postJSON(`/manage/groups/${groupId}/resendInvite/`, {
|
|
|
|
body: {
|
|
|
|
email: user.email,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert({
|
2023-08-23 14:53:01 -04:00
|
|
|
variant: 'resendGroupInviteSuccess',
|
|
|
|
email: user.email,
|
|
|
|
})
|
|
|
|
setIsOpened(false)
|
|
|
|
} catch (err) {
|
|
|
|
if ((err as FetchError)?.response?.status === 429) {
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert({
|
2023-08-23 14:53:01 -04:00
|
|
|
variant: 'resendInviteTooManyRequests',
|
|
|
|
email: user.email,
|
|
|
|
})
|
|
|
|
} else {
|
2024-03-27 11:45:09 -04:00
|
|
|
setGroupUserAlert({
|
2023-08-23 14:53:01 -04:00
|
|
|
variant: 'resendGroupInviteFailed',
|
|
|
|
email: user.email,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
setIsOpened(false)
|
|
|
|
}
|
|
|
|
},
|
2024-03-27 11:45:09 -04:00
|
|
|
[setGroupUserAlert, groupId, runResendGroupInviteAsync]
|
2023-08-23 14:53:01 -04:00
|
|
|
)
|
|
|
|
|
2023-08-22 17:38:37 -04:00
|
|
|
const onResendManagedUserInviteClick = () => {
|
|
|
|
handleResendManagedUserInvite(user)
|
|
|
|
}
|
2023-10-25 07:09:54 -04:00
|
|
|
const onResendSSOLinkInviteClick = () => {
|
|
|
|
handleResendLinkSSOInviteAsync(user)
|
|
|
|
}
|
2023-07-13 04:50:43 -04:00
|
|
|
|
2023-08-23 14:53:01 -04:00
|
|
|
const onResendGroupInviteClick = () => {
|
|
|
|
handleResendGroupInvite(user)
|
|
|
|
}
|
|
|
|
|
2023-07-13 04:50:43 -04:00
|
|
|
const onDeleteUserClick = () => {
|
|
|
|
openOffboardingModalForUser(user)
|
|
|
|
}
|
|
|
|
|
2023-08-22 09:30:34 -04:00
|
|
|
const onRemoveFromGroup = () => {
|
|
|
|
removeMember(user)
|
|
|
|
}
|
|
|
|
|
2024-04-03 10:12:09 -04:00
|
|
|
const onUnlinkUserClick = () => {
|
|
|
|
openUnlinkUserModal(user)
|
|
|
|
}
|
|
|
|
|
2023-11-23 08:53:38 -05:00
|
|
|
const buttons = []
|
|
|
|
|
|
|
|
if (userPending) {
|
|
|
|
buttons.push(
|
|
|
|
<MenuItemButton
|
|
|
|
onClick={onResendGroupInviteClick}
|
|
|
|
key="resend-group-invite-action"
|
|
|
|
data-testid="resend-group-invite-action"
|
|
|
|
>
|
|
|
|
{t('resend_group_invite')}
|
|
|
|
{isResendingGroupInvite ? (
|
|
|
|
<Icon type="spinner" spin style={{ marginLeft: '5px' }} />
|
|
|
|
) : null}
|
|
|
|
</MenuItemButton>
|
|
|
|
)
|
|
|
|
}
|
2023-11-24 09:16:53 -05:00
|
|
|
if (managedUsersActive && !isUserManaged && !userPending) {
|
2023-11-23 08:53:38 -05:00
|
|
|
buttons.push(
|
|
|
|
<MenuItemButton
|
|
|
|
onClick={onResendManagedUserInviteClick}
|
|
|
|
key="resend-managed-user-invite-action"
|
|
|
|
data-testid="resend-managed-user-invite-action"
|
|
|
|
>
|
|
|
|
{t('resend_managed_user_invite')}
|
|
|
|
{isResendingManagedUserInvite ? (
|
|
|
|
<Icon type="spinner" spin style={{ marginLeft: '5px' }} />
|
|
|
|
) : null}
|
|
|
|
</MenuItemButton>
|
|
|
|
)
|
|
|
|
}
|
2024-04-03 10:12:09 -04:00
|
|
|
if (groupSSOActive && isGroupSSOLinked) {
|
|
|
|
buttons.push(
|
|
|
|
<MenuItemButton
|
|
|
|
onClick={onUnlinkUserClick}
|
|
|
|
key="unlink-user-action"
|
|
|
|
data-testid="unlink-user-action"
|
|
|
|
>
|
|
|
|
{t('unlink_user')}
|
|
|
|
</MenuItemButton>
|
|
|
|
)
|
|
|
|
}
|
2023-11-24 09:16:53 -05:00
|
|
|
if (groupSSOActive && !isGroupSSOLinked && !userPending) {
|
2023-11-23 08:53:38 -05:00
|
|
|
buttons.push(
|
|
|
|
<MenuItemButton
|
|
|
|
onClick={onResendSSOLinkInviteClick}
|
|
|
|
key="resend-sso-link-invite-action"
|
|
|
|
data-testid="resend-sso-link-invite-action"
|
|
|
|
>
|
|
|
|
{t('resend_link_sso')}
|
|
|
|
{isResendingSSOLinkInvite ? (
|
|
|
|
<Icon type="spinner" spin style={{ marginLeft: '5px' }} />
|
|
|
|
) : null}
|
|
|
|
</MenuItemButton>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if (isUserManaged && !user.isEntityAdmin) {
|
|
|
|
buttons.push(
|
|
|
|
<MenuItemButton
|
|
|
|
className="delete-user-action"
|
|
|
|
key="delete-user-action"
|
|
|
|
data-testid="delete-user-action"
|
|
|
|
onClick={onDeleteUserClick}
|
|
|
|
>
|
|
|
|
{t('delete_user')}
|
|
|
|
</MenuItemButton>
|
|
|
|
)
|
|
|
|
} else if (!isUserManaged) {
|
|
|
|
buttons.push(
|
|
|
|
<MenuItemButton
|
|
|
|
key="remove-user-action"
|
|
|
|
data-testid="remove-user-action"
|
|
|
|
onClick={onRemoveFromGroup}
|
|
|
|
className="delete-user-action"
|
|
|
|
>
|
|
|
|
{t('remove_from_group')}
|
|
|
|
</MenuItemButton>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buttons.length === 0) {
|
|
|
|
buttons.push(
|
|
|
|
<MenuItem key="no-actions-available" data-testid="no-actions-available">
|
|
|
|
<span className="text-muted">{t('no_actions')}</span>
|
|
|
|
</MenuItem>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-06-30 04:30:20 -04:00
|
|
|
return (
|
2023-08-03 06:06:13 -04:00
|
|
|
<span className="managed-user-actions">
|
2023-08-22 17:38:37 -04:00
|
|
|
<Dropdown
|
|
|
|
id={`managed-user-dropdown-${user.email}`}
|
|
|
|
open={isOpened}
|
|
|
|
onToggle={open => setIsOpened(open)}
|
|
|
|
>
|
2023-07-13 04:50:43 -04:00
|
|
|
<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>
|
2023-08-22 17:38:37 -04:00
|
|
|
<Dropdown.Menu className="dropdown-menu-right managed-user-dropdown-menu">
|
2023-11-23 08:53:38 -05:00
|
|
|
{buttons}
|
2023-07-13 04:50:43 -04:00
|
|
|
</Dropdown.Menu>
|
2023-08-22 17:38:37 -04:00
|
|
|
</Dropdown>
|
2023-08-03 06:06:13 -04:00
|
|
|
</span>
|
2023-06-30 04:30:20 -04:00
|
|
|
)
|
|
|
|
}
|
2023-08-22 17:38:37 -04:00
|
|
|
|
|
|
|
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>
|
|
|
|
)
|
|
|
|
}
|