Skip to content

Commit ec163eb

Browse files
chore(checkout v3): Remove suggested amount buttons (#99545)
Remove suggested amount buttons. <img width="970" height="658" alt="Screenshot 2025-09-15 at 5 55 09 PM" src="https://github.com/user-attachments/assets/911d3bbb-0169-4ab6-9110-9d50faec4fec" /> (Also snuck a small fix to make interrim header card state look okay on Subscription Overview page -- see https://test-billing.sentry.io/settings/billing/overview/)
1 parent f6728e1 commit ec163eb

File tree

4 files changed

+37
-109
lines changed

4 files changed

+37
-109
lines changed

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,6 @@ describe('SetSpendCap', () => {
7676
expect(
7777
screen.queryByRole('textbox', {name: 'Custom errors spending cap'})
7878
).not.toBeInTheDocument();
79-
80-
await userEvent.click(
81-
screen.getByRole('button', {name: '$500 suggested shared spending cap'})
82-
);
83-
expect(paygInput).toHaveValue('500');
8479
});
8580

8681
it('renders for checkout v3 on pre-AM3 tier', async () => {
@@ -131,9 +126,5 @@ describe('SetSpendCap', () => {
131126
name: 'Custom errors spending cap',
132127
});
133128
expect(errorsPaygInput).toBeInTheDocument();
134-
await userEvent.click(
135-
screen.getByRole('button', {name: '$300 suggested errors spending cap'})
136-
);
137-
expect(errorsPaygInput).toHaveValue('300');
138129
});
139130
});

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

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,7 @@ function SetSpendCap({
4242
}, [formData.selectedProducts]);
4343

