Skip to content

Commit

Permalink
Rename myLicensePrivileges to availableEntitlements
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinyanakiev committed Nov 25, 2024
2 parents ea0d061 + 8ee2f1c commit 30992b1
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 38 deletions.
13 changes: 6 additions & 7 deletions src/core/apollo/generated/apollo-hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18056,6 +18056,8 @@ export function refetchSubspacePageQuery(variables: SchemaTypes.SubspacePageQuer
export const PlatformLevelAuthorizationDocument = gql`
query PlatformLevelAuthorization {
platform {
id
myRoles
authorization {
...MyPrivileges
}
Expand Down Expand Up @@ -22270,16 +22272,13 @@ export function refetchInnovationLibraryQuery(variables?: SchemaTypes.Innovation

export const CampaignBlockCredentialsDocument = gql`
query CampaignBlockCredentials {
platform {
id
myRoles
}
me {
user {
id
agent {
id
credentials {
resourceID
type
}
}
account {
id
license {
Expand Down
8 changes: 3 additions & 5 deletions src/core/apollo/generated/graphql-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23536,6 +23536,8 @@ export type PlatformLevelAuthorizationQuery = {
__typename?: 'Query';
platform: {
__typename?: 'Platform';
id: string;
myRoles: Array<PlatformRole>;
authorization?:
| { __typename?: 'Authorization'; myPrivileges?: Array<AuthorizationPrivilege> | undefined }
| undefined;
Expand Down Expand Up @@ -28784,17 +28786,13 @@ export type CampaignBlockCredentialsQueryVariables = Exact<{ [key: string]: neve

export type CampaignBlockCredentialsQuery = {
__typename?: 'Query';
platform: { __typename?: 'Platform'; id: string; myRoles: Array<PlatformRole> };
me: {
__typename?: 'MeQueryResults';
user?:
| {
__typename?: 'User';
id: string;
agent: {
__typename?: 'Agent';
id: string;
credentials?: Array<{ __typename?: 'Credential'; resourceID: string; type: CredentialType }> | undefined;
};
account?:
| {
__typename?: 'Account';
Expand Down
9 changes: 8 additions & 1 deletion src/core/i18n/en/translation.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,13 @@
"year": "{{count}} year",
"year_plural": "{{count}} years"
}
},
"roles": {
"GLOBAL_ADMIN": "Global Admin",
"SUPPORT": "Support Admin",
"LICENSE_MANAGER": "License Manager",
"BETA_TESTER": "Beta Tester",
"VC_CAMPAIGN": "VC Early Access"
}
},
"community": {
Expand All @@ -585,7 +592,7 @@
"memberOrganizations": "Member Organizations ({{count}})",
"pendingApplications": "Pending applications",
"pendingMemberships": "Pending applications & invitations",
"invitationSent": "Invitation sent succesfully",
"invitationSent": "Invitation sent successfully",
"leads": "Leads",
"members": "Members",
"host": "Host",
Expand Down
44 changes: 44 additions & 0 deletions src/core/ui/icon/BadgeLabel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { TypographyProps, useTheme } from '@mui/material';
import { gutters } from '../grid/utils';
import { Caption } from '../typography';

interface BadgeLabelProps extends TypographyProps {
count?: string;
size?: 'small' | 'medium';
}

// copy of BadgeCounter but supporting auto width text
const BadgeSizes: Record<NonNullable<BadgeLabelProps['size']>, TypographyProps> = {
small: {
fontSize: '0.7rem',
lineHeight: gutters(0.8),
width: 'auto',
height: gutters(0.8),
},
medium: {
width: 'auto',
height: gutters(1),
},
};

const BadgeLabel = ({ count, size = 'medium', ...props }: BadgeLabelProps) => {
const theme = useTheme();

return (
<Caption
bgcolor={theme.palette.text.primary}
color={theme.palette.background.paper}
fontWeight="bold"
display="inline-block"
borderRadius={`${theme.shape.borderRadius / 2}px`}
paddingX={gutters(0.2)}
textAlign="center"
{...BadgeSizes[size]}
{...props}
>
{count}
</Caption>
);
};

export default BadgeLabel;
1 change: 1 addition & 0 deletions src/core/ui/navigation/NavigationBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const NavigationBarContent = ({ transparent, children }: PropsWithChildren<Navig
backgroundColor: theme => alpha(theme.palette.primary.main, transparent ? 0 : 0.25),
backdropFilter: transparent ? 'none' : 'blur(8px)',
position: 'relative',
overflow: 'visible',
height: gutters(NAVIGATION_CONTAINER_HEIGHT_GUTTERS - 1),
maxWidth: gutters(MAX_CONTENT_WIDTH_GUTTERS - 2),
}}
Expand Down
20 changes: 18 additions & 2 deletions src/domain/community/user/providers/UserProvider/UserProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import {
useUserProviderQuery,
} from '@/core/apollo/generated/apollo-hooks';
import { ErrorPage } from '@/core/pages/Errors/ErrorPage';
import { AuthorizationPrivilege, LicenseEntitlementType, User } from '@/core/apollo/generated/graphql-schema';
import {
AuthorizationPrivilege,
LicenseEntitlementType,
PlatformRole,
User,
} from '@/core/apollo/generated/graphql-schema';
import { useAuthenticationContext } from '@/core/auth/authentication/hooks/useAuthenticationContext';
import { toUserMetadata, UserMetadata } from '../../hooks/useUserMetadataWrapper';

Expand All @@ -17,6 +22,7 @@ export interface UserContextValue {
loadingMe: boolean; // Loading Authentication and Profile data. Once it's false that's enough for showing the page header and avatar.
verified: boolean;
isAuthenticated: boolean;
platformRoles: PlatformRole[];
accountPrivileges: AuthorizationPrivilege[];
accountEntitlements: LicenseEntitlementType[];
}
Expand All @@ -28,6 +34,7 @@ const UserContext = createContext<UserContextValue>({
loadingMe: true,
verified: false,
isAuthenticated: false,
platformRoles: [],
accountPrivileges: [],
accountEntitlements: [],
});
Expand Down Expand Up @@ -75,10 +82,19 @@ const UserProvider: FC = ({ children }) => {
loadingMe: loadingMeAndParentQueries,
verified,
isAuthenticated,
platformRoles: platformLevelAuthorizationData?.platform.myRoles ?? [],
accountPrivileges: meData?.me.user?.account?.authorization?.myPrivileges ?? [],
accountEntitlements: meData?.me.user?.account?.license?.availableEntitlements ?? [],
}),
[userMetadata, loading, loadingMeAndParentQueries, verified, isAuthenticated]
[
userMetadata,
loading,
loadingMeAndParentQueries,
verified,
isAuthenticated,
platformLevelAuthorizationData,
meData,
]
);

if (error) return <ErrorPage error={error} />;
Expand Down
2 changes: 2 additions & 0 deletions src/domain/platform/PlatformLevelAuthorization.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
query PlatformLevelAuthorization {
platform {
id
myRoles
authorization {
...MyPrivileges
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
query CampaignBlockCredentials {
platform {
id
myRoles
}
me {
user {
id
agent {
id
credentials {
resourceID
type
}
}
account {
id
license {
Expand Down
14 changes: 8 additions & 6 deletions src/main/topLevelPages/myDashboard/Campaigns/CampaignBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCampaignBlockCredentialsQuery } from '@/core/apollo/generated/apollo-hooks';
import { CredentialType, LicenseEntitlementType } from '@/core/apollo/generated/graphql-schema';
import { LicenseEntitlementType, PlatformRole } from '@/core/apollo/generated/graphql-schema';
import PageContentBlock from '@/core/ui/content/PageContentBlock';
import useNewVirtualContributorWizard from '../newVirtualContributorWizard/useNewVirtualContributorWizard';
import CampaignBlockCreateVC from './CampaignBlockCreateVC';
Expand All @@ -10,14 +10,16 @@ const CampaignBlock = () => {
// Do not remove: Inside the blocks startWizard() is being called with a ClickEvent and that messes up with the param that startWizard expects
const handleStartWizard = () => startWizard();

const userRoles: CredentialType[] | undefined = data?.me.user?.agent.credentials?.map(credential => credential.type);
const userEntitlements: LicenseEntitlementType[] | undefined = data?.me.user?.account?.license?.availableEntitlements;
const rolesAvailableTo = [CredentialType.VcCampaign, CredentialType.BetaTester];
const userPlatformRoles: PlatformRole[] | undefined = data?.platform.myRoles;
const userAccountEntitlements: LicenseEntitlementType[] | undefined =
data?.me.user?.account?.license?.availableEntitlements;
const platfromRolesToDisplayCampaignBlockTo = [PlatformRole.VcCampaign];
const entitlementsAvailableTo = [LicenseEntitlementType.AccountVirtualContributor];

// the campaign block should be visible only for VcCampaign users ATM
if (
!userRoles?.some(role => rolesAvailableTo.includes(role)) ||
!userEntitlements?.some(entitlement => entitlementsAvailableTo.includes(entitlement))
!userPlatformRoles?.some(role => platfromRolesToDisplayCampaignBlockTo.includes(role)) ||
!userAccountEntitlements?.some(entitlement => entitlementsAvailableTo.includes(entitlement))
) {
return null;
}
Expand Down
21 changes: 19 additions & 2 deletions src/main/ui/platformNavigation/PlatformNavigationUserAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import MenuTriggerButton from '@/core/ui/tooltip/MenuTriggerButton';
import { PLATFORM_NAVIGATION_MENU_Z_INDEX } from './constants';
import NavigationItemContainer from '@/core/ui/navigation/NavigationItemContainer';
import { useTranslation } from 'react-i18next';
import BadgeLabel from '@/core/ui/icon/BadgeLabel';
import { PlatformRole } from '@/core/apollo/generated/graphql-schema';

interface PlatformNavigationUserAvatarProps {
children: ReactElement<{ onClose?: () => void }>;
Expand All @@ -17,24 +19,27 @@ interface PlatformNavigationUserAvatarProps {

const PlatformNavigationUserAvatar = ({ drawer, children }: PlatformNavigationUserAvatarProps) => {
const { t } = useTranslation();
const { user, isAuthenticated, loadingMe } = useUserContext();
const { user, isAuthenticated, loadingMe, platformRoles } = useUserContext();

const theme = useTheme();

const showBetaBadge = user && isAuthenticated && platformRoles.includes(PlatformRole.BetaTester);

return (
<MenuTriggerButton
keepMounted
drawer={drawer}
placement="bottom-end"
renderTrigger={({ ref, onClick, ...props }) => (
<SwapColors>
<NavigationItemContainer ref={ref as Ref<HTMLDivElement>} position="relative">
<NavigationItemContainer ref={ref as Ref<HTMLDivElement>} position="relative" overflow="visible">
<Paper
component={Avatar}
src={user?.user.profile.avatar?.uri}
sx={{
padding: 0,
cursor: 'pointer',
position: 'relative',
}}
aria-label={t('buttons.userMenu')}
onClick={onClick}
Expand All @@ -47,6 +52,18 @@ const PlatformNavigationUserAvatar = ({ drawer, children }: PlatformNavigationUs
)}
{!loadingMe && !isAuthenticated && <Person color="primary" />}
</Paper>
{showBetaBadge && (
<BadgeLabel
count="Beta"
size="small"
sx={{
position: 'absolute',
bottom: '-8px',
right: '-12px',
zIndex: PLATFORM_NAVIGATION_MENU_Z_INDEX + 1,
}}
/>
)}
<Box
position="absolute"
top={0}
Expand Down
35 changes: 27 additions & 8 deletions src/main/ui/platformNavigation/PlatformNavigationUserMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { forwardRef, PropsWithChildren, ReactNode, useMemo, useState } from 'react';
import { Box, Divider, MenuList, Typography } from '@mui/material';
import AlkemioAvatar from '@/core/ui/image/AlkemioAvatar';
import { BlockTitle, Caption } from '@/core/ui/typography';
import { gutters } from '@/core/ui/grid/utils';
import { buildLoginUrl, buildUserProfileUrl } from '@/main/routing/urlBuilders';
Expand All @@ -16,7 +15,7 @@ import {
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import { AUTH_LOGOUT_PATH } from '@/core/auth/authentication/constants/authentication.constants';
import { useTranslation } from 'react-i18next';
import { AuthorizationPrivilege } from '@/core/apollo/generated/graphql-schema';
import { AuthorizationPrivilege, PlatformRole } from '@/core/apollo/generated/graphql-schema';
import { useUserContext } from '@/domain/community/user';
import Gutters from '@/core/ui/grid/Gutters';
import { ROUTE_HOME } from '@/domain/platform/routes/constants';
Expand All @@ -29,6 +28,7 @@ import NavigatableMenuItem from '@/core/ui/menu/NavigatableMenuItem';
import GlobalMenuSurface from '@/core/ui/menu/GlobalMenuSurface';
import { FocusTrap } from '@mui/base/FocusTrap';
import usePlatformOrigin from '@/domain/platform/routes/usePlatformOrigin';
import Avatar from '@/core/ui/avatar/Avatar';

interface PlatformNavigationUserMenuProps {
surface: boolean;
Expand All @@ -47,18 +47,32 @@ const PlatformNavigationUserMenu = forwardRef<HTMLDivElement, PropsWithChildren<
const platformOrigin = usePlatformOrigin();
const homeUrl = platformOrigin && `${platformOrigin}${ROUTE_HOME}`;

const { user: { user, hasPlatformPrivilege } = {}, isAuthenticated } = useUserContext();
const { user: { user, hasPlatformPrivilege } = {}, isAuthenticated, platformRoles } = useUserContext();

// todo: change with PlatformRole.GlobalAdmin?
const isAdmin = hasPlatformPrivilege?.(AuthorizationPrivilege.PlatformAdmin);

const [isHelpDialogOpen, setIsHelpDialogOpen] = useState(false);

// the roles should follow the order
const role = useMemo(() => {
if (isAdmin) {
// TODO change role name path
return t('common.enums.authorization-credentials.GLOBAL_ADMIN.name');
for (const platformRole of platformRoles) {
switch (platformRole) {
case PlatformRole.GlobalAdmin:
return t('common.roles.GLOBAL_ADMIN');
case PlatformRole.Support:
return t('common.roles.SUPPORT');
case PlatformRole.LicenseManager:
return t('common.roles.LICENSE_MANAGER');
case PlatformRole.BetaTester:
return t('common.roles.BETA_TESTER');
case PlatformRole.VcCampaign:
return t('common.roles.VC_CAMPAIGN');
default:
return null;
}
}
}, [isAdmin, t]);
}, [platformRoles, t]);

const Wrapper = surface ? GlobalMenuSurface : Box;

Expand All @@ -67,7 +81,12 @@ const PlatformNavigationUserMenu = forwardRef<HTMLDivElement, PropsWithChildren<
<Wrapper ref={ref}>
{user && (
<Gutters disableGap alignItems="center" sx={{ paddingBottom: 1 }}>
<AlkemioAvatar size="lg" src={user.profile.avatar?.uri} />
<Avatar
size="large"
src={user.profile.avatar?.uri}
aria-label="User avatar"
alt={t('common.avatar-of', { user: user.profile?.displayName })}
/>
<BlockTitle lineHeight={gutters(2)}>{user.profile.displayName}</BlockTitle>
{role && (
<Caption color="neutralMedium.main" textTransform="uppercase">
Expand Down

0 comments on commit 30992b1

Please sign in to comment.