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 3f72af54be6..2adb6aa411b 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. @@ -119,11 +123,11 @@ export const UserMenu = React.memo(() => { if (isProxyUser && !getStorage('proxy_user')) { setStorage('proxy_user', 'true'); - enqueueSnackbar(`Account switched to ${companyName}.`, { + enqueueSnackbar(`Account switched to ${companyNameOrEmail}.`, { variant: 'success', }); } - }, [isProxyUser, companyName, enqueueSnackbar]); + }, [isProxyUser, companyNameOrEmail, enqueueSnackbar]); const accountLinks: MenuLink[] = React.useMemo( () => [ @@ -225,19 +229,19 @@ export const UserMenu = React.memo(() => { {userName} - {showCompanyName && ( + {companyNameOrEmail && ( ({ fontFamily: theme.font.bold, fontSize: '0.875rem', })} > - {companyName} + {companyNameOrEmail} )} @@ -275,7 +279,9 @@ export const UserMenu = React.memo(() => { fontSize="1.1rem" > - {canSwitchBetweenParentOrProxyAccount ? companyName : userName} + {canSwitchBetweenParentOrProxyAccount && companyNameOrEmail + ? companyNameOrEmail + : userName} {canSwitchBetweenParentOrProxyAccount && ( @@ -291,23 +297,11 @@ export const UserMenu = React.memo(() => { My Profile - - + + {profileLinks.slice(0, 4).map(renderLink)} - + {profileLinks.slice(4).map(renderLink)}