• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alkem-io / client-web / #10019

24 Jan 2025 08:44AM UTC coverage: 5.69%. First build
#10019

Pull #7423

travis-ci

Pull Request #7423: Role setsv2

188 of 11014 branches covered (1.71%)

Branch coverage included in aggregate %.

346 of 1595 new or added lines in 92 files covered. (21.69%)

1517 of 18952 relevant lines covered (8.0%)

0.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/ui/platformNavigation/PlatformNavigationUserMenu.tsx
1
import {
2
  AssignmentIndOutlined,
3
  DashboardOutlined,
4
  ExitToAppOutlined,
5
  HdrStrongOutlined,
6
  LanguageOutlined,
7
  MeetingRoomOutlined,
8
} from '@mui/icons-material';
9
import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
10
import LocalOfferOutlinedIcon from '@mui/icons-material/LocalOfferOutlined';
11
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
12
import { Box, Divider, Menu, MenuItem, MenuList, Typography } from '@mui/material';
13
import FocusTrap from '@mui/material/Unstable_TrapFocus';
14
import { type PropsWithChildren, type ReactNode, Suspense, useState } from 'react';
15
import { useTranslation } from 'react-i18next';
16
import { useLocation } from 'react-router-dom';
17
import { AuthorizationPrivilege, RoleName } from '@/core/apollo/generated/graphql-schema';
18
import { AUTH_LOGOUT_PATH } from '@/core/auth/authentication/constants/authentication.constants';
19
import { lazyWithGlobalErrorHandler } from '@/core/lazyLoading/lazyWithGlobalErrorHandler';
20
import Avatar from '@/core/ui/avatar/Avatar';
21
import Gutters from '@/core/ui/grid/Gutters';
22
import { gutters } from '@/core/ui/grid/utils';
23
import useLanguageSelect from '@/core/ui/language/useLanguageSelect';
24
import GlobalMenuSurface from '@/core/ui/menu/GlobalMenuSurface';
25
import NavigatableMenuItem from '@/core/ui/menu/NavigatableMenuItem';
26
import { BlockTitle, Caption } from '@/core/ui/typography';
27
import {
28
  PendingMembershipsDialogType,
29
  usePendingMembershipsDialog,
30
} from '@/domain/community/pendingMembership/PendingMembershipsDialogContext';
31
import { usePendingInvitationsCount } from '@/domain/community/pendingMembership/usePendingInvitationsCount';
32
import { useCurrentUserContext } from '@/domain/community/userCurrent/useCurrentUserContext';
33
import { ROUTE_HOME, ROUTE_USER_ME } from '@/domain/platform/routes/constants';
34
import usePlatformOrigin from '@/domain/platform/routes/usePlatformOrigin';
35
import { buildLoginUrl, buildUserAccountUrl } from '@/main/routing/urlBuilders';
36
import { PLATFORM_NAVIGATION_MENU_Z_INDEX } from './constants';
37

38
const PendingMembershipsDialog = lazyWithGlobalErrorHandler(
39
  () => import('@/domain/community/pendingMembership/PendingMembershipsDialog')
×
40
);
41
const HelpDialog = lazyWithGlobalErrorHandler(() => import('@/core/help/dialog/HelpDialog'));
×
42

43
interface PlatformNavigationUserMenuProps {
×
44
  surface: boolean;
45
  footer?: ReactNode;
×
46
  onClose?: () => void;
47
}
×
48

×
49
export const UserMenuDivider = () => <Divider sx={{ width: '85%', marginX: 'auto' }} />;
50

