import {Fragment} from 'react'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/button'; import ListLink from 'sentry/components/links/listLink'; import NavTabs from 'sentry/components/navTabs'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {IconCodecov} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {Organization} from 'sentry/types/organization'; import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader'; import {openCodecovModal} from 'getsentry/actionCreators/modal'; import PartnerPlanEndingBanner from 'getsentry/components/partnerPlanEndingBanner'; import type {Subscription} from 'getsentry/types'; import { hasAccessToSubscriptionOverview, hasPerformance, isBizPlanFamily, } from 'getsentry/utils/billing'; import {isDisabledByPartner} from 'getsentry/utils/partnerships'; import PartnershipNote from 'getsentry/views/subscriptionPage/partnershipNote'; import {HeaderCards} from './headerCards/headerCards'; import DecidePendingChanges from './decidePendingChanges'; import ManagedNote from './managedNote'; import {SubscriptionUpsellBanner} from './subscriptionUpsellBanner'; import TrialAlert from './trialAlert'; import {hasPermissions, hasSpendVisibilityNotificationsFeature} from './utils'; const requireBilling = (organization: Organization, isDisabled: boolean) => hasPermissions(organization, 'org:billing') && !isDisabled; // The order of the keys here will determine the order tabs in the UI const tabConfig = [ { key: 'overview', name: t('Overview'), // always show the overview tab show: () => true, }, { key: 'usage', name: t('Usage History'), show: requireBilling, }, { key: 'receipts', name: t('Receipts'), show: requireBilling, }, { key: 'notifications', name: t('Notifications'), show: (organization: Organization, isDisabled: boolean) => { return ( requireBilling(organization, isDisabled) && hasSpendVisibilityNotificationsFeature(organization) ); }, }, { key: 'details', name: t('Billing Details'), show: ( organization: Organization, isDisabled: boolean, subscription: Subscription ) => { return requireBilling(organization, isDisabled) && !subscription.isSelfServePartner; }, }, { key: 'usage-log', name: t('Usage Log'), // always show the usage log tab show: () => true, }, ] as const; type Props = { organization: Organization; subscription: Subscription; }; /** * Header and Tab navigation common across subscription views. */ function SubscriptionHeader(props: Props) { const {subscription, organization} = props; const hasBillingPerms = hasPermissions(organization, 'org:billing'); const isDisabled = isDisabledByPartner(subscription); return ( {tabConfig.reduce((acc, {key, name, show}) => { if (show(organization, isDisabled, subscription)) { acc.push( {name} ); } return acc; }, [] as React.ReactNode[])} } action={ {subscription.canSelfServe && hasBillingPerms && ( )} {hasAccessToSubscriptionOverview(subscription, organization) ? ( ) : null} } body={ // Some billing visibility is disabled by partners like billing modification or contract details isDisabled ? ( ) : hasBillingPerms ? ( ) : ( ) } /> ); } /** * It's important to separate the views for folks with billing permissions (org:billing) and those without. Only * owners and billing admins have the billing scope, everyone else including managers, admins, and members lack that * scope. */ function BodyWithBillingPerms({organization, subscription}: any) { return ( {subscription.pendingChanges ? ( ) : null} {organization.features.includes('partner-billing-migration') && ( )} ); } function BodyWithoutBillingPerms({organization, subscription}: any) { // if a current tier self serve business plan, we have nothing to render in this section if ( isBizPlanFamily(subscription?.planDetails) && hasPerformance(subscription.planDetails) && subscription.canSelfServe ) { return null; } return ( ); } export default SubscriptionHeader; const ActionContainer = styled('div')` display: flex; flex-direction: row; gap: ${space(1)}; padding-top: ${space(1)}; `;