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

alkem-io / client-web / #10235

05 Feb 2025 04:32PM UTC coverage: 5.791%. First build
#10235

Pull #7599

travis-ci

Pull Request #7599: retrieve the number of pending invitations as number; add limit to number of dashboard entries to return

192 of 11023 branches covered (1.74%)

Branch coverage included in aggregate %.

1 of 12 new or added lines in 6 files covered. (8.33%)

1545 of 18970 relevant lines covered (8.14%)

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 { PropsWithChildren, ReactNode, useState, Suspense } from 'react';
2
import { Box, Divider, MenuList, Typography } from '@mui/material';
3
import { BlockTitle, Caption } from '@/core/ui/typography';
4
import { gutters } from '@/core/ui/grid/utils';
5
import { buildLoginUrl, buildUserAccountUrl } from '@/main/routing/urlBuilders';
6
import {
7
  AssignmentIndOutlined,
8
  DashboardOutlined,
9
  ExitToAppOutlined,
10
  HdrStrongOutlined,
11
  LanguageOutlined,
12
  MeetingRoomOutlined,
13
} from '@mui/icons-material';
14
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
15
import { AUTH_LOGOUT_PATH } from '@/core/auth/authentication/constants/authentication.constants';
16
import { useTranslation } from 'react-i18next';
17
import { AuthorizationPrivilege, RoleName } from '@/core/apollo/generated/graphql-schema';
18
import { useCurrentUserContext } from '@/domain/community/userCurrent/useCurrentUserContext';
19
import Gutters from '@/core/ui/grid/Gutters';
20
import { ROUTE_HOME, ROUTE_USER_ME } from '@/domain/platform/routes/constants';
21
import LanguageSelect from '@/core/ui/language/LanguageSelect';
22
import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
23
import { PLATFORM_NAVIGATION_MENU_Z_INDEX } from './constants';
24
import { useLocation } from 'react-router-dom';
25
import NavigatableMenuItem from '@/core/ui/menu/NavigatableMenuItem';
26
import GlobalMenuSurface from '@/core/ui/menu/GlobalMenuSurface';
27
import usePlatformOrigin from '@/domain/platform/routes/usePlatformOrigin';
28
import Avatar from '@/core/ui/avatar/Avatar';
29
import {
30
  PendingMembershipsDialogType,
31
  usePendingMembershipsDialog,
32
} from '@/domain/community/pendingMembership/PendingMembershipsDialogContext';
33
import { usePendingInvitationsCount } from '@/domain/community/pendingMembership/usePendingInvitationsCount';
34
import FocusTrap from '@mui/material/Unstable_TrapFocus';
35
import LocalOfferOutlinedIcon from '@mui/icons-material/LocalOfferOutlined';
36
import { lazyWithGlobalErrorHandler } from '@/core/lazyLoading/lazyWithGlobalErrorHandler';
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,
NEW
55
  footer,
×
NEW
56
  children,
×
57
}: PropsWithChildren<PlatformNavigationUserMenuProps> & {
58
  ref?: React.Ref<HTMLDivElement>;
×
59
}) => {
60
  const { t } = useTranslation();
×
61

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

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

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

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

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

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

76
  // the roles should follow the order
×
77
  const getRole = (): string | null => {
78
    for (const platformRole of platformRoles) {
×
79
      switch (platformRole) {
80
        case RoleName.GlobalAdmin:
×
81
          return t('common.roles.GLOBAL_ADMIN');
82
        case RoleName.GlobalSupport:
83
          return t('common.roles.GLOBAL_SUPPORT');
84
        case RoleName.GlobalLicenseManager:
85
          return t('common.roles.GLOBAL_LICENSE_MANAGER');
×
86
        case RoleName.PlatformBetaTester:
87
          return t('common.roles.PLATFORM_BETA_TESTER');
×
88
        case RoleName.PlatformVcCampaign:
89
          return t('common.roles.PLATFORM_VC_CAMPAIGN');
90
      }
×
91
    }
92
    return null;
93
  };
94
  const role = getRole();
95

96
  const Wrapper = surface ? GlobalMenuSurface : Box;
97

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

225
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