From d863f8d8eca34b5b9e7dbc2ee6c02c142a2fcb17 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Fri, 3 Oct 2025 14:53:43 -0700 Subject: [PATCH 1/2] disable chonk opt in if user has exceeded subscriptions --- static/app/types/hooks.tsx | 1 + static/app/utils/theme/ChonkOptInBanner.tsx | 8 +++++++- static/app/views/nav/primary/index.tsx | 5 +++-- static/gsApp/components/chonkOptInBanner.tsx | 16 ++++++++++++++++ static/gsApp/components/navBillingStatus.tsx | 20 +++++++++++++++++--- static/gsApp/registerHooks.tsx | 4 ++++ 6 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 static/gsApp/components/chonkOptInBanner.tsx diff --git a/static/app/types/hooks.tsx b/static/app/types/hooks.tsx index 8e31d6f2311cd7..7969e149b7d5c4 100644 --- a/static/app/types/hooks.tsx +++ b/static/app/types/hooks.tsx @@ -280,6 +280,7 @@ type InterfaceChromeHooks = { footer: GenericComponentHook; 'help-modal:footer': HelpModalFooterHook; 'sidebar:billing-status': GenericOrganizationComponentHook; + 'sidebar:chonk-opt-in-banner': () => React.ReactNode; 'sidebar:help-menu': GenericOrganizationComponentHook; 'sidebar:item-label': SidebarItemLabelHook; 'sidebar:organization-dropdown-menu': GenericOrganizationComponentHook; diff --git a/static/app/utils/theme/ChonkOptInBanner.tsx b/static/app/utils/theme/ChonkOptInBanner.tsx index d92d1512cc99d8..794077930497df 100644 --- a/static/app/utils/theme/ChonkOptInBanner.tsx +++ b/static/app/utils/theme/ChonkOptInBanner.tsx @@ -4,6 +4,7 @@ import {ThemeProvider} from '@emotion/react'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/core/button'; +import HookOrDefault from 'sentry/components/hookOrDefault'; import Panel from 'sentry/components/panels/panel'; import {IconClose} from 'sentry/icons'; import {t} from 'sentry/locale'; @@ -15,7 +16,7 @@ import useMutateUserOptions from 'sentry/utils/useMutateUserOptions'; import {useChonkPrompt} from './useChonkPrompt'; -export function ChonkOptInBanner(props: {collapsed: boolean | 'never'}) { +export function ChonkOptInBannerComponent(props: {collapsed: boolean | 'never'}) { const chonkPrompt = useChonkPrompt(); const config = useLegacyStore(ConfigStore); const {mutate: mutateUserOptions} = useMutateUserOptions(); @@ -63,6 +64,11 @@ export function ChonkOptInBanner(props: {collapsed: boolean | 'never'}) { ); } +export const ChonkOptInBanner = HookOrDefault({ + hookName: 'sidebar:chonk-opt-in-banner', + defaultComponent: () => , +}); + const TranslucentBackgroundPanel = styled(Panel)<{ isDarkMode: boolean; position: 'absolute' | 'relative'; diff --git a/static/app/views/nav/primary/index.tsx b/static/app/views/nav/primary/index.tsx index d720df983a4e50..2825233dd382a8 100644 --- a/static/app/views/nav/primary/index.tsx +++ b/static/app/views/nav/primary/index.tsx @@ -14,7 +14,6 @@ import { IconPrevent, IconSettings, } from 'sentry/icons'; -import {ChonkOptInBanner} from 'sentry/utils/theme/ChonkOptInBanner'; import useOrganization from 'sentry/utils/useOrganization'; import {getDefaultExploreRoute} from 'sentry/views/explore/utils'; import {useNavContext} from 'sentry/views/nav/context'; @@ -179,7 +178,9 @@ export function PrimaryNavigationItems() { - + + + diff --git a/static/gsApp/components/chonkOptInBanner.tsx b/static/gsApp/components/chonkOptInBanner.tsx new file mode 100644 index 00000000000000..bd0fa45b7ed16f --- /dev/null +++ b/static/gsApp/components/chonkOptInBanner.tsx @@ -0,0 +1,16 @@ +import {ChonkOptInBannerComponent} from 'sentry/utils/theme/ChonkOptInBanner'; + +import useSubscription from 'getsentry/hooks/useSubscription'; + +import {useExceededSubscriptionCategories} from './navBillingStatus'; + +export function ChonkOptInBanner() { + const subscription = useSubscription(); + const exceededCategories = useExceededSubscriptionCategories(subscription); + + if (exceededCategories.length === 0) { + return null; + } + + return ; +} diff --git a/static/gsApp/components/navBillingStatus.tsx b/static/gsApp/components/navBillingStatus.tsx index 82e723a6f2691b..6aff194cf4bd84 100644 --- a/static/gsApp/components/navBillingStatus.tsx +++ b/static/gsApp/components/navBillingStatus.tsx @@ -149,10 +149,15 @@ function QuotaExceededContent({ ); } -function PrimaryNavigationQuotaExceeded({organization}: {organization: Organization}) { - const subscription = useSubscription(); +export function useExceededSubscriptionCategories( + subscription: Subscription | null +): DataCategory[] { + if (!subscription) { + return []; + } + const exceededCategories = ( - sortCategoriesWithKeys(subscription?.categories ?? {}) as Array< + sortCategoriesWithKeys(subscription.categories) as Array< [DataCategory, BillingMetricHistory] > ) @@ -181,6 +186,14 @@ function PrimaryNavigationQuotaExceeded({organization}: {organization: Organizat } return acc; }, [] as DataCategory[]); + + return exceededCategories; +} + +function PrimaryNavigationQuotaExceeded({organization}: {organization: Organization}) { + const subscription = useSubscription(); + const exceededCategories = useExceededSubscriptionCategories(subscription); + const promptsToCheck = exceededCategories .map(category => { return `${snakeCase(category)}_overage_alert`; @@ -278,6 +291,7 @@ function PrimaryNavigationQuotaExceeded({organization}: {organization: Organizat subscription && subscription.canSelfServe && !subscription.hasOverageNotificationsDisabled; + if (!shouldShow || isLoading || isError) { return null; } diff --git a/static/gsApp/registerHooks.tsx b/static/gsApp/registerHooks.tsx index db1d648ee96451..b18a4a39d77619 100644 --- a/static/gsApp/registerHooks.tsx +++ b/static/gsApp/registerHooks.tsx @@ -70,6 +70,7 @@ import {useMetricDetectorLimit} from 'getsentry/hooks/useMetricDetectorLimit'; import rawTrackAnalyticsEvent from 'getsentry/utils/rawTrackAnalyticsEvent'; import trackMetric from 'getsentry/utils/trackMetric'; +import {ChonkOptInBanner} from './components/chonkOptInBanner'; import {CodecovSettingsLink} from './components/codecovSettingsLink'; import PrimaryNavigationQuotaExceeded from './components/navBillingStatus'; import OpenInDiscoverBtn from './components/openInDiscoverBtn'; @@ -132,6 +133,9 @@ const GETSENTRY_HOOKS: Partial = { organization={props.organization} /> ), + 'sidebar:chonk-opt-in-banner': () => { + return ; + }, /** * Augment the global help search modal with a contat support button From d86431562060e573ed431b263358cdbf36d5cf6e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 3 Oct 2025 23:25:52 +0000 Subject: [PATCH 2/2] Fix: Show banner only when categories are exceeded Co-authored-by: jonas.badalic --- static/gsApp/components/chonkOptInBanner.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/gsApp/components/chonkOptInBanner.tsx b/static/gsApp/components/chonkOptInBanner.tsx index bd0fa45b7ed16f..fdc3a24805af9c 100644 --- a/static/gsApp/components/chonkOptInBanner.tsx +++ b/static/gsApp/components/chonkOptInBanner.tsx @@ -8,7 +8,7 @@ export function ChonkOptInBanner() { const subscription = useSubscription(); const exceededCategories = useExceededSubscriptionCategories(subscription); - if (exceededCategories.length === 0) { + if (exceededCategories.length > 0) { return null; }