From 20c086923880739be92caced9f0f8b0b62cde416 Mon Sep 17 00:00:00 2001 From: Mariah Jacobs <114685994+mjac0bs@users.noreply.github.com> Date: Mon, 11 Mar 2024 09:15:13 -0600 Subject: [PATCH] fix: [M3-7269] - Display parent email in user menu when no company name is available for restricted parent user (#10248) * Display username if no company name; update tests * Wrap links for all long usernames * Commit forgotten changesets * Use email instead of username * Remove change to company field in apiv4; cannot be null * Update unit test to use email rather than username * Update changeset * Improve styling for very long usernames * Revert more changes from when we though company could be null --- ...r-10248-upcoming-features-1709325591286.md | 5 ++ .../TopMenu/UserMenu/UserMenu.test.tsx | 44 +++++++++++++++++ .../features/TopMenu/UserMenu/UserMenu.tsx | 48 ++++++++----------- 3 files changed, 70 insertions(+), 27 deletions(-) create mode 100644 packages/manager/.changeset/pr-10248-upcoming-features-1709325591286.md diff --git a/packages/manager/.changeset/pr-10248-upcoming-features-1709325591286.md b/packages/manager/.changeset/pr-10248-upcoming-features-1709325591286.md new file mode 100644 index 00000000000..a235d89664f --- /dev/null +++ b/packages/manager/.changeset/pr-10248-upcoming-features-1709325591286.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Display parent email in user menu for restricted parent users without access to company name ([#10248](https://github.com/linode/manager/pull/10248)) diff --git a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.test.tsx b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.test.tsx index a4424eabad5..9254b677082 100644 --- a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.test.tsx +++ b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.test.tsx @@ -197,4 +197,48 @@ describe('UserMenu', () => { expect(within(userMenuPopover).getByText('Child Company')).toBeVisible(); expect(within(userMenuPopover).getByText('Switch Account')).toBeVisible(); }); + + it('shows the parent email for a parent user if their company name is not set', async () => { + // Mock a forbidden request to the /account endpoint, which happens if Billing (Account) Access is None. + server.use( + rest.get('*/account/users/*/grants', (req, res, ctx) => { + return res( + ctx.json( + grantsFactory.build({ + global: { + account_access: null, + }, + }) + ) + ); + }), + rest.get('*/account', (req, res, ctx) => { + return res(ctx.status(403)); + }), + rest.get('*/profile', (req, res, ctx) => { + return res( + ctx.json( + profileFactory.build({ + email: 'parent@parent.com', + user_type: 'parent', + username: 'parent-username', + }) + ) + ); + }) + ); + + const { findByLabelText, findByTestId } = renderWithTheme(, { + flags: { parentChildAccountAccess: true }, + }); + + const userMenuButton = await findByLabelText('Profile & Account'); + fireEvent.click(userMenuButton); + + const userMenuPopover = await findByTestId('user-menu-popover'); + + expect( + within(userMenuPopover).getByText('parent@parent.com') + ).toBeVisible(); + }); }); diff --git a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx index 68280bf0d39..d900920e35b 100644 --- a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx +++ b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx @@ -80,12 +80,16 @@ export const UserMenu = React.memo(() => { ((!isChildAccountAccessRestricted && isParentUser) || isProxyUser); const open = Boolean(anchorEl); const id = open ? 'user-menu-popover' : undefined; - const companyName = - (hasParentChildAccountAccess && - profile?.user_type !== 'default' && - account?.company) ?? - ''; - const showCompanyName = hasParentChildAccountAccess && companyName; + + // If there is no company name to identify an account, fall back on the email. + // Covers an edge case in which a restricted parent user without `account_access` cannot access the account company. + const companyNameOrEmail = + hasParentChildAccountAccess && + profile?.user_type !== 'default' && + account?.company + ? account.company + : profile?.email; + const { isParentTokenExpired } = useParentTokenManagement({ isProxyUser }); // Used for fetching parent profile and account data by making a request with the parent's token. @@ -117,11 +121,11 @@ export const UserMenu = React.memo(() => { React.useEffect(() => { // Run after we've switched to a proxy user. if (isProxyUser) { - enqueueSnackbar(`Account switched to ${companyName}.`, { + enqueueSnackbar(`Account switched to ${companyNameOrEmail}.`, { variant: 'success', }); } - }, [isProxyUser, companyName, enqueueSnackbar]); + }, [isProxyUser, companyNameOrEmail, enqueueSnackbar]); const accountLinks: MenuLink[] = React.useMemo( () => [ @@ -223,19 +227,19 @@ export const UserMenu = React.memo(() => { {userName} - {showCompanyName && ( + {companyNameOrEmail && ( ({ fontFamily: theme.font.bold, fontSize: '0.875rem', })} > - {companyName} + {companyNameOrEmail} )} @@ -273,7 +277,9 @@ export const UserMenu = React.memo(() => { fontSize="1.1rem" > - {canSwitchBetweenParentOrProxyAccount ? companyName : userName} + {canSwitchBetweenParentOrProxyAccount && companyNameOrEmail + ? companyNameOrEmail + : userName} {canSwitchBetweenParentOrProxyAccount && ( @@ -289,23 +295,11 @@ export const UserMenu = React.memo(() => { My Profile - - + + {profileLinks.slice(0, 4).map(renderLink)} - + {profileLinks.slice(4).map(renderLink)}