×
51
const PlatformNavigationUserMenu = ({
52
  ref,
53
  surface,
×
54
  onClose,
55
  footer,
×
56
  children,
57
}: PropsWithChildren<PlatformNavigationUserMenuProps> & {
58
  ref?: React.Ref<HTMLDivElement>;
×
59
}) => {
×
60
  const { t } = useTranslation();
×
61

62
  const { pathname, search } = useLocation();
×
63

NEW
64
  const platformOrigin = usePlatformOrigin();
×
65
  const homeUrl = platformOrigin && `${platformOrigin}${ROUTE_HOME}`;
NEW
66

×
67
  const [isHelpDialogOpen, setIsHelpDialogOpen] = useState(false);
NEW
68
  const { setOpenDialog } = usePendingMembershipsDialog();
×
69

NEW
70
  const { userModel, platformPrivilegeWrapper: userWrapper, isAuthenticated, platformRoles } = useCurrentUserContext();
×
71

72
  const isAdmin = userWrapper?.hasPlatformPrivilege?.(AuthorizationPrivilege.PlatformAdmin);
×
73

74
  const { count: pendingInvitationsCount } = usePendingInvitationsCount();
75

76
  const {
77
    openSelect,
×
78
    isOpen: isLanguageMenuOpen,
79
    menuProps: languageMenuProps,
×
80
    languages,
81
  } = useLanguageSelect({
82
    anchorOrigin: {
×
83
      vertical: 'bottom',
84
      horizontal: 'left',
85
    },
86
    transformOrigin: {
87
      vertical: 'top',
88
      horizontal: 'left',
89
    },
90
    zIndex: PLATFORM_NAVIGATION_MENU_Z_INDEX + 1,
91
  });
×
92

93
  // the roles should follow the order
94
  const getRole = (): string | null => {
95
    for (const platformRole of platformRoles) {
96
      switch (platformRole) {
97
        case RoleName.GlobalAdmin:
98
          return t('common.roles.GLOBAL_ADMIN');
99
        case RoleName.GlobalSupport:
100
          return t('common.roles.GLOBAL_SUPPORT');
×
101
        case RoleName.GlobalLicenseManager:
102
          return t('common.roles.GLOBAL_LICENSE_MANAGER');
103
        case RoleName.PlatformBetaTester:
104
          return t('common.roles.PLATFORM_BETA_TESTER');
105
        case RoleName.PlatformVcCampaign:
106
          return t('common.roles.PLATFORM_VC_CAMPAIGN');
107
      }
108
    }
109
    return null;
110
  };
111
  const role = getRole();
112

113
  const Wrapper = surface ? GlobalMenuSurface : Box;
114

×
115
  return (
116
    <>
117
      <Wrapper ref={ref}>
118
        {userModel && (
119
          <Gutters disableGap={true} alignItems="center" sx={{ paddingBottom: 1 }}>
×
120
            <Avatar
121
              size="large"
122
              src={userModel.profile?.avatar?.uri}
×
123
              alt={
124
                userModel.profile?.displayName
125
                  ? t('common.avatar-of', { user: userModel.profile?.displayName })
×
126
                  : t('common.avatar')
×
127
              }
128
            />
129
            <BlockTitle lineHeight={gutters(2)}>{userModel.profile?.displayName}</BlockTitle>
130
            {role && (
131
              <Caption color="neutralMedium.main" textTransform="uppercase">
132
                {role}
133
              </Caption>
134
            )}
135
          </Gutters>
136
        )}
×
137
        <FocusTrap open={true}>
138
          <MenuList autoFocus={true} disablePadding={true} sx={{ paddingY: 1, outline: 'none' }}>
139
            {!isAuthenticated && (
140
              <NavigatableMenuItem
141
                iconComponent={MeetingRoomOutlined}
142
                route={buildLoginUrl(pathname, search)}
143
                onClick={onClose}
144
              >
145
                <Typography variant="inherit" fontWeight="bold">
146
                  {t('topBar.sign-in')}
147
                </Typography>
148
              </NavigatableMenuItem>
149
            )}
150
            <NavigatableMenuItem iconComponent={DashboardOutlined} route={homeUrl} onClick={onClose}>
151
              {t('pages.home.title')}
152
            </NavigatableMenuItem>
153
            {userModel && (
×
154
              <NavigatableMenuItem iconComponent={AssignmentIndOutlined} route={ROUTE_USER_ME} onClick={onClose}>
155
                {t('pages.user-profile.title')}
×
156
              </NavigatableMenuItem>
157
            )}
158
            {userModel && (
159
              <NavigatableMenuItem
160
                iconComponent={LocalOfferOutlinedIcon}
161
                route={buildUserAccountUrl(ROUTE_USER_ME)}
162
                onClick={onClose}
163
              >
164
                {t('pages.home.mainNavigation.myAccount')}
×
165
              </NavigatableMenuItem>
×
166
            )}
167
            {userModel && (
168
              <NavigatableMenuItem
169
                iconComponent={HdrStrongOutlined}
170
                onClick={() => {
×
171
                  setOpenDialog({ type: PendingMembershipsDialogType.PendingMembershipsList });
172
                  onClose?.();
173
                }}
174
              >
175
                {t('community.pendingMembership.pendingMembershipsWithCount', { count: pendingInvitationsCount })}
176
              </NavigatableMenuItem>
177
            )}
178
            <UserMenuDivider />
179
            {children}
180
            {isAdmin && (
181
              <NavigatableMenuItem iconComponent={SettingsIcon} route="/admin" onClick={onClose}>
182
                {t('common.administration')}
×
183
              </NavigatableMenuItem>
184
            )}
185
            <NavigatableMenuItem
186
              id="language-button"
187
              iconComponent={LanguageOutlined}
188
              onClick={event => openSelect(event.currentTarget as HTMLElement)}
189
              aria-controls={isLanguageMenuOpen ? 'language-menu' : undefined}
190
              aria-haspopup="true"
191
              aria-expanded={isLanguageMenuOpen ? 'true' : undefined}
192
            >
193
              {t('buttons.changeLanguage')}
194
            </NavigatableMenuItem>
195
            <NavigatableMenuItem
196
              iconComponent={HelpOutlineIcon}
197
              onClick={() => {
198
                setIsHelpDialogOpen(true);
199
                onClose?.();
200
              }}
201
            >
202
              {t('buttons.getHelp')}
203
            </NavigatableMenuItem>
204
            {isAuthenticated && (
205
              <NavigatableMenuItem iconComponent={MeetingRoomOutlined} route={AUTH_LOGOUT_PATH} onClick={onClose}>
206
                {t('buttons.sign-out')}
207
              </NavigatableMenuItem>
208
            )}
209
            <NavigatableMenuItem tabOnly={true} iconComponent={ExitToAppOutlined} onClick={onClose}>
210
              {t('components.navigation.exitMenu')}
211
            </NavigatableMenuItem>
212
            {footer}
213
          </MenuList>
214
        </FocusTrap>
215
      </Wrapper>
216
      {userModel && (
217
        <Suspense fallback={null}>
218
          <PendingMembershipsDialog />
219
        </Suspense>
220
      )}
221
      <Suspense fallback={null}>
222
        <HelpDialog open={isHelpDialogOpen} onClose={() => setIsHelpDialogOpen(false)} />
223
      </Suspense>
224
      <Menu {...languageMenuProps}>
225
        {languages.map(lng => (
226
          <MenuItem key={lng.key} selected={lng.selected} onClick={lng.onClick}>
227
            <Caption lang={lng.lang}>{lng.label}</Caption>
228
          </MenuItem>
229
        ))}
230
      </Menu>
231
    </>
232
  );
233
};
234

235
export default PlatformNavigationUserMenu;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc