From 6225717fb6de506a0654a91efeb50dd87080dcc7 Mon Sep 17 00:00:00 2001 From: Bartosz Jarocki Date: Wed, 13 Dec 2023 16:32:49 +0100 Subject: [PATCH 01/15] feat: managing teams --- .../components/OrgBilling/Organization.tsx | 17 ++++-- .../OrgTeamMembers/OrgTeamMembers.tsx | 47 +++++++++++++++++ .../OrgTeamMembers/OrgTeamMembersRoot.tsx | 25 +++++++++ .../OrgTeamMembers/OrgTeamMembersRow.tsx | 36 +++++++++++++ .../components/OrgTeams/OrgTeams.tsx | 52 +++++++++++++------ .../components/OrgTeams/OrgTeamsRow.tsx | 47 +++++------------ packages/client/ui/Button/Button.tsx | 12 ++--- 7 files changed, 175 insertions(+), 61 deletions(-) create mode 100644 packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx create mode 100644 packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRoot.tsx create mode 100644 packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx diff --git a/packages/client/modules/userDashboard/components/OrgBilling/Organization.tsx b/packages/client/modules/userDashboard/components/OrgBilling/Organization.tsx index 36ea78f60e3..908b1913064 100644 --- a/packages/client/modules/userDashboard/components/OrgBilling/Organization.tsx +++ b/packages/client/modules/userDashboard/components/OrgBilling/Organization.tsx @@ -21,6 +21,10 @@ const OrgMembers = lazy( import(/* webpackChunkName: 'OrgMembersRoot' */ '../../containers/OrgMembers/OrgMembersRoot') ) +const OrgTeamMembers = lazy( + () => import(/* webpackChunkName: 'OrgTeamMembers' */ '../OrgTeamMembers/OrgTeamMembersRoot') +) + const OrgDetails = lazy(() => import(/* webpackChunkName: 'OrgDetails' */ './OrgDetails')) const Authentication = lazy( () => @@ -71,11 +75,14 @@ const Organization = (props: Props) => { render={() => } /> {isBillingLeader && ( - } - /> + <> + } + /> + + )} +} + +const query = graphql` + query OrgTeamMembersQuery($teamId: ID!) { + viewer { + team(teamId: $teamId) { + ...ArchiveTeam_team + isLead + id + name + tier + billingTier + orgId + teamMembers(sortBy: "preferredName") { + id + ...OrgTeamMembersRow_teamMember + } + } + } + } +` + +export const OrgTeamMembers = (props: Props) => { + const {queryRef} = props + const data = usePreloadedQuery(query, queryRef) + const {viewer} = data + const {team} = viewer + if (!team) return null + + const teamMembers = team.teamMembers + + return ( +
+ {teamMembers.map((teamMember) => ( + + ))} +
+ ) +} diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRoot.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRoot.tsx new file mode 100644 index 00000000000..c0c959d084c --- /dev/null +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRoot.tsx @@ -0,0 +1,25 @@ +import React, {Suspense} from 'react' +import orgTeamMembersQuery, {OrgTeamMembersQuery} from '~/__generated__/OrgTeamMembersQuery.graphql' +import useQueryLoaderNow from '../../../../hooks/useQueryLoaderNow' +import {LoaderSize} from '../../../../types/constEnums' +import {Loader} from '../../../../utils/relay/renderLoader' +import {OrgTeamMembers} from './OrgTeamMembers' +import useRouter from '../../../../hooks/useRouter' + +const OrgTeamMembersRoot = () => { + const {match} = useRouter<{teamId: string}>() + const { + params: {teamId} + } = match + const queryRef = useQueryLoaderNow(orgTeamMembersQuery, { + teamId + }) + + return ( + }> + {queryRef && } + + ) +} + +export default OrgTeamMembersRoot diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx new file mode 100644 index 00000000000..57d7bc2916d --- /dev/null +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx @@ -0,0 +1,36 @@ +import React from 'react' +import graphql from 'babel-plugin-relay/macro' +import Row from '../../../../components/Row/Row' +import {useFragment} from 'react-relay' +import {OrgTeamMembersRow_teamMember$key} from '../../../../__generated__/OrgTeamMembersRow_teamMember.graphql' + +type Props = { + teamMemberRef: OrgTeamMembersRow_teamMember$key +} + +export const OrgTeamMembersRow = (props: Props) => { + const {teamMemberRef} = props + const member = useFragment( + graphql` + fragment OrgTeamMembersRow_teamMember on TeamMember { + id + preferredName + isLead + isOrgAdmin + isSelf + email + } + `, + teamMemberRef + ) + const teamLeadEmail = member.isLead ? member.email : '' + const isViewerTeamLead = member.isSelf && (member.isLead || member.isOrgAdmin) + + return ( + +
+
{member.preferredName}
+
+
+ ) +} diff --git a/packages/client/modules/userDashboard/components/OrgTeams/OrgTeams.tsx b/packages/client/modules/userDashboard/components/OrgTeams/OrgTeams.tsx index e9bd39f71d7..5f7390a98d1 100644 --- a/packages/client/modules/userDashboard/components/OrgTeams/OrgTeams.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeams/OrgTeams.tsx @@ -1,16 +1,11 @@ import React from 'react' import graphql from 'babel-plugin-relay/macro' -import styled from '@emotion/styled' -import Row from '../../../../components/Row/Row' -import Panel from '../../../../components/Panel/Panel' -import {ElementWidth} from '../../../../types/constEnums' import {useFragment} from 'react-relay' import OrgTeamsRow from './OrgTeamsRow' import {OrgTeams_organization$key} from '../../../../__generated__/OrgTeams_organization.graphql' - -const StyledPanel = styled(Panel)({ - maxWidth: ElementWidth.PANEL_WIDTH -}) +import AddTeamDialogRoot from '../../../../components/AddTeamDialogRoot' +import {Button} from '../../../../ui/Button/Button' +import {useDialogState} from '../../../../ui/Dialog/useDialogState' type Props = { organizationRef: OrgTeams_organization$key @@ -31,23 +26,46 @@ const OrgTeams = (props: Props) => { `, organizationRef ) + const { + open: openAddTeamDialog, + close: closeAddTeamDialog, + isOpen: isAddTeamDialogOpened + } = useDialogState() + const {allTeams, isBillingLeader} = organization if (!isBillingLeader) return null + return ( - <> -

{'Teams'}

- - +
+
+

Teams

+
+ +
+
+ +
+
-
Team Name
-
Lead
+
{allTeams.length} Teams
- +
{allTeams.map((team) => ( ))} - - +
+ + {isAddTeamDialogOpened ? ( + + ) : null} +
) } diff --git a/packages/client/modules/userDashboard/components/OrgTeams/OrgTeamsRow.tsx b/packages/client/modules/userDashboard/components/OrgTeams/OrgTeamsRow.tsx index 00123a43b5d..be7c5750b73 100644 --- a/packages/client/modules/userDashboard/components/OrgTeams/OrgTeamsRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeams/OrgTeamsRow.tsx @@ -1,7 +1,6 @@ import React from 'react' import {Link} from 'react-router-dom' import graphql from 'babel-plugin-relay/macro' -import Row from '../../../../components/Row/Row' import {useFragment} from 'react-relay' import plural from '../../../../utils/plural' import {OrgTeamsRow_team$key} from '../../../../__generated__/OrgTeamsRow_team.graphql' @@ -30,42 +29,24 @@ const OrgTeamsRow = (props: Props) => { ) const {id: teamId, teamMembers, name} = team const teamMembersCount = teamMembers.length - const teamLeadEmail = teamMembers.find((member) => member.isLead)?.email ?? '' - const isViewerTeamLead = teamMembers.some( - (member) => member.isSelf && (member.isLead || member.isOrgAdmin) - ) + return ( - -
-
{name}
-
-
- {`${teamMembersCount} ${plural(teamMembersCount, 'member')}`} - {isViewerTeamLead && ( - <> - - - {'Manage Team'} - - - )} + +
+
+
{name}
+
+
+ {`${teamMembersCount} ${plural(teamMembersCount, 'member')}`} +
- - - {`${teamLeadEmail} ${isViewerTeamLead ? '(You)' : ''}`} -
+
- + ) } diff --git a/packages/client/ui/Button/Button.tsx b/packages/client/ui/Button/Button.tsx index a60c67700d7..c7f8f4a15b1 100644 --- a/packages/client/ui/Button/Button.tsx +++ b/packages/client/ui/Button/Button.tsx @@ -11,16 +11,16 @@ const BASE_STYLES = // TODO: make sure the styles match the designs const VARIANT_STYLES: Record = { - primary: 'bg-primary text-white hover:bg-primary/90', + primary: 'bg-gradient-to-r from-tomato-600 to-rose-500 text-white hover:opacity-90', destructive: 'bg-tomato-500 text-white hover:bg-tomato-500/90', - outline: 'text-slate-900 border border-slate-400 hover:bg-slate-200 px-2.5 py-1 bg-transparent', + outline: 'text-slate-900 border border-slate-400 hover:bg-slate-200 px-2.5 py-1 bg-transparent', secondary: 'bg-sky-500 text-white hover:bg-sky-500/80', ghost: 'hover:bg-accent', link: 'text-primary underline-offset-4 hover:underline' } const SIZE_STYLES: Record = { - default: 'px-4 py-2 text-xs', + default: 'px-2.5 py-1', sm: 'h-7 px-3 text-xs', md: 'h-9 px-4 text-sm', lg: 'h-11 px-8 text-base' @@ -29,18 +29,18 @@ const SIZE_STYLES: Record = { const SHAPE_STYLES: Record = { pill: 'rounded-full', circle: 'rounded-full aspect-square', - default: 'rounded-md' + default: '' } export interface ButtonProps extends React.ButtonHTMLAttributes { asChild?: boolean variant: Variant size?: Size - shape: Shape + shape?: Shape } const Button = React.forwardRef( - ({className, variant, size, shape, asChild = false, ...props}, ref) => { + ({className, variant, size = 'default', shape = 'default', asChild = false, ...props}, ref) => { const Comp = asChild ? Slot : 'button' return ( Date: Wed, 13 Dec 2023 21:05:46 +0100 Subject: [PATCH 02/15] feat: team members view --- .../OrgTeamMembers/OrgTeamMembers.tsx | 53 +++++++++++++++++-- .../OrgTeamMembers/OrgTeamMembersRow.tsx | 51 ++++++++++++++++-- .../components/OrgTeams/OrgTeams.tsx | 4 +- .../components/OrgTeams/OrgTeamsRow.tsx | 8 ++- packages/client/package.json | 1 + packages/client/ui/Avatar/Avatar.tsx | 16 ++++++ packages/client/ui/Avatar/AvatarFallback.tsx | 19 +++++++ packages/client/ui/Avatar/AvatarImage.tsx | 16 ++++++ packages/client/ui/Button/Button.tsx | 15 +++--- yarn.lock | 11 ++++ 10 files changed, 174 insertions(+), 20 deletions(-) create mode 100644 packages/client/ui/Avatar/Avatar.tsx create mode 100644 packages/client/ui/Avatar/AvatarFallback.tsx create mode 100644 packages/client/ui/Avatar/AvatarImage.tsx diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx index 079eb180a34..df99c16779a 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx @@ -1,8 +1,14 @@ import React from 'react' import graphql from 'babel-plugin-relay/macro' +import {MoreVert, ArrowBack} from '@mui/icons-material' import {PreloadedQuery, usePreloadedQuery} from 'react-relay' import {OrgTeamMembersQuery} from '../../../../__generated__/OrgTeamMembersQuery.graphql' import {OrgTeamMembersRow} from './OrgTeamMembersRow' +import {Button} from '../../../../ui/Button/Button' +import AddTeamMemberModal from '../../../../components/AddTeamMemberModal' +import useModal from '../../../../hooks/useModal' +import {Link} from 'react-router-dom' +import {ORGANIZATIONS} from '../../../../utils/constants' interface Props { queryRef: PreloadedQuery @@ -21,6 +27,8 @@ const query = graphql` orgId teamMembers(sortBy: "preferredName") { id + isNotRemoved + ...AddTeamMemberModal_teamMembers ...OrgTeamMembersRow_teamMember } } @@ -33,15 +41,52 @@ export const OrgTeamMembers = (props: Props) => { const data = usePreloadedQuery(query, queryRef) const {viewer} = data const {team} = viewer + const {togglePortal: toggleModal, closePortal: closeModal, modalPortal} = useModal() if (!team) return null const teamMembers = team.teamMembers return ( -
- {teamMembers.map((teamMember) => ( - - ))} +
+
+
+ +

Teams

+
+ +
+ + +
+
+ +
+
+
+
{teamMembers.length} Active
+
+
+ {teamMembers.map((teamMember) => ( + + ))} +
+ + {modalPortal( + + )}
) } diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx index 57d7bc2916d..3e97d97164e 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx @@ -1,8 +1,12 @@ import React from 'react' import graphql from 'babel-plugin-relay/macro' -import Row from '../../../../components/Row/Row' import {useFragment} from 'react-relay' import {OrgTeamMembersRow_teamMember$key} from '../../../../__generated__/OrgTeamMembersRow_teamMember.graphql' +import {Avatar} from '../../../../UI/Avatar/Avatar' +import {AvatarFallback} from '../../../../UI/Avatar/AvatarFallback' +import {AvatarImage} from '../../../../UI/Avatar/AvatarImage' +import {Button} from '../../../../ui/Button/Button' +import {MoreVert} from '@mui/icons-material' type Props = { teamMemberRef: OrgTeamMembersRow_teamMember$key @@ -14,11 +18,17 @@ export const OrgTeamMembersRow = (props: Props) => { graphql` fragment OrgTeamMembersRow_teamMember on TeamMember { id + picture preferredName isLead isOrgAdmin isSelf email + user { + teams { + name + } + } } `, teamMemberRef @@ -26,11 +36,42 @@ export const OrgTeamMembersRow = (props: Props) => { const teamLeadEmail = member.isLead ? member.email : '' const isViewerTeamLead = member.isSelf && (member.isLead || member.isOrgAdmin) + console.log(member) + return ( - -
-
{member.preferredName}
+
+
+ + + CN + +
+
+
+ {member.preferredName}{' '} + {member.isLead ? ( + + Team Lead + + ) : null} +
+
+ +
+
+
Teams:
+
+ {member.user.teams.map((team) => team.name).join(', ')} +
+
+
+
+
- +
) } diff --git a/packages/client/modules/userDashboard/components/OrgTeams/OrgTeams.tsx b/packages/client/modules/userDashboard/components/OrgTeams/OrgTeams.tsx index 5f7390a98d1..765ad512a59 100644 --- a/packages/client/modules/userDashboard/components/OrgTeams/OrgTeams.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeams/OrgTeams.tsx @@ -36,7 +36,7 @@ const OrgTeams = (props: Props) => { if (!isBillingLeader) return null return ( -
+

Teams

@@ -53,7 +53,7 @@ const OrgTeams = (props: Props) => {
-
+
{allTeams.length} Teams
diff --git a/packages/client/modules/userDashboard/components/OrgTeams/OrgTeamsRow.tsx b/packages/client/modules/userDashboard/components/OrgTeams/OrgTeamsRow.tsx index be7c5750b73..d6da2e5e6c6 100644 --- a/packages/client/modules/userDashboard/components/OrgTeams/OrgTeamsRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeams/OrgTeamsRow.tsx @@ -2,6 +2,8 @@ import React from 'react' import {Link} from 'react-router-dom' import graphql from 'babel-plugin-relay/macro' import {useFragment} from 'react-relay' +import {ChevronRight} from '@mui/icons-material' + import plural from '../../../../utils/plural' import {OrgTeamsRow_team$key} from '../../../../__generated__/OrgTeamsRow_team.graphql' @@ -36,7 +38,7 @@ const OrgTeamsRow = (props: Props) => { to={`teams/${teamId}`} >
-
+
{name}
@@ -44,7 +46,9 @@ const OrgTeamsRow = (props: Props) => {
-
+
+ +
) diff --git a/packages/client/package.json b/packages/client/package.json index 085bd29d0b3..035c00623d3 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -82,6 +82,7 @@ "@radix-ui/react-select": "^1.2.2", "@radix-ui/react-tooltip": "^1.0.7", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-avatar": "^1.0.4", "@sentry/browser": "^5.8.0", "@stripe/react-stripe-js": "^1.16.5", "@stripe/stripe-js": "^1.47.0", diff --git a/packages/client/ui/Avatar/Avatar.tsx b/packages/client/ui/Avatar/Avatar.tsx new file mode 100644 index 00000000000..23bbecd22a6 --- /dev/null +++ b/packages/client/ui/Avatar/Avatar.tsx @@ -0,0 +1,16 @@ +import React from 'react' +import * as AvatarPrimitive from '@radix-ui/react-avatar' +import clsx from 'clsx' + +export const Avatar = React.forwardRef< + HTMLSpanElement, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)) + +Avatar.displayName = AvatarPrimitive.Root.displayName diff --git a/packages/client/ui/Avatar/AvatarFallback.tsx b/packages/client/ui/Avatar/AvatarFallback.tsx new file mode 100644 index 00000000000..482648102a8 --- /dev/null +++ b/packages/client/ui/Avatar/AvatarFallback.tsx @@ -0,0 +1,19 @@ +import React from 'react' +import * as AvatarPrimitive from '@radix-ui/react-avatar' +import clsx from 'clsx' + +export const AvatarFallback = React.forwardRef< + HTMLSpanElement, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)) + +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName diff --git a/packages/client/ui/Avatar/AvatarImage.tsx b/packages/client/ui/Avatar/AvatarImage.tsx new file mode 100644 index 00000000000..66f41abad5d --- /dev/null +++ b/packages/client/ui/Avatar/AvatarImage.tsx @@ -0,0 +1,16 @@ +import React from 'react' +import * as AvatarPrimitive from '@radix-ui/react-avatar' +import clsx from 'clsx' + +export const AvatarImage = React.forwardRef< + HTMLImageElement, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)) + +AvatarImage.displayName = AvatarPrimitive.Image.displayName diff --git a/packages/client/ui/Button/Button.tsx b/packages/client/ui/Button/Button.tsx index c7f8f4a15b1..90554dc662e 100644 --- a/packages/client/ui/Button/Button.tsx +++ b/packages/client/ui/Button/Button.tsx @@ -7,20 +7,21 @@ type Size = 'sm' | 'md' | 'lg' | 'default' type Shape = 'pill' | 'circle' | 'default' const BASE_STYLES = - 'cursor-pointer inline-flex items-center justify-center whitespace-nowrap font-semibold transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50' + 'cursor-pointer inline-flex items-center justify-center whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50' // TODO: make sure the styles match the designs const VARIANT_STYLES: Record = { - primary: 'bg-gradient-to-r from-tomato-600 to-rose-500 text-white hover:opacity-90', - destructive: 'bg-tomato-500 text-white hover:bg-tomato-500/90', - outline: 'text-slate-900 border border-slate-400 hover:bg-slate-200 px-2.5 py-1 bg-transparent', - secondary: 'bg-sky-500 text-white hover:bg-sky-500/80', - ghost: 'hover:bg-accent', + primary: 'bg-gradient-to-r from-tomato-600 to-rose-500 text-white font-semibold hover:opacity-90', + destructive: 'bg-tomato-500 text-white font-semibold hover:bg-tomato-500/90', + outline: + 'text-slate-900 border border-slate-400 hover:bg-slate-200 px-2.5 py-1 bg-transparent font-semibold', + secondary: 'bg-sky-500 text-white hover:bg-sky-500/80 font-semibold', + ghost: 'hover:opacity-80 bg-transparent font-semibold', link: 'text-primary underline-offset-4 hover:underline' } const SIZE_STYLES: Record = { - default: 'px-2.5 py-1', + default: '', sm: 'h-7 px-3 text-xs', md: 'h-9 px-4 text-sm', lg: 'h-11 px-8 text-base' diff --git a/yarn.lock b/yarn.lock index 17637e0e348..610fb961913 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5685,6 +5685,17 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-primitive" "1.0.3" +"@radix-ui/react-avatar@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-avatar/-/react-avatar-1.0.4.tgz#de9a5349d9e3de7bbe990334c4d2011acbbb9623" + integrity sha512-kVK2K7ZD3wwj3qhle0ElXhOjbezIgyl2hVvgwfIdexL3rN6zJmy5AqqIf+D31lxVppdzV8CjAfZ6PklkmInZLw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-collection@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.2.tgz#d50da00bfa2ac14585319efdbbb081d4c5a29a97" From 97fed267a4dc639b3171be859bbde9cef7c41233 Mon Sep 17 00:00:00 2001 From: Bartosz Jarocki Date: Wed, 13 Dec 2023 21:42:25 +0100 Subject: [PATCH 03/15] feat: use team name in team details --- .../components/OrgTeamMembers/OrgTeamMembers.tsx | 2 +- .../components/OrgTeamMembers/OrgTeamMembersRow.tsx | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx index df99c16779a..c37ba96a41a 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx @@ -55,7 +55,7 @@ export const OrgTeamMembers = (props: Props) => { -

Teams

+

{team.name}

diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx index 3e97d97164e..55f501a615d 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx @@ -33,10 +33,6 @@ export const OrgTeamMembersRow = (props: Props) => { `, teamMemberRef ) - const teamLeadEmail = member.isLead ? member.email : '' - const isViewerTeamLead = member.isSelf && (member.isLead || member.isOrgAdmin) - - console.log(member) return (
From 5919989453bee75afff238525ff28d07a57197a1 Mon Sep 17 00:00:00 2001 From: Bartosz Jarocki Date: Wed, 13 Dec 2023 21:58:59 +0100 Subject: [PATCH 04/15] fix: routing --- .../components/OrgBilling/Organization.tsx | 21 ++++++++++--------- .../containers/OrgMembers/OrgMembersRoot.tsx | 1 + 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/client/modules/userDashboard/components/OrgBilling/Organization.tsx b/packages/client/modules/userDashboard/components/OrgBilling/Organization.tsx index 908b1913064..ceab6eb6e09 100644 --- a/packages/client/modules/userDashboard/components/OrgBilling/Organization.tsx +++ b/packages/client/modules/userDashboard/components/OrgBilling/Organization.tsx @@ -74,16 +74,7 @@ const Organization = (props: Props) => { path={`${match.url}/${BILLING_PAGE}`} render={() => } /> - {isBillingLeader && ( - <> - } - /> - - - )} + { path={`${match.url}/${AUTHENTICATION_PAGE}`} render={(p) => } /> + {isBillingLeader && ( + <> + } + /> + + + )} ) diff --git a/packages/client/modules/userDashboard/containers/OrgMembers/OrgMembersRoot.tsx b/packages/client/modules/userDashboard/containers/OrgMembers/OrgMembersRoot.tsx index b0a7ab43373..8242ebf2b8e 100644 --- a/packages/client/modules/userDashboard/containers/OrgMembers/OrgMembersRoot.tsx +++ b/packages/client/modules/userDashboard/containers/OrgMembers/OrgMembersRoot.tsx @@ -15,6 +15,7 @@ const OrgMembersRoot = (props: Props) => { orgId, first: 10000 }) + return ( }> {queryRef && } From 8e6020b33769904c98af1c9671c8d894abe58514 Mon Sep 17 00:00:00 2001 From: Bartosz Jarocki Date: Wed, 13 Dec 2023 22:36:39 +0100 Subject: [PATCH 05/15] fix: some menus --- .../OrgTeamMembers/OrgTeamMembers.tsx | 12 +++++++++--- .../OrgTeamMembers/OrgTeamMembersMenu.tsx | 18 ++++++++++++++++++ .../OrgTeamMembers/OrgTeamMembersRow.tsx | 10 +++++++--- packages/client/tsconfig.json | 1 + 4 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersMenu.tsx diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx index c37ba96a41a..e8283639376 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx @@ -9,6 +9,9 @@ import AddTeamMemberModal from '../../../../components/AddTeamMemberModal' import useModal from '../../../../hooks/useModal' import {Link} from 'react-router-dom' import {ORGANIZATIONS} from '../../../../utils/constants' +import {MenuPosition} from '../../../../hooks/useCoords' +import useMenu from '../../../../hooks/useMenu' +import {OrgTeamMembersMenu} from './OrgTeamMembersMenu' interface Props { queryRef: PreloadedQuery @@ -42,9 +45,10 @@ export const OrgTeamMembers = (props: Props) => { const {viewer} = data const {team} = viewer const {togglePortal: toggleModal, closePortal: closeModal, modalPortal} = useModal() - if (!team) return null + const {togglePortal, originRef, menuPortal, menuProps} = useMenu(MenuPosition.UPPER_RIGHT) - const teamMembers = team.teamMembers + if (!team) return null + const {teamMembers} = team return (
@@ -67,7 +71,7 @@ export const OrgTeamMembers = (props: Props) => { > Add member -
@@ -87,6 +91,8 @@ export const OrgTeamMembers = (props: Props) => { {modalPortal( )} + + {menuPortal()}
) } diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersMenu.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersMenu.tsx new file mode 100644 index 00000000000..8c743ccc68e --- /dev/null +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersMenu.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import {MenuProps} from '../../../../hooks/useMenu' +import Menu from '../../../../components/Menu' +import MenuItem from '../../../../components/MenuItem' + +interface OrgTeamMembersMenuProps { + menuProps: MenuProps +} + +export const OrgTeamMembersMenu = (props: OrgTeamMembersMenuProps) => { + const {menuProps} = props + + return ( + + + + ) +} diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx index 55f501a615d..f1f023d1846 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx @@ -2,11 +2,13 @@ import React from 'react' import graphql from 'babel-plugin-relay/macro' import {useFragment} from 'react-relay' import {OrgTeamMembersRow_teamMember$key} from '../../../../__generated__/OrgTeamMembersRow_teamMember.graphql' -import {Avatar} from '../../../../UI/Avatar/Avatar' -import {AvatarFallback} from '../../../../UI/Avatar/AvatarFallback' -import {AvatarImage} from '../../../../UI/Avatar/AvatarImage' +import {Avatar} from '../../../../ui/Avatar/Avatar' +import {AvatarFallback} from '../../../../ui/Avatar/AvatarFallback' +import {AvatarImage} from '../../../../ui/Avatar/AvatarImage' import {Button} from '../../../../ui/Button/Button' import {MoreVert} from '@mui/icons-material' +import {MenuPosition} from '../../../../hooks/useCoords' +import useMenu from '../../../../hooks/useMenu' type Props = { teamMemberRef: OrgTeamMembersRow_teamMember$key @@ -34,6 +36,8 @@ export const OrgTeamMembersRow = (props: Props) => { teamMemberRef ) + const {togglePortal, originRef, menuPortal, menuProps} = useMenu(MenuPosition.UPPER_RIGHT) + return (
diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index 58280d064ea..dc680e3ec06 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -12,6 +12,7 @@ }, "files": [ "client.tsx", + "./modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersMenu.tsx" ], "exclude": ["serviceWorker", "**/node_modules"] } From 7cd6631fe9880d3f3058810c072589cfc936b216 Mon Sep 17 00:00:00 2001 From: Bartosz Jarocki Date: Wed, 13 Dec 2023 23:51:32 +0100 Subject: [PATCH 06/15] feat: added alert dialog component --- .../OrgTeamMembers/OrgTeamMembersRow.tsx | 2 +- packages/client/package.json | 1 + .../client/ui/AlertDialog/AlertDialog.tsx | 5 ++ .../ui/AlertDialog/AlertDialogAction.tsx | 18 +++++++ .../ui/AlertDialog/AlertDialogCancel.tsx | 18 +++++++ .../ui/AlertDialog/AlertDialogContent.tsx | 23 ++++++++ .../ui/AlertDialog/AlertDialogDescription.tsx | 15 ++++++ .../ui/AlertDialog/AlertDialogFooter.tsx | 10 ++++ .../ui/AlertDialog/AlertDialogHeader.tsx | 7 +++ .../ui/AlertDialog/AlertDialogOverlay.tsx | 18 +++++++ .../ui/AlertDialog/AlertDialogPortal.tsx | 3 ++ .../ui/AlertDialog/AlertDialogTitle.tsx | 15 ++++++ .../ui/AlertDialog/AlertDialogTrigger.tsx | 3 ++ yarn.lock | 52 +++++++++++++++++++ 14 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 packages/client/ui/AlertDialog/AlertDialog.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogAction.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogCancel.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogContent.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogDescription.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogFooter.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogHeader.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogOverlay.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogPortal.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogTitle.tsx create mode 100644 packages/client/ui/AlertDialog/AlertDialogTrigger.tsx diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx index f1f023d1846..51594754b47 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx @@ -36,7 +36,7 @@ export const OrgTeamMembersRow = (props: Props) => { teamMemberRef ) - const {togglePortal, originRef, menuPortal, menuProps} = useMenu(MenuPosition.UPPER_RIGHT) + // const {togglePortal, originRef, menuPortal, menuProps} = useMenu(MenuPosition.UPPER_RIGHT) return (
diff --git a/packages/client/package.json b/packages/client/package.json index 035c00623d3..350509ca486 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -83,6 +83,7 @@ "@radix-ui/react-tooltip": "^1.0.7", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-alert-dialog": "1.0.5", "@sentry/browser": "^5.8.0", "@stripe/react-stripe-js": "^1.16.5", "@stripe/stripe-js": "^1.47.0", diff --git a/packages/client/ui/AlertDialog/AlertDialog.tsx b/packages/client/ui/AlertDialog/AlertDialog.tsx new file mode 100644 index 00000000000..8b4fdf6a396 --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialog.tsx @@ -0,0 +1,5 @@ +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' + +const AlertDialog = AlertDialogPrimitive.Root + +export {AlertDialog} diff --git a/packages/client/ui/AlertDialog/AlertDialogAction.tsx b/packages/client/ui/AlertDialog/AlertDialogAction.tsx new file mode 100644 index 00000000000..75b93fb02a9 --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogAction.tsx @@ -0,0 +1,18 @@ +import * as React from 'react' +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' +import clsx from 'clsx' + +const AlertDialogAction = React.forwardRef< + HTMLButtonElement, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)) +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName diff --git a/packages/client/ui/AlertDialog/AlertDialogCancel.tsx b/packages/client/ui/AlertDialog/AlertDialogCancel.tsx new file mode 100644 index 00000000000..201ca648679 --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogCancel.tsx @@ -0,0 +1,18 @@ +import * as React from 'react' +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' +import clsx from 'clsx' + +const AlertDialogCancel = React.forwardRef< + HTMLButtonElement, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)) +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName diff --git a/packages/client/ui/AlertDialog/AlertDialogContent.tsx b/packages/client/ui/AlertDialog/AlertDialogContent.tsx new file mode 100644 index 00000000000..dbcd0de0582 --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogContent.tsx @@ -0,0 +1,23 @@ +import * as React from 'react' +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' +import clsx from 'clsx' +import {AlertDialogOverlay} from './AlertDialogOverlay' +import {AlertDialogPortal} from './AlertDialog' + +const AlertDialogContent = React.forwardRef< + HTMLDivElement, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + + + + +)) +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName diff --git a/packages/client/ui/AlertDialog/AlertDialogDescription.tsx b/packages/client/ui/AlertDialog/AlertDialogDescription.tsx new file mode 100644 index 00000000000..7c940b02fec --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogDescription.tsx @@ -0,0 +1,15 @@ +import * as React from 'react' +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' +import clsx from 'clsx' + +const AlertDialogDescription = React.forwardRef< + HTMLParagraphElement, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)) +AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName diff --git a/packages/client/ui/AlertDialog/AlertDialogFooter.tsx b/packages/client/ui/AlertDialog/AlertDialogFooter.tsx new file mode 100644 index 00000000000..0148d9a8c39 --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogFooter.tsx @@ -0,0 +1,10 @@ +import * as React from 'react' +import clsx from 'clsx' + +const AlertDialogFooter = ({className, ...props}: React.HTMLAttributes) => ( +
+) +AlertDialogFooter.displayName = 'AlertDialogFooter' diff --git a/packages/client/ui/AlertDialog/AlertDialogHeader.tsx b/packages/client/ui/AlertDialog/AlertDialogHeader.tsx new file mode 100644 index 00000000000..869b09ccfc3 --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogHeader.tsx @@ -0,0 +1,7 @@ +import * as React from 'react' +import clsx from 'clsx' + +const AlertDialogHeader = ({className, ...props}: React.HTMLAttributes) => ( +
+) +AlertDialogHeader.displayName = 'AlertDialogHeader' diff --git a/packages/client/ui/AlertDialog/AlertDialogOverlay.tsx b/packages/client/ui/AlertDialog/AlertDialogOverlay.tsx new file mode 100644 index 00000000000..e867c7ed363 --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogOverlay.tsx @@ -0,0 +1,18 @@ +import * as React from 'react' +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' +import clsx from 'clsx' + +export const AlertDialogOverlay = React.forwardRef< + HTMLDivElement, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)) +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName diff --git a/packages/client/ui/AlertDialog/AlertDialogPortal.tsx b/packages/client/ui/AlertDialog/AlertDialogPortal.tsx new file mode 100644 index 00000000000..c4e8d56916f --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogPortal.tsx @@ -0,0 +1,3 @@ +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' + +const AlertDialogPortal = AlertDialogPrimitive.Portal diff --git a/packages/client/ui/AlertDialog/AlertDialogTitle.tsx b/packages/client/ui/AlertDialog/AlertDialogTitle.tsx new file mode 100644 index 00000000000..c7c14e011c5 --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogTitle.tsx @@ -0,0 +1,15 @@ +import * as React from 'react' +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' +import clsx from 'clsx' + +const AlertDialogTitle = React.forwardRef< + HTMLHeadingElement, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)) +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName diff --git a/packages/client/ui/AlertDialog/AlertDialogTrigger.tsx b/packages/client/ui/AlertDialog/AlertDialogTrigger.tsx new file mode 100644 index 00000000000..0a20feddfc1 --- /dev/null +++ b/packages/client/ui/AlertDialog/AlertDialogTrigger.tsx @@ -0,0 +1,3 @@ +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' + +const AlertDialogTrigger = AlertDialogPrimitive.Trigger diff --git a/yarn.lock b/yarn.lock index 610fb961913..7281b832415 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5677,6 +5677,27 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-alert-dialog@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.5.tgz#70dd529cbf1e4bff386814d3776901fcaa131b8c" + integrity sha512-OrVIOcZL0tl6xibeuGt5/+UxoT2N27KCFOPjFyfXMnchxSHZ/OW7cCX2nGlIYJrbHK/fczPcFzAwvNBB6XBNMA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dialog" "1.0.5" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + +"@radix-ui/react-arrow@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.2.tgz#93b0ff95f65e2264a05b14ef1031ec798243dd6f" + integrity sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.2" + "@radix-ui/react-arrow@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz#c24f7968996ed934d57fe6cde5d6ec7266e1d25d" @@ -5746,6 +5767,27 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-dialog@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300" + integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + "@radix-ui/react-dialog@^1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.4.tgz#06bce6c16bb93eb36d7a8589e665a20f4c1c52c1" @@ -5836,6 +5878,16 @@ "@radix-ui/react-primitive" "1.0.3" "@radix-ui/react-use-callback-ref" "1.0.1" +"@radix-ui/react-focus-scope@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525" + integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-id@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.0.tgz#8d43224910741870a45a8c9d092f25887bb6d11e" From 7496901d11f1d7cb92d37785fd9d0f4dd704393f Mon Sep 17 00:00:00 2001 From: Marcus Wermuth Date: Wed, 17 Jan 2024 11:16:57 +0100 Subject: [PATCH 07/15] Added Delete Team Dialog --- .../client/components/DeleteTeamDialog.tsx | 77 +++++++++++++++++++ .../components/DeleteTeamDialogRoot.tsx | 30 ++++++++ .../OrgTeamMembers/OrgTeamMembers.tsx | 22 +++++- .../OrgTeamMembers/OrgTeamMembersMenu.tsx | 12 ++- .../OrgTeamMembers/OrgTeamMembersRow.tsx | 2 - 5 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 packages/client/components/DeleteTeamDialog.tsx create mode 100644 packages/client/components/DeleteTeamDialogRoot.tsx diff --git a/packages/client/components/DeleteTeamDialog.tsx b/packages/client/components/DeleteTeamDialog.tsx new file mode 100644 index 00000000000..48636ab54d4 --- /dev/null +++ b/packages/client/components/DeleteTeamDialog.tsx @@ -0,0 +1,77 @@ +import React, {useState} from 'react' +import FlatPrimaryButton from './FlatPrimaryButton' +import {Input} from '../ui/Input/Input' +import {Dialog} from '../ui/Dialog/Dialog' +import {DialogContent} from '../ui/Dialog/DialogContent' +import {DialogTitle} from '../ui/Dialog/DialogTitle' +import {DialogActions} from '../ui/Dialog/DialogActions' +import useMutationProps from '../hooks/useMutationProps' +import SecondaryButton from './SecondaryButton' +import ArchiveTeamMutation from '../mutations/ArchiveTeamMutation' +import useAtmosphere from '../hooks/useAtmosphere' +import useRouter from '../hooks/useRouter' + +interface Props { + isOpen: boolean + onClose: () => void + onDeleteTeam: (teamId: string) => void + teamId: string + teamName: string + teamOrgId: string +} + +const DeleteTeamDialog = (props: Props) => { + const atmosphere = useAtmosphere() + const {history} = useRouter() + const {isOpen, onClose, teamId, teamName, teamOrgId, onDeleteTeam} = props + + const {submitting, onCompleted, onError, error, submitMutation} = useMutationProps() + + const [typedTeamName, setTypedTeamName] = useState(false) + + const handleDeleteTeam = () => { + if (submitting) return + submitMutation() + ArchiveTeamMutation(atmosphere, {teamId}, {history, onError, onCompleted}) + onDeleteTeam(teamId) + history.push(`/me/organizations/${teamOrgId}/teams`) + } + + const labelStyles = `text-left text-sm font-semibold mb-3 text-slate-600` + const fieldsetStyles = `mx-0 mb-6 flex flex-col w-full p-0` + + return ( + + + Delete Team + +
+ + { + e.preventDefault() + if (e.target.value === teamName) setTypedTeamName(true) + else setTypedTeamName(false) + }} + placeholder={teamName} + /> + {error && ( +
{error.message}
+ )} +
+ + + + I understand the consequences, delete this team + + Cancel + +
+
+ ) +} + +export default DeleteTeamDialog diff --git a/packages/client/components/DeleteTeamDialogRoot.tsx b/packages/client/components/DeleteTeamDialogRoot.tsx new file mode 100644 index 00000000000..fda6d5f4e54 --- /dev/null +++ b/packages/client/components/DeleteTeamDialogRoot.tsx @@ -0,0 +1,30 @@ +import React, {Suspense} from 'react' +import DeleteTeamDialog from './DeleteTeamDialog' +import {Loader} from '../utils/relay/renderLoader' + +interface Props { + onClose: () => void + onDeleteTeam: (teamId: string) => void + teamId: string + teamName: string + teamOrgId: string +} + +const DeleteTeamDialogRoot = (props: Props) => { + const {onClose, onDeleteTeam, teamId, teamName, teamOrgId} = props + + return ( + }> + + + ) +} + +export default DeleteTeamDialogRoot diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx index e8283639376..8fd6b3ca16f 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx @@ -12,6 +12,8 @@ import {ORGANIZATIONS} from '../../../../utils/constants' import {MenuPosition} from '../../../../hooks/useCoords' import useMenu from '../../../../hooks/useMenu' import {OrgTeamMembersMenu} from './OrgTeamMembersMenu' +import {useDialogState} from '../../../../ui/Dialog/useDialogState' +import DeleteTeamDialogRoot from '../../../../components/DeleteTeamDialogRoot' interface Props { queryRef: PreloadedQuery @@ -47,6 +49,12 @@ export const OrgTeamMembers = (props: Props) => { const {togglePortal: toggleModal, closePortal: closeModal, modalPortal} = useModal() const {togglePortal, originRef, menuPortal, menuProps} = useMenu(MenuPosition.UPPER_RIGHT) + const { + open: openDeleteTeamDialog, + close: closeDeleteTeamDialog, + isOpen: isDeleteTeamDialogOpened + } = useDialogState() + if (!team) return null const {teamMembers} = team @@ -92,7 +100,19 @@ export const OrgTeamMembers = (props: Props) => { )} - {menuPortal()} + {menuPortal( + + )} + + {isDeleteTeamDialogOpened ? ( + + ) : null}
) } diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersMenu.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersMenu.tsx index 8c743ccc68e..bc53031bfc8 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersMenu.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersMenu.tsx @@ -5,14 +5,22 @@ import MenuItem from '../../../../components/MenuItem' interface OrgTeamMembersMenuProps { menuProps: MenuProps + openDeleteTeamModal: () => void } export const OrgTeamMembersMenu = (props: OrgTeamMembersMenuProps) => { - const {menuProps} = props + const {menuProps, openDeleteTeamModal} = props + const {closePortal} = menuProps return ( - + { + closePortal() + openDeleteTeamModal() + }} + /> ) } diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx index 51594754b47..3e132c89bdb 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx @@ -7,8 +7,6 @@ import {AvatarFallback} from '../../../../ui/Avatar/AvatarFallback' import {AvatarImage} from '../../../../ui/Avatar/AvatarImage' import {Button} from '../../../../ui/Button/Button' import {MoreVert} from '@mui/icons-material' -import {MenuPosition} from '../../../../hooks/useCoords' -import useMenu from '../../../../hooks/useMenu' type Props = { teamMemberRef: OrgTeamMembersRow_teamMember$key From 6d2bac8438634443c746e6ac7c38a02dd88fe52f Mon Sep 17 00:00:00 2001 From: Marcus Wermuth Date: Wed, 17 Jan 2024 11:21:35 +0100 Subject: [PATCH 08/15] Updated Delete Dialog label --- packages/client/components/DeleteTeamDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/components/DeleteTeamDialog.tsx b/packages/client/components/DeleteTeamDialog.tsx index 48636ab54d4..0f721134c5a 100644 --- a/packages/client/components/DeleteTeamDialog.tsx +++ b/packages/client/components/DeleteTeamDialog.tsx @@ -47,7 +47,7 @@ const DeleteTeamDialog = (props: Props) => {
Date: Thu, 8 Feb 2024 09:11:15 +0100 Subject: [PATCH 09/15] Fixed Refresh after archiving team --- .../OrgTeamMembers/OrgTeamMemberMenu.tsx | 71 ++++++++++++++++++ .../OrgTeamMembers/OrgTeamMembers.tsx | 10 ++- .../OrgTeamMembers/OrgTeamMembersRow.tsx | 73 ++++++++++++++++--- .../client/mutations/ArchiveTeamMutation.ts | 8 ++ 4 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMemberMenu.tsx diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMemberMenu.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMemberMenu.tsx new file mode 100644 index 00000000000..7526eb55775 --- /dev/null +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMemberMenu.tsx @@ -0,0 +1,71 @@ +import styled from '@emotion/styled' +import React from 'react' +import graphql from 'babel-plugin-relay/macro' +import useAtmosphere from '~/hooks/useAtmosphere' +import {useFragment} from 'react-relay' +import {MenuProps} from '../../../../hooks/useMenu' +import Menu from '../../../../components/Menu' +import MenuItem from '../../../../components/MenuItem' +import MenuItemLabel from '../../../../components/MenuItemLabel' +import {OrgTeamMemberMenu_teamMember$key} from '../../../../__generated__/OrgTeamMemberMenu_teamMember.graphql' + +interface OrgTeamMemberMenuProps { + isLead: boolean + menuProps: MenuProps + isViewerLead: boolean + isViewerOrgAdmin: boolean + manageTeamMemberId?: string | null + teamMember: OrgTeamMemberMenu_teamMember$key + handleNavigate?: () => void + togglePromote: () => void + toggleRemove: () => void +} + +const StyledLabel = styled(MenuItemLabel)({ + padding: '4px 16px' +}) + +export const OrgTeamMemberMenu = (props: OrgTeamMemberMenuProps) => { + const { + isViewerLead, + isViewerOrgAdmin, + teamMember: teamMemberRef, + menuProps, + togglePromote, + toggleRemove + } = props + const teamMember = useFragment( + graphql` + fragment OrgTeamMemberMenu_teamMember on TeamMember { + isSelf + preferredName + userId + isLead + } + `, + teamMemberRef + ) + const atmosphere = useAtmosphere() + const {preferredName, userId} = teamMember + const {viewerId} = atmosphere + const isSelf = userId === viewerId + const isViewerTeamAdmin = isViewerLead || isViewerOrgAdmin + + return ( + + {isViewerTeamAdmin && (!isSelf || !isViewerLead) && ( + Promote {preferredName} to Team Lead} + key='promote' + onClick={togglePromote} + /> + )} + {isViewerTeamAdmin && !isSelf && ( + Remove {preferredName} from Team} + onClick={toggleRemove} + /> + )} + + ) +} diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx index 8fd6b3ca16f..3fa502bf22a 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx @@ -25,6 +25,7 @@ const query = graphql` team(teamId: $teamId) { ...ArchiveTeam_team isLead + isOrgAdmin id name tier @@ -56,7 +57,7 @@ export const OrgTeamMembers = (props: Props) => { } = useDialogState() if (!team) return null - const {teamMembers} = team + const {isLead: isViewerLead, isOrgAdmin: isViewerOrgAdmin, teamMembers} = team return (
@@ -92,7 +93,12 @@ export const OrgTeamMembers = (props: Props) => {
{teamMembers.map((teamMember) => ( - + ))}
diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx index 3e132c89bdb..5bcc9ea48b7 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx @@ -7,17 +7,28 @@ import {AvatarFallback} from '../../../../ui/Avatar/AvatarFallback' import {AvatarImage} from '../../../../ui/Avatar/AvatarImage' import {Button} from '../../../../ui/Button/Button' import {MoreVert} from '@mui/icons-material' +import {OrgTeamMemberMenu} from './OrgTeamMemberMenu' +import {MenuPosition} from '../../../../hooks/useCoords' +import useMenu from '../../../../hooks/useMenu' +import PromoteTeamMemberModal from '../../../teamDashboard/components/PromoteTeamMemberModal/PromoteTeamMemberModal' +import RemoveTeamMemberModal from '../../../teamDashboard/components/RemoveTeamMemberModal/RemoveTeamMemberModal' +import useModal from '../../../../hooks/useModal' +import useAtmosphere from '../../../../hooks/useAtmosphere' type Props = { teamMemberRef: OrgTeamMembersRow_teamMember$key + isViewerLead: boolean + isViewerOrgAdmin: boolean } export const OrgTeamMembersRow = (props: Props) => { const {teamMemberRef} = props - const member = useFragment( + const teamMember = useFragment( graphql` fragment OrgTeamMembersRow_teamMember on TeamMember { + ...OrgTeamMemberMenu_teamMember id + userId picture preferredName isLead @@ -29,25 +40,49 @@ export const OrgTeamMembersRow = (props: Props) => { name } } + ...PromoteTeamMemberModal_teamMember + ...RemoveTeamMemberModal_teamMember } `, teamMemberRef ) - // const {togglePortal, originRef, menuPortal, menuProps} = useMenu(MenuPosition.UPPER_RIGHT) + const {isViewerLead, isViewerOrgAdmin} = props + const {id: isLead, isOrgAdmin, userId} = teamMember + + const atmosphere = useAtmosphere() + const {viewerId} = atmosphere + const isSelf = userId === viewerId + + const showMenuButton = + (isViewerOrgAdmin && !isLead) || + (isViewerLead && !isSelf && !isOrgAdmin) || + (!isViewerLead && isSelf) + + const {togglePortal, originRef, menuPortal, menuProps} = useMenu(MenuPosition.UPPER_RIGHT) + const { + closePortal: closePromote, + togglePortal: togglePromote, + modalPortal: portalPromote + } = useModal() + const { + closePortal: closeRemove, + togglePortal: toggleRemove, + modalPortal: portalRemove + } = useModal() return (
- - CN + + {teamMember.preferredName.substring(0, 2)}
- {member.preferredName}{' '} - {member.isLead ? ( + {teamMember.preferredName}{' '} + {teamMember.isLead ? ( Team Lead @@ -55,21 +90,41 @@ export const OrgTeamMembersRow = (props: Props) => {
Teams:
- {member.user.teams.map((team) => team.name).join(', ')} + {teamMember.user.teams.map((team) => team.name).join(', ')}
- + {menuPortal( + + )}
+ + {portalPromote()} + {portalRemove()}
) } diff --git a/packages/client/mutations/ArchiveTeamMutation.ts b/packages/client/mutations/ArchiveTeamMutation.ts index 15afd828d4b..218fdd0c7c1 100644 --- a/packages/client/mutations/ArchiveTeamMutation.ts +++ b/packages/client/mutations/ArchiveTeamMutation.ts @@ -30,6 +30,14 @@ graphql` activeMeetings { id } + organization { + allTeams { + id + } + viewerTeams { + id + } + } } teamTemplateIds } From 1e45eb4c53197aa9b5407dfb59e7e65a1b9b7c61 Mon Sep 17 00:00:00 2001 From: Jordan Husney Date: Mon, 4 Mar 2024 17:04:07 -0800 Subject: [PATCH 10/15] feat: As a SuperAdmin, I can remove team members Also: feat: As a SuperAdmin, I can promote others to SuperAdmin feat: As a SuperAdmin, I can demote others to other roles chore: yarn changes chore: update .vscode/launch.json from dep. pwa-chome to chrome --- .vscode/launch.json | 4 +- .../client/components/OrgAdminActionMenu.tsx | 95 +++++++++++++++++++ .../components/OrgMembers/OrgMembers.tsx | 5 + .../OrgTeamMembers/OrgTeamMembers.tsx | 10 +- .../OrgTeamMembers/OrgTeamMembersRow.tsx | 14 +-- .../components/OrgUserRow/OrgMemberRow.tsx | 80 ++++++++-------- packages/server/graphql/types/Organization.ts | 17 +++- packages/server/utils/authorization.ts | 25 ++++- yarn.lock | 9 +- 9 files changed, 186 insertions(+), 73 deletions(-) create mode 100644 packages/client/components/OrgAdminActionMenu.tsx diff --git a/.vscode/launch.json b/.vscode/launch.json index 2d3b6382f4e..a7fe78cf299 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -30,7 +30,7 @@ { "name": "Launch Chrome", "request": "launch", - "type": "pwa-chrome", + "type": "chrome", "url": "http://localhost:3000", "webRoot": "${workspaceFolder}" }, @@ -38,7 +38,7 @@ "type": "node", "request": "launch", "name": "Debug Executor", - "program": "scripts/runExecutor.js", + "program": "scripts/runExecutor.js" }, { "type": "node", diff --git a/packages/client/components/OrgAdminActionMenu.tsx b/packages/client/components/OrgAdminActionMenu.tsx new file mode 100644 index 00000000000..ef059c50006 --- /dev/null +++ b/packages/client/components/OrgAdminActionMenu.tsx @@ -0,0 +1,95 @@ +import graphql from 'babel-plugin-relay/macro' +import React from 'react' +import {useFragment} from 'react-relay' +import useAtmosphere from '~/hooks/useAtmosphere' +import {MenuProps} from '../hooks/useMenu' +import SetOrgUserRoleMutation from '../mutations/SetOrgUserRoleMutation' +import withMutationProps, {WithMutationProps} from '../utils/relay/withMutationProps' +import {OrgAdminActionMenu_organization$key} from '../__generated__/OrgAdminActionMenu_organization.graphql' +import {OrgAdminActionMenu_organizationUser$key} from '../__generated__/OrgAdminActionMenu_organizationUser.graphql' +import Menu from './Menu' +import MenuItem from './MenuItem' + +interface Props extends WithMutationProps { + menuProps: MenuProps + isViewerLastOrgAdmin: boolean + organizationUser: OrgAdminActionMenu_organizationUser$key + organization: OrgAdminActionMenu_organization$key + toggleLeave: () => void + toggleRemove: () => void +} + +const OrgAdminActionMenu = (props: Props) => { + const { + menuProps, + isViewerLastOrgAdmin, + organizationUser: organizationUserRef, + submitting, + submitMutation, + onError, + onCompleted, + organization: organizationRef, + toggleLeave, + toggleRemove + } = props + const organization = useFragment( + graphql` + fragment OrgAdminActionMenu_organization on Organization { + id + } + `, + organizationRef + ) + const organizationUser = useFragment( + graphql` + fragment OrgAdminActionMenu_organizationUser on OrganizationUser { + role + user { + id + } + } + `, + organizationUserRef + ) + const atmosphere = useAtmosphere() + const {id: orgId} = organization + const {viewerId} = atmosphere + const {role, user} = organizationUser + const {id: userId} = user + + const setRole = + (role: 'ORG_ADMIN' | 'BILLING_LEADER' | null = null) => + () => { + if (submitting) return + submitMutation() + const variables = {orgId, userId, role} + SetOrgUserRoleMutation(atmosphere, variables, {onError, onCompleted}) + } + + const isOrgAdmin = role === 'ORG_ADMIN' + const isBillingLeader = role === 'BILLING_LEADER' + const roleName = role === 'ORG_ADMIN' ? 'Org Admin' : 'Billing Leader' + const notSelf = viewerId !== userId + const canRemoveSelf = viewerId === userId && !isViewerLastOrgAdmin + + return ( + <> + + {!isOrgAdmin && } + {!isOrgAdmin && !isBillingLeader && ( + + )} + {isOrgAdmin && ( + + )} + {((role && notSelf) || canRemoveSelf) && ( + + )} + {canRemoveSelf && } + {notSelf && } + + + ) +} + +export default withMutationProps(OrgAdminActionMenu) diff --git a/packages/client/modules/userDashboard/components/OrgMembers/OrgMembers.tsx b/packages/client/modules/userDashboard/components/OrgMembers/OrgMembers.tsx index a4d365a8e91..e56be6deb45 100644 --- a/packages/client/modules/userDashboard/components/OrgMembers/OrgMembers.tsx +++ b/packages/client/modules/userDashboard/components/OrgMembers/OrgMembers.tsx @@ -75,6 +75,10 @@ const OrgMembers = (props: Props) => { ['BILLING_LEADER', 'ORG_ADMIN'].includes(node.role ?? '') ? count + 1 : count, 0 ) + const orgAdminCount = organizationUsers.edges.reduce( + (count, {node}) => (['ORG_ADMIN'].includes(node.role ?? '') ? count + 1 : count), + 0 + ) const exportToCSV = async () => { const rows = organizationUsers.edges.map((orgUser, idx) => { @@ -117,6 +121,7 @@ const OrgMembers = (props: Props) => { diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx index 3fa502bf22a..515ec13eaaf 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembers.tsx @@ -24,12 +24,11 @@ const query = graphql` viewer { team(teamId: $teamId) { ...ArchiveTeam_team - isLead - isOrgAdmin id - name - tier billingTier + isOrgAdmin + isViewerLead + name orgId teamMembers(sortBy: "preferredName") { id @@ -37,6 +36,7 @@ const query = graphql` ...AddTeamMemberModal_teamMembers ...OrgTeamMembersRow_teamMember } + tier } } } @@ -57,7 +57,7 @@ export const OrgTeamMembers = (props: Props) => { } = useDialogState() if (!team) return null - const {isLead: isViewerLead, isOrgAdmin: isViewerOrgAdmin, teamMembers} = team + const {isViewerLead, isOrgAdmin: isViewerOrgAdmin, teamMembers} = team return (
diff --git a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx index 5bcc9ea48b7..6c35efa6023 100644 --- a/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgTeamMembers/OrgTeamMembersRow.tsx @@ -27,7 +27,6 @@ export const OrgTeamMembersRow = (props: Props) => { graphql` fragment OrgTeamMembersRow_teamMember on TeamMember { ...OrgTeamMemberMenu_teamMember - id userId picture preferredName @@ -35,11 +34,6 @@ export const OrgTeamMembersRow = (props: Props) => { isOrgAdmin isSelf email - user { - teams { - name - } - } ...PromoteTeamMemberModal_teamMember ...RemoveTeamMemberModal_teamMember } @@ -48,7 +42,7 @@ export const OrgTeamMembersRow = (props: Props) => { ) const {isViewerLead, isViewerOrgAdmin} = props - const {id: isLead, isOrgAdmin, userId} = teamMember + const {isLead, isOrgAdmin, userId} = teamMember const atmosphere = useAtmosphere() const {viewerId} = atmosphere @@ -93,12 +87,6 @@ export const OrgTeamMembersRow = (props: Props) => { {teamMember.email}
-
-
Teams:
-
- {teamMember.user.teams.map((team) => team.name).join(', ')} -
-

{team.name}

- -
- - -
@@ -102,10 +85,6 @@ export const OrgTeamMembers = (props: Props) => { ))}
- {modalPortal( - - )} - {menuPortal( )} From c14c0eceab0220b706226019332694878fe1d19a Mon Sep 17 00:00:00 2001 From: Jordan Husney Date: Thu, 7 Mar 2024 15:08:30 -0800 Subject: [PATCH 15/15] chore: code review fixups --- .../client/components/DeleteTeamDialog.tsx | 7 ++--- .../components/DeleteTeamDialogRoot.tsx | 30 ------------------- .../client/components/OrgAdminActionMenu.tsx | 11 +++---- .../OrgTeamMembers/OrgTeamMembers.tsx | 7 +++-- .../OrgTeamMembers/OrgTeamMembersRow.tsx | 25 ++++++++-------- .../components/OrgTeams/OrgTeams.tsx | 7 +++-- .../components/OrgUserRow/OrgMemberRow.tsx | 2 +- 7 files changed, 28 insertions(+), 61 deletions(-) delete mode 100644 packages/client/components/DeleteTeamDialogRoot.tsx diff --git a/packages/client/components/DeleteTeamDialog.tsx b/packages/client/components/DeleteTeamDialog.tsx index 0f721134c5a..d6bb993bbde 100644 --- a/packages/client/components/DeleteTeamDialog.tsx +++ b/packages/client/components/DeleteTeamDialog.tsx @@ -37,16 +37,13 @@ const DeleteTeamDialog = (props: Props) => { history.push(`/me/organizations/${teamOrgId}/teams`) } - const labelStyles = `text-left text-sm font-semibold mb-3 text-slate-600` - const fieldsetStyles = `mx-0 mb-6 flex flex-col w-full p-0` - return ( Delete Team -
-
-
+
{teamMembers.length} Active
@@ -90,7 +90,8 @@ export const OrgTeamMembers = (props: Props) => { )} {isDeleteTeamDialogOpened ? ( - { const {viewerId} = atmosphere const isSelf = userId === viewerId - const showMenuButton = - (isViewerOrgAdmin && !isLead) || - (isViewerLead && !isSelf && !isOrgAdmin) || - (!isViewerLead && isSelf) + const showMenuButton = (isViewerOrgAdmin && !isLead) || (isViewerLead && !isSelf && !isOrgAdmin) const {togglePortal, originRef, menuPortal, menuProps} = useMenu(MenuPosition.UPPER_RIGHT) const { @@ -89,15 +86,17 @@ export const OrgTeamMembersRow = (props: Props) => {
- + {showMenuButton && ( + + )} {menuPortal( {
-
+
-
{allTeams.length} Teams
+
+ {allTeams.length} {plural(allTeams.length, 'Team')} +
{allTeams.map((team) => ( diff --git a/packages/client/modules/userDashboard/components/OrgUserRow/OrgMemberRow.tsx b/packages/client/modules/userDashboard/components/OrgUserRow/OrgMemberRow.tsx index d27e6966a50..8a15e046096 100644 --- a/packages/client/modules/userDashboard/components/OrgUserRow/OrgMemberRow.tsx +++ b/packages/client/modules/userDashboard/components/OrgUserRow/OrgMemberRow.tsx @@ -115,7 +115,7 @@ const UserAvatar: React.FC = ({picture}) => ( {picture ? ( ) : ( - + default avatar )} )