Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: consolidate org user menus #10162

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 0 additions & 90 deletions packages/client/components/BillingLeaderActionMenu.tsx

This file was deleted.

40 changes: 0 additions & 40 deletions packages/client/components/BillingLeaderMenu.tsx

This file was deleted.

1 change: 1 addition & 0 deletions packages/client/components/FlatButton.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// DEPRECATED use packages/client/ui/Button/Button.tsx with variant='flat'
import styled from '@emotion/styled'
import React, {ReactNode} from 'react'
import {PALETTE} from '../styles/paletteV3'
Expand Down
92 changes: 67 additions & 25 deletions packages/client/components/OrgAdminActionMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import {MoreVert} from '@mui/icons-material'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import graphql from 'babel-plugin-relay/macro'
import React from 'react'
import {useFragment} from 'react-relay'
import useAtmosphere from '~/hooks/useAtmosphere'
import {OrgAdminActionMenu_organization$key} from '../__generated__/OrgAdminActionMenu_organization.graphql'
import {OrgAdminActionMenu_organizationUser$key} from '../__generated__/OrgAdminActionMenu_organizationUser.graphql'
import {MenuProps} from '../hooks/useMenu'
import useMutationProps from '../hooks/useMutationProps'
import SetOrgUserRoleMutation from '../mutations/SetOrgUserRoleMutation'
import Menu from './Menu'
import MenuItem from './MenuItem'
import {Button} from '../ui/Button/Button'
import {Menu} from '../ui/Menu/Menu'
import {MenuContent} from '../ui/Menu/MenuContent'
import {MenuItem} from '../ui/Menu/MenuItem'

interface Props {
menuProps: MenuProps
isViewerLastOrgAdmin: boolean
organizationUser: OrgAdminActionMenu_organizationUser$key
organization: OrgAdminActionMenu_organization$key
toggleLeave: () => void
toggleRemove: () => void
}

const OrgAdminActionMenu = (props: Props) => {
export const OrgAdminActionMenu = (props: Props) => {
const {
menuProps,
isViewerLastOrgAdmin,
organizationUser: organizationUserRef,
organization: organizationRef,
toggleLeave,
Expand All @@ -32,6 +31,12 @@ const OrgAdminActionMenu = (props: Props) => {
graphql`
fragment OrgAdminActionMenu_organization on Organization {
id
isBillingLeader
isOrgAdmin
billingLeaders {
id
role
}
}
`,
organizationRef
Expand All @@ -49,10 +54,21 @@ const OrgAdminActionMenu = (props: Props) => {
)
const atmosphere = useAtmosphere()
const {onError, onCompleted, submitting, submitMutation} = useMutationProps()
const {id: orgId} = organization
const {
id: orgId,
isBillingLeader: isViewerBillingLeaderPlus,
isOrgAdmin: isViewerOrgAdmin,
billingLeaders
} = organization
const {viewerId} = atmosphere
const {role, user} = organizationUser
const {id: userId} = user
const orgAdminCount = billingLeaders.filter(
(billingLeader) => billingLeader.role === 'ORG_ADMIN'
).length
const canEdit = isViewerOrgAdmin || (isViewerBillingLeaderPlus && role !== 'ORG_ADMIN')
const isViewerLastOrgAdmin = isViewerOrgAdmin && orgAdminCount === 1
const isViewerLastRole = isViewerBillingLeaderPlus && billingLeaders.length === 1

const setRole =
(role: 'ORG_ADMIN' | 'BILLING_LEADER' | null = null) =>
Expand All @@ -66,27 +82,53 @@ const OrgAdminActionMenu = (props: Props) => {
const isOrgAdmin = role === 'ORG_ADMIN'
const isBillingLeader = role === 'BILLING_LEADER'
const isSelf = viewerId === userId
const canRemoveSelf = isSelf && !isViewerLastOrgAdmin
const roleName = role === 'ORG_ADMIN' ? 'Org Admin' : 'Billing Leader'

const canRemoveRole =
role &&
((isViewerOrgAdmin && (!isSelf || !isViewerLastOrgAdmin)) ||
(isViewerBillingLeaderPlus && isBillingLeader && (!isSelf || !isViewerLastRole)))
return (
<>
<Menu ariaLabel={'Select your action'} {...menuProps}>
{!isOrgAdmin && <MenuItem label='Promote to Org Admin' onClick={setRole('ORG_ADMIN')} />}
{!isOrgAdmin && !isBillingLeader && (
<MenuItem label='Promote to Billing Leader' onClick={setRole('BILLING_LEADER')} />
<Menu
trigger={
canEdit && (
<Button variant='flat' className='h-7 w-7'>
<MoreVert className='text-lg' />
</Button>
)
}
>
<MenuContent
className='data-[side=top]:animate-slideUp data-[side=bottom]:animate-slideDown'
align='end'
sideOffset={4}
>
{isViewerOrgAdmin && !isOrgAdmin && (
<MenuItem onClick={setRole('ORG_ADMIN')}>{'Promote to Org Admin'}</MenuItem>
)}
{isViewerBillingLeaderPlus && !isOrgAdmin && !isBillingLeader && (
<MenuItem onClick={setRole('BILLING_LEADER')}>{'Promote to Billing Leader'}</MenuItem>
)}
{isOrgAdmin && !isSelf && (
<MenuItem label='Change to Billing Leader' onClick={setRole('BILLING_LEADER')} />
{isViewerOrgAdmin && isOrgAdmin && (!isSelf || !isViewerLastOrgAdmin) && (
<MenuItem onClick={setRole('BILLING_LEADER')}>{'Change to Billing Leader'}</MenuItem>
)}
{((role && !isSelf) || canRemoveSelf) && (
<MenuItem label={`Remove ${roleName} role`} onClick={setRole(null)} />
{canRemoveRole && <MenuItem onClick={setRole(null)}>{`Remove ${roleName} role`}</MenuItem>}
{isSelf &&
((isOrgAdmin && !isViewerLastOrgAdmin) ||
(isBillingLeader && !isViewerLastRole) ||
!isViewerBillingLeaderPlus) && (
<MenuItem onClick={toggleLeave}>{'Leave Organization'}</MenuItem>
)}
{!isSelf && (isViewerOrgAdmin || (isViewerBillingLeaderPlus && !isOrgAdmin)) && (
<MenuItem onClick={toggleRemove}>{'Remove from Organization'}</MenuItem>
)}
{canRemoveSelf && <MenuItem label='Leave Organization' onClick={toggleLeave} />}
{!isSelf && <MenuItem label='Remove from Organization' onClick={toggleRemove} />}
{isSelf && !canRemoveSelf && <MenuItem label='Contact support@parabol.co to be removed' />}
</Menu>
</>
{isSelf &&
((isOrgAdmin && isViewerLastOrgAdmin) || (isBillingLeader && isViewerLastRole)) && (
<DropdownMenu.Label className='select-none p-2'>
{'Contact support@parabol.co to be removed'}
</DropdownMenu.Label>
)}
</MenuContent>
</Menu>
)
}

Expand Down
Loading
Loading