Skip to content

Commit 1aac7d6

Browse files
isabellaenriquezandrewshie-sentry
authored andcommitted
feat(checkout v3): Update product select (#97630)
Closes https://linear.app/getsentry/issue/BIL-1203/update-product-select-styling-and-copy Figma: https://www.figma.com/design/4ICnO5MHVqkm6JV0TKzf7H/Checkout-Redesign?node-id=2682-35176&t=qdEalTpNeinXU3hi-4 Copy is not yet final. Product checkout name comes from backend. # unchecked <img width="680" height="268" alt="Screenshot 2025-08-11 at 5 46 08 PM" src="https://github.com/user-attachments/assets/47458967-aa40-4e21-8139-bc3c2344e487" /> # checked <img width="679" height="265" alt="Screenshot 2025-08-11 at 5 45 49 PM" src="https://github.com/user-attachments/assets/f192424b-58fe-42b7-8e2d-70114056b1b7" />
1 parent 73d2983 commit 1aac7d6

File tree

6 files changed

+252
-69
lines changed

6 files changed

+252
-69
lines changed

static/gsApp/views/amCheckout/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ import type {
7676
SelectedProductData,
7777
} from 'getsentry/views/amCheckout/types';
7878
import {SelectableProduct} from 'getsentry/views/amCheckout/types';
79-
import {getBucket} from 'getsentry/views/amCheckout/utils';
79+
import {getBucket, hasCheckoutV3} from 'getsentry/views/amCheckout/utils';
8080
import {
8181
getTotalBudget,
8282
hasOnDemandBudgetsFeature,
@@ -652,6 +652,7 @@ class AMCheckout extends Component<Props, State> {
652652
const isActive = currentStep === stepNumber;
653653
const isCompleted = !isActive && completedSteps.has(stepNumber);
654654
const prevStepCompleted = completedSteps.has(stepNumber - 1);
655+
const isNewCheckout = hasCheckoutV3(organization); // TODO(checkout-v3): remove post-GA
655656

656657
return (
657658
<CheckoutStep
@@ -662,6 +663,7 @@ class AMCheckout extends Component<Props, State> {
662663
isCompleted={isCompleted}
663664
prevStepCompleted={prevStepCompleted}
664665
referrer={this.referrer}
666+
isNewCheckout={isNewCheckout}
665667
/>
666668
);
667669
});

static/gsApp/views/amCheckout/steps/planSelect.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ function PlanSelect({
129129
subscription,
130130
formData,
131131
referrer,
132+
isNewCheckout,
132133
onEdit,
133134
onToggleLegacy,
134135
onUpdate,
@@ -330,7 +331,12 @@ function PlanSelect({
330331
/>
331332
{isActive && renderBody()}
332333
{isActive && (
333-
<ProductSelect activePlan={activePlan} formData={formData} onUpdate={onUpdate} />
334+
<ProductSelect
335+
activePlan={activePlan}
336+
formData={formData}
337+
onUpdate={onUpdate}
338+
isNewCheckout={isNewCheckout}
339+
/>
334340
)}
335341
{isActive && renderFooter()}
336342
</Panel>

static/gsApp/views/amCheckout/steps/productSelect.spec.tsx

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,45 @@ describe('ProductSelect', function () {
6767
{organization}
6868
);
6969

70-
expect(await screen.findByTestId('body-choose-your-plan')).toBeInTheDocument();
71-
expect(screen.getByTestId('product-option-seer')).toBeInTheDocument();
70+
expect(await screen.findByTestId('product-option-seer')).toBeInTheDocument();
7271
expect(screen.getAllByTestId(/product-option-feature/)).toHaveLength(2);
7372
expect(screen.getAllByTestId(/product-option/)).toHaveLength(3);
7473
expect(screen.getByText('Add to plan')).toBeInTheDocument();
7574
expect(screen.getByTestId('footer-choose-your-plan')).toBeInTheDocument();
7675
});
7776

77+
it('renders for checkout v3', async function () {
78+
const organizationWithFlag = OrganizationFixture({
79+
features: ['checkout-v3'],
80+
});
81+
const freeSubscription = SubscriptionFixture({
82+
organization: organizationWithFlag,
83+
plan: 'am3_f',
84+
isFree: true,
85+
});
86+
SubscriptionStore.set(organizationWithFlag.slug, freeSubscription);
87+
88+
render(
89+
<AMCheckout
90+
{...RouteComponentPropsFixture()}
91+
params={params}
92+
api={api}
93+
onToggleLegacy={jest.fn()}
94+
checkoutTier={PlanTier.AM3}
95+
/>,
96+
{organization: organizationWithFlag}
97+
);
98+
99+
expect(await screen.findByTestId('product-option-seer')).toBeInTheDocument();
100+
expect(screen.getAllByTestId(/product-option-feature/)).toHaveLength(3); // +1 for credits included
101+
expect(screen.getAllByTestId(/product-option/)).toHaveLength(4); // +1 for credits included
102+
expect(screen.queryByText('Add to plan')).not.toBeInTheDocument();
103+
expect(
104+
screen.getByRole('checkbox', {name: /Add seer AI agent to plan/})
105+
).toBeInTheDocument();
106+
expect(screen.getByTestId('footer-choose-your-plan')).toBeInTheDocument();
107+
});
108+
78109
it('does not render products if flags are missing', async function () {
79110
const mockBillingConfig = structuredClone(BillingConfigFixture(PlanTier.AM3));
80111
mockBillingConfig.planList.forEach(plan => {

0 commit comments

Comments
 (0)