diff --git a/jsapp/js/account/accountSidebar.module.scss b/jsapp/js/account/accountSidebar.module.scss index b068805e9c..8cc4432d30 100644 --- a/jsapp/js/account/accountSidebar.module.scss +++ b/jsapp/js/account/accountSidebar.module.scss @@ -33,7 +33,7 @@ color: inherit; padding: 0 0 0 18px !important; border-left: 3px solid transparent; - margin-bottom: 18px; + margin-bottom: 16px; cursor: pointer; .newLinkLabelText { @@ -59,7 +59,7 @@ } .subhead { - padding: 0 0 0 18px !important; + padding: 0 0 0 20px !important; margin-bottom: 16px; font-size: 12px; font-weight: 600; diff --git a/jsapp/js/account/accountSidebar.tsx b/jsapp/js/account/accountSidebar.tsx index 41aa3a54ba..1966d65fee 100644 --- a/jsapp/js/account/accountSidebar.tsx +++ b/jsapp/js/account/accountSidebar.tsx @@ -1,4 +1,4 @@ -import React, {useContext, useMemo, useState} from 'react'; +import React, {useMemo, useState} from 'react'; import {NavLink} from 'react-router-dom'; import {observer} from 'mobx-react-lite'; import styles from './accountSidebar.module.scss'; @@ -7,9 +7,14 @@ import Icon from 'js/components/common/icon'; import type {IconName} from 'jsapp/fonts/k-icons'; import Badge from '../components/common/badge'; import subscriptionStore from 'js/account/subscriptionStore'; +import envStore from 'js/envStore'; import useWhenStripeIsEnabled from 'js/hooks/useWhenStripeIsEnabled.hook'; import {ACCOUNT_ROUTES} from 'js/account/routes.constants'; import {useOrganizationQuery} from './stripe.api'; +import {OrganizationUserRole} from './stripe.types'; +import {useFeatureFlag, FeatureFlag} from 'js/featureFlags'; +import {getSimpleMMOLabel} from './organizations/organizations.utils'; +import LoadingSpinner from 'js/components/common/loadingSpinner'; interface AccountNavLinkProps { iconName: IconName; @@ -36,56 +41,168 @@ function AccountNavLink(props: AccountNavLinkProps) { ); } -function AccountSidebar() { - const [showPlans, setShowPlans] = useState(false); - - const orgQuery = useOrganizationQuery(); +// TODO: When we no longer hide the MMO sidebar behind a feature flag, +// the check for org ownership can be removed as it will be logically entailed +// by the org being single-user. +function renderSingleUserOrgSidebar( + isStripeEnabled: boolean, + showAddOnsLink: boolean, + isOwner: boolean +) { + return ( + + ); +} - useWhenStripeIsEnabled(() => { - if (!subscriptionStore.isInitialised) { - subscriptionStore.fetchSubscriptionInfo(); - } - setShowPlans(true); - }, [subscriptionStore.isInitialised]); +function renderMmoSidebar( + userRole: OrganizationUserRole, + isStripeEnabled: boolean, + showAddOnsLink: boolean, + mmoLabel: string +) { + const showBillingRoutes = + userRole === OrganizationUserRole.owner && isStripeEnabled; + const hasAdminPrivileges = [ + OrganizationUserRole.admin, + OrganizationUserRole.owner, + ].includes(userRole); return ( ); } +function AccountSidebar() { + const [isStripeEnabled, setIsStripeEnabled] = useState(false); + const enableMMORoutes = useFeatureFlag(FeatureFlag.mmosEnabled); + const orgQuery = useOrganizationQuery(); + + useWhenStripeIsEnabled(() => { + if (!subscriptionStore.isInitialised) { + subscriptionStore.fetchSubscriptionInfo(); + } + setIsStripeEnabled(true); + }, [subscriptionStore.isInitialised]); + + const showAddOnsLink = useMemo(() => { + return !subscriptionStore.planResponse.length; + }, [subscriptionStore.isInitialised]); + + const mmoLabel = getSimpleMMOLabel( + envStore.data, + subscriptionStore.activeSubscriptions[0] + ); + + if (!orgQuery.data) { + return ; + } + + if (orgQuery.data.is_mmo && enableMMORoutes) { + return renderMmoSidebar( + orgQuery.data?.request_user_role, + isStripeEnabled, + showAddOnsLink, + mmoLabel + ); + } + + return renderSingleUserOrgSidebar( + isStripeEnabled, + showAddOnsLink, + orgQuery.data.is_owner + ); +} + export default observer(AccountSidebar); diff --git a/jsapp/svg-icons/users.svg b/jsapp/svg-icons/users.svg new file mode 100644 index 0000000000..86cac0349c --- /dev/null +++ b/jsapp/svg-icons/users.svg @@ -0,0 +1,6 @@ + + + + + +