From dcc75ab011b1f2f1bebc9b8e48ee8a0f91ff0984 Mon Sep 17 00:00:00 2001 From: isabellaenriquez Date: Mon, 10 Nov 2025 11:09:34 -0500 Subject: [PATCH 1/4] ref(checkout v3): Clean up routing --- .../traceTypeWarnings/errorsOnlyWarnings.tsx | 2 +- static/gsApp/components/addEventsCTA.tsx | 2 +- .../gsApp/components/ai/AiSetupDataConsent.tsx | 4 ++-- .../components/crons/cronsBannerUpgradeCTA.tsx | 2 +- .../features/dateRangeQueryLimitFooter.tsx | 5 +---- .../features/disabledPerformancePage.tsx | 5 +---- static/gsApp/components/gsBanner.tsx | 2 +- .../gsApp/components/partnerPlanEndingBanner.tsx | 2 +- .../gsApp/components/partnerPlanEndingModal.tsx | 2 +- .../performance/quotaExceededAlert.tsx | 2 +- .../productTrial/productTrialAlert.tsx | 8 ++------ .../profiling/profilingUpgradeModal.tsx | 6 +++--- static/gsApp/components/replayOnboardingCTA.tsx | 2 +- .../components/upgradeNowModal/actionButtons.tsx | 6 +++--- .../upgradeNowModal/modalSamePrice.tsx | 2 +- .../gsApp/components/upgradeNowModal/utils.tsx | 5 ++--- static/gsApp/components/upgradeOrTrialButton.tsx | 5 ++--- static/gsApp/components/upsellProvider.tsx | 2 +- static/gsApp/hooks/dashboardsLimit.tsx | 4 +--- static/gsApp/hooks/rootRoutes.tsx | 3 +-- static/gsApp/hooks/settingsRoutes.tsx | 12 ++---------- static/gsApp/hooks/targetedOnboardingHeader.tsx | 4 +--- .../gsApp/views/amCheckout/checkoutSuccess.tsx | 2 +- static/gsApp/views/amCheckout/index.tsx | 16 ---------------- static/gsApp/views/spendAllocations/index.tsx | 2 +- .../performanceReservedTransactionsPromo.tsx | 2 +- .../subscriptionPage/subscriptionHeader.tsx | 4 ++-- .../gsApp/views/subscriptionPage/usageTotals.tsx | 2 +- 28 files changed, 37 insertions(+), 78 deletions(-) diff --git a/static/app/views/performance/newTraceDetails/traceTypeWarnings/errorsOnlyWarnings.tsx b/static/app/views/performance/newTraceDetails/traceTypeWarnings/errorsOnlyWarnings.tsx index 7cf5c9e2de11ee..fd41b3415571bf 100644 --- a/static/app/views/performance/newTraceDetails/traceTypeWarnings/errorsOnlyWarnings.tsx +++ b/static/app/views/performance/newTraceDetails/traceTypeWarnings/errorsOnlyWarnings.tsx @@ -174,7 +174,7 @@ function PerformanceQuotaExceededWarning(props: ErrorOnlyWarningsProps) { props.tree.shape ); browserHistory.push({ - pathname: `/settings/billing/checkout/?referrer=trace-view`, + pathname: `/checkout/?referrer=trace-view`, query: { skipBundles: true, }, diff --git a/static/gsApp/components/addEventsCTA.tsx b/static/gsApp/components/addEventsCTA.tsx index a08acfd2d4d207..c9ec499a6076b2 100644 --- a/static/gsApp/components/addEventsCTA.tsx +++ b/static/gsApp/components/addEventsCTA.tsx @@ -108,7 +108,7 @@ function AddEventsCTA(props: Props) { }, 0); }; - const checkoutUrl = `/settings/${organization.slug}/billing/checkout/?referrer=${referrer}`; + const checkoutUrl = `/checkout/?referrer=${referrer}`; const subscriptionUrl = `/settings/${organization.slug}/billing/overview/`; switch (action) { diff --git a/static/gsApp/components/ai/AiSetupDataConsent.tsx b/static/gsApp/components/ai/AiSetupDataConsent.tsx index 5e88a1d5051a9a..ed85b6d8728392 100644 --- a/static/gsApp/components/ai/AiSetupDataConsent.tsx +++ b/static/gsApp/components/ai/AiSetupDataConsent.tsx @@ -83,7 +83,7 @@ function AiSetupDataConsent({groupId}: AiSetupDataConsentProps) { const autofixAcknowledgeMutation = useSeerAcknowledgeMutation(); function handlePurchaseSeer() { - navigate(`/settings/billing/checkout/?referrer=ai_setup_data_consent`); + navigate(`/checkout/?referrer=ai_setup_data_consent`); } function handleAddBudget() { @@ -92,7 +92,7 @@ function AiSetupDataConsent({groupId}: AiSetupDataConsentProps) { } if (isPerCategoryOnDemand) { // Seer does not support per category on demand budgets, so we need to redirect to the checkout page to prompt the user to switch - navigate(`/settings/billing/checkout/?referrer=ai_setup_data_consent#step3`); + navigate('/checkout/?referrer=ai_setup_data_consent#step3'); return; } openOnDemandBudgetEditModal({ diff --git a/static/gsApp/components/crons/cronsBannerUpgradeCTA.tsx b/static/gsApp/components/crons/cronsBannerUpgradeCTA.tsx index 6d1226c69bb392..af2a6da0739391 100644 --- a/static/gsApp/components/crons/cronsBannerUpgradeCTA.tsx +++ b/static/gsApp/components/crons/cronsBannerUpgradeCTA.tsx @@ -21,7 +21,7 @@ export function CronsBannerUpgradeCTA({hasBillingAccess}: UpgradeCTAProps) { if (hasBillingAccess) { return ( diff --git a/static/gsApp/components/gsBanner.tsx b/static/gsApp/components/gsBanner.tsx index 488e667247563b..60f153b38cdac0 100644 --- a/static/gsApp/components/gsBanner.tsx +++ b/static/gsApp/components/gsBanner.tsx @@ -1014,7 +1014,7 @@ class GSBanner extends Component { // if there are deactivated members, than anyone who doesn't have org:billing will be // prevented from accessing this view anyways cause they will be deactivated if (isOverMemberLimit && !deactivatedMemberDismissed && this.hasBillingPerms) { - const checkoutUrl = `/settings/${organization.slug}/billing/checkout/?referrer=deactivated_member_header`; + const checkoutUrl = `/checkout/?referrer=deactivated_member_header`; const wrappedNumber = {membersDeactivatedFromLimit}; // only disabling members if the plan allows exactly one member return ( diff --git a/static/gsApp/components/partnerPlanEndingBanner.tsx b/static/gsApp/components/partnerPlanEndingBanner.tsx index 945e81276a1f6e..307d7a13a45813 100644 --- a/static/gsApp/components/partnerPlanEndingBanner.tsx +++ b/static/gsApp/components/partnerPlanEndingBanner.tsx @@ -81,7 +81,7 @@ function PartnerPlanEndingBanner({ analyticsEventName="Partner Plan Ending Banner: Manage Subscription" size="md" onClick={() => handleAnalytics()} - to={`/settings/${organization.slug}/billing/checkout/?referrer=partner_plan_ending_banner`} + to="/checkout/?referrer=partner_plan_ending_banner" > {t('Upgrade to %s', planToUpgradeTo)} diff --git a/static/gsApp/components/partnerPlanEndingModal.tsx b/static/gsApp/components/partnerPlanEndingModal.tsx index 5ad0148b66ea43..d18a759a40d841 100644 --- a/static/gsApp/components/partnerPlanEndingModal.tsx +++ b/static/gsApp/components/partnerPlanEndingModal.tsx @@ -157,7 +157,7 @@ function PartnerPlanEndingModal({organization, subscription, closeModal}: Props) {hasBillingAccess ? ( diff --git a/static/gsApp/components/performance/quotaExceededAlert.tsx b/static/gsApp/components/performance/quotaExceededAlert.tsx index f8b47da50133ac..3870c20566a0c5 100644 --- a/static/gsApp/components/performance/quotaExceededAlert.tsx +++ b/static/gsApp/components/performance/quotaExceededAlert.tsx @@ -79,7 +79,7 @@ function useQuotaExceededAlertMessage( const billingPageLink = ( { - browserHistory.push( - normalizeUrl(`/settings/${organization.slug}/billing/checkout/`) - ); + browserHistory.push(normalizeUrl(`/checkout/`)); }} > {t('Update Plan')} @@ -202,9 +200,7 @@ function ProductTrialAlert(props: ProductTrialAlertProps) { {t('Manage Subscription')} diff --git a/static/gsApp/components/replayOnboardingCTA.tsx b/static/gsApp/components/replayOnboardingCTA.tsx index 4da04d3ef2cb01..cbaa382505c838 100644 --- a/static/gsApp/components/replayOnboardingCTA.tsx +++ b/static/gsApp/components/replayOnboardingCTA.tsx @@ -95,7 +95,7 @@ function ReplayOnboardingCTAUpsell({ if (hasBillingAccess) { // Redirect the user to the subscriptions page, where they will find important information. // If they wish to update their plan, we ask them to contact our sales/support team. - redirectToManage(organization); + redirectToManage(); } return; } diff --git a/static/gsApp/components/upgradeNowModal/actionButtons.tsx b/static/gsApp/components/upgradeNowModal/actionButtons.tsx index 2ab4047b4750b0..8129a37581ba0f 100644 --- a/static/gsApp/components/upgradeNowModal/actionButtons.tsx +++ b/static/gsApp/components/upgradeNowModal/actionButtons.tsx @@ -80,7 +80,7 @@ function ActionButtons({ }); } catch (err) { Sentry.captureException(err); - redirectToManage(organization); + redirectToManage(); } }, [ api, @@ -114,7 +114,7 @@ function ActionButtons({ }); }, onError: () => { - redirectToManage(organization); + redirectToManage(); }, }); }, [api, organization, subscription, surface, onComplete]); @@ -142,7 +142,7 @@ function ActionButtons({ {t('Update Now')} {t('Manage Subscription')} diff --git a/static/gsApp/components/upgradeNowModal/modalSamePrice.tsx b/static/gsApp/components/upgradeNowModal/modalSamePrice.tsx index 0787c94139478b..6df7532db2374d 100644 --- a/static/gsApp/components/upgradeNowModal/modalSamePrice.tsx +++ b/static/gsApp/components/upgradeNowModal/modalSamePrice.tsx @@ -75,7 +75,7 @@ function UpgradeNowModal({ }); } catch (err) { Sentry.captureException(err); - redirectToManage(organization); + redirectToManage(); addErrorMessage( t( 'Oops! Unable to update Subscription automatically. Click through to update manually.' diff --git a/static/gsApp/components/upgradeNowModal/utils.tsx b/static/gsApp/components/upgradeNowModal/utils.tsx index 6d370d333614e1..ca0005573cb00e 100644 --- a/static/gsApp/components/upgradeNowModal/utils.tsx +++ b/static/gsApp/components/upgradeNowModal/utils.tsx @@ -1,11 +1,10 @@ -import type {Organization} from 'sentry/types/organization'; import {browserHistory} from 'sentry/utils/browserHistory'; import normalizeUrl from 'sentry/utils/url/normalizeUrl'; -export function redirectToManage(organization: Organization) { +export function redirectToManage() { browserHistory.replace( normalizeUrl({ - pathname: `/settings/${organization.slug}/billing/checkout/`, + pathname: `/checkout/`, query: { referrer: 'replay_onboard-error-redirect', }, diff --git a/static/gsApp/components/upgradeOrTrialButton.tsx b/static/gsApp/components/upgradeOrTrialButton.tsx index 6b47e8a7ff2f75..b419bf7d646532 100644 --- a/static/gsApp/components/upgradeOrTrialButton.tsx +++ b/static/gsApp/components/upgradeOrTrialButton.tsx @@ -62,7 +62,6 @@ function UpgradeOrTrialButton({ ...props }: BaseButtonProps & (Omit | Omit)) { - const {slug} = organization; const hasAccess = organization.access.includes('org:billing'); // can override action if we want @@ -153,8 +152,8 @@ function UpgradeOrTrialButton({ if (hasAccess) { // send self-serve directly to checkout const baseUrl = subscription.canSelfServe - ? `/settings/${slug}/billing/checkout/` - : `/settings/${slug}/billing/overview/`; + ? '/checkout/' + : '/settings/:orgId/billing/overview/'; return ( - ), + link: , } ) : null; diff --git a/static/gsApp/hooks/rootRoutes.tsx b/static/gsApp/hooks/rootRoutes.tsx index 9e13c9b649f6ce..b1c373d347a480 100644 --- a/static/gsApp/hooks/rootRoutes.tsx +++ b/static/gsApp/hooks/rootRoutes.tsx @@ -7,8 +7,7 @@ import OrganizationSubscriptionContext from 'getsentry/components/organizationSu const rootRoutes = (): SentryRouteObject => ({ children: [ { - // TODO(checkout v3): rename this to /checkout/ when the legacy checkout route is removed - path: '/checkout-v3/', + path: '/checkout/', component: errorHandler(OrganizationSubscriptionContext), deprecatedRouteProps: true, customerDomainOnlyRoute: true, diff --git a/static/gsApp/hooks/settingsRoutes.tsx b/static/gsApp/hooks/settingsRoutes.tsx index 77f8871a2fb077..56bda6722a0471 100644 --- a/static/gsApp/hooks/settingsRoutes.tsx +++ b/static/gsApp/hooks/settingsRoutes.tsx @@ -23,18 +23,10 @@ const settingsRoutes = (): SentryRouteObject => ({ redirectTo: 'overview/', }, { - // TODO(checkout v3): This should be removed when checkout v3 is GA'd + // NOTE: This route is retained for legacy linking path: 'checkout/', name: 'Change', - component: errorHandler(SubscriptionContext), - deprecatedRouteProps: true, - children: [ - { - index: true, - component: make(() => import('../views/decideCheckout')), - deprecatedRouteProps: true, - }, - ], + redirectTo: '/checkout/', }, { path: 'cancel/', diff --git a/static/gsApp/hooks/targetedOnboardingHeader.tsx b/static/gsApp/hooks/targetedOnboardingHeader.tsx index 708fb148e7a1a6..71eb9b79d9d0b8 100644 --- a/static/gsApp/hooks/targetedOnboardingHeader.tsx +++ b/static/gsApp/hooks/targetedOnboardingHeader.tsx @@ -55,9 +55,7 @@ function TargetedOnboardingHeader({source, subscription}: Props) { {cta} } diff --git a/static/gsApp/views/amCheckout/checkoutSuccess.tsx b/static/gsApp/views/amCheckout/checkoutSuccess.tsx index a3ae4d71211d73..5b536af054c71c 100644 --- a/static/gsApp/views/amCheckout/checkoutSuccess.tsx +++ b/static/gsApp/views/amCheckout/checkoutSuccess.tsx @@ -606,7 +606,7 @@ function CheckoutSuccess({ {t('Edit plan')} diff --git a/static/gsApp/views/amCheckout/index.tsx b/static/gsApp/views/amCheckout/index.tsx index 2992a18449d49a..ef7a2cfd1f43ed 100644 --- a/static/gsApp/views/amCheckout/index.tsx +++ b/static/gsApp/views/amCheckout/index.tsx @@ -6,7 +6,6 @@ import {loadStripe} from '@stripe/stripe-js'; import type {Location} from 'history'; import isEqual from 'lodash/isEqual'; import moment from 'moment-timezone'; -import * as qs from 'query-string'; import type {Client} from 'sentry/api'; import {Alert} from 'sentry/components/core/alert'; @@ -134,21 +133,6 @@ class AMCheckout extends Component { ) { props.onToggleLegacy(props.subscription.planTier); } - const query = props.location?.query; - const queryString = - query && Object.keys(query).length > 0 ? `?${qs.stringify(query)}` : ''; - - // TODO(checkout v3): remove these checks once checkout v3 is GA'd and we've remove the legacy checkout route - if (props.location?.pathname.includes('checkout-v3') && !props.isNewCheckout) { - props.navigate( - `/settings/${props.organization.slug}/billing/checkout/${queryString}`, - { - replace: true, - } - ); - } else if (!props.location?.pathname.includes('checkout-v3') && props.isNewCheckout) { - props.navigate(`/checkout-v3/${queryString}`, {replace: true}); - } let step = 1; if (props.location?.hash) { const stepMatch = /^#step(\d)$/.exec(props.location.hash); diff --git a/static/gsApp/views/spendAllocations/index.tsx b/static/gsApp/views/spendAllocations/index.tsx index 4b07b6bdfb4e2d..50d1ff5eda6de6 100644 --- a/static/gsApp/views/spendAllocations/index.tsx +++ b/static/gsApp/views/spendAllocations/index.tsx @@ -371,7 +371,7 @@ export function SpendAllocationsRoot({organization, subscription}: Props) { aria-label={t('Manage Subscription')} size="sm" style={{marginRight: space(1)}} - to={`/settings/${organization.slug}/billing/checkout/?referrer=spend_allocations`} + to="/checkout/?referrer=spend_allocations" > {t('Manage Subscription')} diff --git a/static/gsApp/views/subscriptionPage/promotions/performanceReservedTransactionsPromo.tsx b/static/gsApp/views/subscriptionPage/promotions/performanceReservedTransactionsPromo.tsx index 12c2ec45539851..185e9c2eb086fc 100644 --- a/static/gsApp/views/subscriptionPage/promotions/performanceReservedTransactionsPromo.tsx +++ b/static/gsApp/views/subscriptionPage/promotions/performanceReservedTransactionsPromo.tsx @@ -87,7 +87,7 @@ function openPerformanceReservedTransactionsDiscountModal({ onAccept: () => { navigate( normalizeUrl({ - pathname: `/settings/${organization.slug}/billing/checkout/`, + pathname: '/checkout/', query: { skipBundles: true, }, diff --git a/static/gsApp/views/subscriptionPage/subscriptionHeader.tsx b/static/gsApp/views/subscriptionPage/subscriptionHeader.tsx index 3fecb67e9b2d39..9386c06ef4df27 100644 --- a/static/gsApp/views/subscriptionPage/subscriptionHeader.tsx +++ b/static/gsApp/views/subscriptionPage/subscriptionHeader.tsx @@ -146,7 +146,7 @@ function SubscriptionHeader(props: Props) { {subscription.canSelfServe && hasBillingPerms && ( {t('Manage Subscription')} @@ -210,7 +210,7 @@ function SubscriptionHeader(props: Props) { {subscription.canSelfServe && hasBillingPerms && ( diff --git a/static/gsApp/views/subscriptionPage/usageTotals.tsx b/static/gsApp/views/subscriptionPage/usageTotals.tsx index 7e94c15e75e040..ae9a8c0b676006 100644 --- a/static/gsApp/views/subscriptionPage/usageTotals.tsx +++ b/static/gsApp/views/subscriptionPage/usageTotals.tsx @@ -1081,7 +1081,7 @@ export function CombinedUsageTotals({ } > {tct('Enable [productName]', { From a514aebe45adca1b4689314ec6472dfbeda8380c Mon Sep 17 00:00:00 2001 From: isabellaenriquez Date: Mon, 10 Nov 2025 11:36:15 -0500 Subject: [PATCH 2/4] fix tests + absolute url + normalize url --- src/sentry/organizations/absolute_url.py | 1 + static/app/utils/url/normalizeUrl.spec.tsx | 3 +++ static/app/utils/url/normalizeUrl.tsx | 1 + .../performance/quotaExceededAlert.spec.tsx | 10 ++------- .../components/upsellModal/footer.spec.tsx | 2 +- .../gsApp/components/upsellProvider.spec.tsx | 2 +- static/gsApp/hooks/rootRoutes.tsx | 21 +++++++++++++++++-- 7 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/sentry/organizations/absolute_url.py b/src/sentry/organizations/absolute_url.py index a4e2c62a7154ba..854c613b321452 100644 --- a/src/sentry/organizations/absolute_url.py +++ b/src/sentry/organizations/absolute_url.py @@ -27,6 +27,7 @@ re.compile(r"^\/?(?!settings)[^/]+\/([^/]+)\/getting-started\/(.*)"), r"/getting-started/\1/\2", ), + (re.compile(r"^\/?checkout\/[^/]+\/?.*"), r"/checkout/"), ] diff --git a/static/app/utils/url/normalizeUrl.spec.tsx b/static/app/utils/url/normalizeUrl.spec.tsx index 0122580ef2335d..4618b1e9ed8edb 100644 --- a/static/app/utils/url/normalizeUrl.spec.tsx +++ b/static/app/utils/url/normalizeUrl.spec.tsx @@ -79,6 +79,9 @@ describe('normalizeUrl', () => { ['/onboarding/acme/', '/onboarding/'], ['/onboarding/acme/project/', '/onboarding/project/'], + ['/checkout/', '/checkout/'], + ['/checkout/acme/', '/checkout/'], + ['/organizations/new/', '/organizations/new/'], ['/organizations/albertos-organizations/issues/', '/issues/'], [ diff --git a/static/app/utils/url/normalizeUrl.tsx b/static/app/utils/url/normalizeUrl.tsx index 8429cab1329af4..137eed67ba7a35 100644 --- a/static/app/utils/url/normalizeUrl.tsx +++ b/static/app/utils/url/normalizeUrl.tsx @@ -22,6 +22,7 @@ const NORMALIZE_PATTERNS: Array<[pattern: RegExp, replacement: string]> = [ // Handles /org-slug/project-slug/getting-started/platform/ -> /getting-started/project-slug/platform/ [/^\/?(?!settings)[^/]+\/([^/]+)\/getting-started\/(.*)/, '/getting-started/$1/$2'], [/^\/?accept-terms\/[^/]*\/?$/, '/accept-terms/'], + [/^\/?checkout\/[^/]+\/?.*$/, '/checkout/'], ]; type NormalizeUrlOptions = { diff --git a/static/gsApp/components/performance/quotaExceededAlert.spec.tsx b/static/gsApp/components/performance/quotaExceededAlert.spec.tsx index d484d8dbebe246..e17b6941613df6 100644 --- a/static/gsApp/components/performance/quotaExceededAlert.spec.tsx +++ b/static/gsApp/components/performance/quotaExceededAlert.spec.tsx @@ -121,10 +121,7 @@ describe('Renders QuotaExceededAlert correctly for spans', () => { expect( screen.getByRole('link', {name: /increase your on-demand budget/}) - ).toHaveAttribute( - 'href', - '/settings/billing/checkout/?referrer=trace-view&skipBundles=true' - ); + ).toHaveAttribute('href', '/checkout/?referrer=trace-view&skipBundles=true'); }); it('renders alert when quota is exceeded for logs', async () => { @@ -176,9 +173,6 @@ describe('Renders QuotaExceededAlert correctly for spans', () => { expect( screen.getByRole('link', {name: /increase your on-demand budget/}) - ).toHaveAttribute( - 'href', - '/settings/billing/checkout/?referrer=trace-view&skipBundles=true' - ); + ).toHaveAttribute('href', '/checkout/?referrer=trace-view&skipBundles=true'); }); }); diff --git a/static/gsApp/components/upsellModal/footer.spec.tsx b/static/gsApp/components/upsellModal/footer.spec.tsx index 8d673de636d71a..c8a51243c774f7 100644 --- a/static/gsApp/components/upsellModal/footer.spec.tsx +++ b/static/gsApp/components/upsellModal/footer.spec.tsx @@ -9,7 +9,7 @@ describe('Business Landing Footer', () => { const organization = OrganizationFixture({access: ['org:billing']}); const subscription = SubscriptionFixture({organization}); - const checkoutPage = `/settings/${organization.slug}/billing/checkout/?referrer=upgrade-business-landing.unknown`; + const checkoutPage = '/checkout/?referrer=upgrade-business-landing.unknown'; beforeEach(() => { MockApiClient.clearMockResponses(); diff --git a/static/gsApp/components/upsellProvider.spec.tsx b/static/gsApp/components/upsellProvider.spec.tsx index f269a7cbc4543c..23e02f07f12486 100644 --- a/static/gsApp/components/upsellProvider.spec.tsx +++ b/static/gsApp/components/upsellProvider.spec.tsx @@ -120,7 +120,7 @@ describe('UpsellProvider', () => { expect(router.location).toEqual( expect.objectContaining({ - pathname: `/settings/${org.slug}/billing/checkout/`, + pathname: '/checkout/', query: { referrer: 'upsell-test-abc', }, diff --git a/static/gsApp/hooks/rootRoutes.tsx b/static/gsApp/hooks/rootRoutes.tsx index b1c373d347a480..ab19c28ff7f737 100644 --- a/static/gsApp/hooks/rootRoutes.tsx +++ b/static/gsApp/hooks/rootRoutes.tsx @@ -1,6 +1,8 @@ import {makeLazyloadComponent as make} from 'sentry/makeLazyloadComponent'; import type {SentryRouteObject} from 'sentry/router/types'; import errorHandler from 'sentry/utils/errorHandler'; +import withDomainRedirect from 'sentry/utils/withDomainRedirect'; +import withDomainRequired from 'sentry/utils/withDomainRequired'; import OrganizationSubscriptionContext from 'getsentry/components/organizationSubscriptionContext'; @@ -9,12 +11,27 @@ const rootRoutes = (): SentryRouteObject => ({ { path: '/checkout/', component: errorHandler(OrganizationSubscriptionContext), - deprecatedRouteProps: true, customerDomainOnlyRoute: true, + deprecatedRouteProps: true, + children: [ + { + index: true, + component: withDomainRequired( + make(() => import('getsentry/views/decideCheckout')) + ), + }, + ], + }, + { + path: '/checkout/:orgId/', + component: errorHandler(OrganizationSubscriptionContext), + deprecatedRouteProps: true, children: [ { index: true, - component: make(() => import('getsentry/views/decideCheckout')), + component: withDomainRedirect( + make(() => import('getsentry/views/decideCheckout')) + ), }, ], }, From 23e0a798d59ee0744f2093df53f1f3b45917ad82 Mon Sep 17 00:00:00 2001 From: isabellaenriquez Date: Mon, 10 Nov 2025 11:44:07 -0500 Subject: [PATCH 3/4] cleanup --- .../gsApp/components/features/dateRangeQueryLimitFooter.tsx | 3 ++- static/gsApp/components/gsBanner.tsx | 2 +- static/gsApp/components/productTrial/productTrialAlert.tsx | 6 ++++-- static/gsApp/components/upgradeNowModal/utils.tsx | 2 +- static/gsApp/components/upgradeOrTrialButton.tsx | 3 ++- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/static/gsApp/components/features/dateRangeQueryLimitFooter.tsx b/static/gsApp/components/features/dateRangeQueryLimitFooter.tsx index 1dbf5a25441de2..0c45440d86b0ae 100644 --- a/static/gsApp/components/features/dateRangeQueryLimitFooter.tsx +++ b/static/gsApp/components/features/dateRangeQueryLimitFooter.tsx @@ -5,6 +5,7 @@ import {LinkButton} from 'sentry/components/core/button/linkButton'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {Organization} from 'sentry/types/organization'; +import normalizeUrl from 'sentry/utils/url/normalizeUrl'; import withOrganization from 'sentry/utils/withOrganization'; import {openUpsellModal} from 'getsentry/actionCreators/modal'; @@ -29,7 +30,7 @@ function DateRangeQueryLimitFooter({ subscription, upsellDefaultSelection, }: Props) { - const checkoutUrl = `/checkout/?referrer=checkout-${source}`; + const checkoutUrl = normalizeUrl(`/checkout/?referrer=checkout-${source}`); const canTrial = subscription.canTrial; diff --git a/static/gsApp/components/gsBanner.tsx b/static/gsApp/components/gsBanner.tsx index 60f153b38cdac0..634b4f8a35f845 100644 --- a/static/gsApp/components/gsBanner.tsx +++ b/static/gsApp/components/gsBanner.tsx @@ -1014,7 +1014,7 @@ class GSBanner extends Component { // if there are deactivated members, than anyone who doesn't have org:billing will be // prevented from accessing this view anyways cause they will be deactivated if (isOverMemberLimit && !deactivatedMemberDismissed && this.hasBillingPerms) { - const checkoutUrl = `/checkout/?referrer=deactivated_member_header`; + const checkoutUrl = '/checkout/?referrer=deactivated_member_header'; const wrappedNumber = {membersDeactivatedFromLimit}; // only disabling members if the plan allows exactly one member return ( diff --git a/static/gsApp/components/productTrial/productTrialAlert.tsx b/static/gsApp/components/productTrial/productTrialAlert.tsx index 2aec19022d80ac..4282395a857572 100644 --- a/static/gsApp/components/productTrial/productTrialAlert.tsx +++ b/static/gsApp/components/productTrial/productTrialAlert.tsx @@ -167,7 +167,9 @@ function ProductTrialAlert(props: ProductTrialAlertProps) {