4444
const handleBudgetChange = useCallback(
45-
({
46-
onDemandBudgets,
47-
fromButton,
48-
}: {
49-
fromButton: boolean;
50-
onDemandBudgets: OnDemandBudgets;
51-
}) => {
45+
({onDemandBudgets}: {onDemandBudgets: OnDemandBudgets}) => {
5246
const totalBudget = getTotalBudget(onDemandBudgets);
5347
onUpdate({
5448
...formData,
@@ -62,7 +56,7 @@ function SetSpendCap({
6256
subscription,
6357
plan: formData.plan,
6458
cents: totalBudget || 0,
65-
method: fromButton ? 'button' : 'textbox',
59+
method: 'textbox',
6660
});
6761
}
6862
},
@@ -87,9 +81,7 @@ function SetSpendCap({
8781
onDemandBudgets={
8882
formData.onDemandBudget ?? parseOnDemandBudgetsFromSubscription(subscription)
8983
}
90-
onUpdate={({onDemandBudgets, fromButton}) =>
91-
handleBudgetChange({onDemandBudgets, fromButton: !!fromButton})
92-
}
84+
onUpdate={({onDemandBudgets}) => handleBudgetChange({onDemandBudgets})}
9385
currentReserved={formData.reserved}
9486
additionalProducts={additionalProducts}
9587
isOpen={isOpen}

static/gsApp/views/spendCaps/spendCapSettings.tsx

Lines changed: 21 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import type React from 'react';
2-
import {Fragment, useState} from 'react';
2+
import {Fragment} from 'react';
33
import styled from '@emotion/styled';
44
import Color from 'color';
55

6-
import {Button} from 'sentry/components/core/button';
7-
import {ButtonBar} from 'sentry/components/core/button/buttonBar';
86
import {Input} from 'sentry/components/core/input';
97
import {Flex, Grid} from 'sentry/components/core/layout';
108
import {Radio} from 'sentry/components/core/radio';
@@ -27,8 +25,6 @@ import type {SelectableProduct} from 'getsentry/views/amCheckout/types';
2725
import {displayPrice, displayPriceWithCents} from 'getsentry/views/amCheckout/utils';
2826
import {convertOnDemandBudget} from 'getsentry/views/onDemandBudgets/utils';
2927

30-
const SUGGESTED_SPENDING_CAPS = [300_00, 500_00, 1_000_00, 10_000_00];
31-
3228
type PartialSpendCapUpdate = Partial<Record<DataCategory, number>> & {
3329
sharedMaxBudget?: number;
3430
};
@@ -45,13 +41,7 @@ interface SpendCapSettingsProps {
4541
currentReserved: Partial<Record<DataCategory, number>>;
4642
header: React.ReactNode;
4743
onDemandBudgets: OnDemandBudgets;
48-
onUpdate: ({
49-
onDemandBudgets,
50-
fromButton,
51-
}: {
52-
onDemandBudgets: OnDemandBudgets;
53-
fromButton?: boolean;
54-
}) => void;
44+
onUpdate: ({onDemandBudgets}: {onDemandBudgets: OnDemandBudgets}) => void;
5545
isOpen?: boolean;
5646
}
5747

@@ -72,13 +62,7 @@ interface SpendCapInputProps extends Pick<SpendCapSettingsProps, 'activePlan'> {
7262
budgetMode: OnDemandBudgetMode;
7363
category: DataCategory | null;
7464
currentSpendingCap: number;
75-
onUpdate: ({
76-
newData,
77-
fromButton,
78-
}: {
79-
newData: PartialSpendCapUpdate;
80-
fromButton?: boolean;
81-
}) => void;
65+
onUpdate: ({newData}: {newData: PartialSpendCapUpdate}) => void;
8266
reserved: number | null;
8367
}
8468

@@ -129,9 +113,6 @@ function SpendCapInput({
129113
category,
130114
reserved,
131115
}: SpendCapInputProps) {
132-
const [selectedButton, setSelectedButton] = useState<string | null>(
133-
`button-${currentSpendingCap}`
134-
);
135116
// category and reserved should never be null for per category but this makes TS happy
136117
const isPerCategory =
137118
budgetMode === OnDemandBudgetMode.PER_CATEGORY &&
@@ -158,50 +139,23 @@ function SpendCapInput({
158139
};
159140

160141
return (
161-
<Flex align="center" justify="start" gap="md">
162-
<ButtonBar merged gap="0">
163-
{SUGGESTED_SPENDING_CAPS.map(cap => {
164-
const isSelected = selectedButton === `button-${cap}`;
165-
const formattedCap = displayPrice({cents: cap});
166-
return (
167-
<StyledButton
168-
key={cap}
169-
onClick={() => {
170-
setSelectedButton(`button-${cap}`);
171-
onUpdate({
172-
newData: {[inputName]: cap},
173-
fromButton: true,
174-
});
175-
}}
176-
aria-checked={isSelected}
177-
isSelected={isSelected}
178-
aria-label={t('%s suggested %s spending cap', formattedCap, displayName)}
179-
>
180-
{formattedCap}
181-
</StyledButton>
182-
);
183-
})}
184-
</ButtonBar>
185-
<Currency>
186-
<StyledInput
187-
aria-label={t('Custom %s spending cap', displayName)}
188-
name={`spending-cap-${inputName}`}
189-
type="text"
190-
inputMode="numeric"
191-
pattern="[0-9]*"
192-
placeholder="300"
193-
value={coerceValue(currentSpendingCap)}
194-
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
195-
const parsedBudget = parseInputValue(e);
196-
onUpdate({
197-
newData: {[inputName]: parsedBudget},
198-
fromButton: false,
199-
});
200-
setSelectedButton(`button-${parsedBudget}`);
201-
}}
202-
/>
203-
</Currency>
204-
</Flex>
142+
<Currency>
143+
<StyledInput
144+
aria-label={t('Custom %s spending cap', displayName)}
145+
name={`spending-cap-${inputName}`}
146+
type="text"
147+
inputMode="numeric"
148+
pattern="[0-9]*"
149+
placeholder="300"
150+
value={coerceValue(currentSpendingCap)}
151+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
152+
const parsedBudget = parseInputValue(e);
153+
onUpdate({
154+
newData: {[inputName]: parsedBudget},
155+
});
156+
}}
157+
/>
158+
</Currency>
205159
);
206160
}
207161

@@ -328,13 +282,7 @@ function InnerSpendCapSettings({
328282
currentReserved,
329283
additionalProducts,
330284
}: InnerSpendCapSettingsProps) {
331-
const handleUpdate = ({
332-
newData,
333-
fromButton,
334-
}: {
335-
newData: PartialSpendCapUpdate;
336-
fromButton?: boolean;
337-
}) => {
285+
const handleUpdate = ({newData}: {newData: PartialSpendCapUpdate}) => {
338286
if (onDemandBudgets.budgetMode === OnDemandBudgetMode.PER_CATEGORY) {
339287
onUpdate({
340288
onDemandBudgets: {
@@ -344,15 +292,13 @@ function InnerSpendCapSettings({
344292
...newData,
345293
},
346294
},
347-
fromButton,
348295
});
349296
} else {
350297
onUpdate({
351298
onDemandBudgets: {
352299
...onDemandBudgets,
353300
...newData,
354301
},
355-
fromButton,
356302
});
357303
}
358304
};
@@ -673,14 +619,6 @@ const ExampleContainer = styled('div')`
673619
}
674620
`;
675621

676-
// TODO(isabella): fix text color
677-
const StyledButton = styled(Button)<{isSelected: boolean}>`
678-
color: ${p => (p.isSelected ? p.theme.activeText : p.theme.gray500)};
679-
&:hover {
680-
color: ${p => p.theme.activeText};
681-
}
682-
`;
683-
684622
const StyledInput = styled(Input)`
685623
width: 124px;
686624
text-align: right;

static/gsApp/views/subscriptionPage/headerCards/headerCards.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {css} from '@emotion/react';
12
import styled from '@emotion/styled';
23

34
import ErrorBoundary from 'sentry/components/errorBoundary';
@@ -6,6 +7,7 @@ import {space} from 'sentry/styles/space';
67
import type {Organization} from 'sentry/types/organization';
78

89
import type {Subscription} from 'getsentry/types';
10+
import {hasCheckoutV3} from 'getsentry/views/amCheckout/utils';
911
import SeerAutomationAlert from 'getsentry/views/subscriptionPage/seerAutomationAlert';
1012

1113
import {SubscriptionCard} from './subscriptionCard';
@@ -20,20 +22,25 @@ export function HeaderCards({organization, subscription}: HeaderCardsProps) {
2022
return (
2123
<ErrorBoundary mini>
2224
<SeerAutomationAlert organization={organization} />
23-
<HeaderCardWrapper>
25+
<HeaderCardWrapper hasNewCheckout={hasCheckoutV3(organization)}>
2426
<SubscriptionCard organization={organization} subscription={subscription} />
2527
<UsageCard organization={organization} subscription={subscription} />
2628
</HeaderCardWrapper>
2729
</ErrorBoundary>
2830
);
2931
}
3032

31-
const HeaderCardWrapper = styled(Panel)`
33+
// TODO(checkout v3): update this with the real layout
34+
const HeaderCardWrapper = styled(Panel)<{hasNewCheckout: boolean}>`
3235
display: grid;
3336
margin-bottom: ${space(2)};
3437
35-
@media (min-width: ${p => p.theme.breakpoints.lg}) {
36-
grid-template-columns: auto minmax(0, 600px);
37-
gap: ${space(2)};
38-
}
38+
${p =>
39+
!p.hasNewCheckout &&
40+
css`
41+
@media (min-width: ${p.theme.breakpoints.lg}) {
42+
grid-template-columns: auto minmax(0, 600px);
43+
gap: ${space(2)};
44+
}
45+
`}
3946
`;

0 commit comments

Comments
 (0)