Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions static/gsApp/components/billingDetails/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {useLocation} from 'sentry/utils/useLocation';
import LegacyBillingDetailsForm from 'getsentry/components/billingDetails/legacyForm';
import StripeWrapper from 'getsentry/components/stripeWrapper';
import type {BillingDetails} from 'getsentry/types';
import {hasNewBillingUI, hasStripeComponentsFeature} from 'getsentry/utils/billing';
import {hasStripeComponentsFeature} from 'getsentry/utils/billing';
import {countryCodes} from 'getsentry/utils/ISO3166codes';
import type {TaxFieldInfo} from 'getsentry/utils/salesTax';
import {
Expand Down Expand Up @@ -167,7 +167,6 @@ function BillingDetailsForm({
!!initialData?.taxNumber || countryHasSalesTax(initialData?.countryCode),
});
const hasStripeComponents = hasStripeComponentsFeature(organization);
const isNewBillingUI = hasNewBillingUI(organization);
const location = useLocation();

const taxFieldInfo = useMemo(
Expand Down Expand Up @@ -228,7 +227,6 @@ function BillingDetailsForm({
if (analyticsEvent) {
trackGetsentryAnalytics(analyticsEvent, {
organization,
isNewBillingUI,
isStripeComponent: hasStripeComponents,
referrer: decodeScalar(location.query?.referrer),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ import {decodeScalar} from 'sentry/utils/queryString';
import InnerIntentForm from 'getsentry/components/creditCardEdit/intentForms/innerIntentForm';
import type {StripeIntentFormProps} from 'getsentry/components/creditCardEdit/intentForms/types';
import {usePaymentIntentData} from 'getsentry/hooks/useIntentData';
import {hasNewBillingUI} from 'getsentry/utils/billing';
import trackGetsentryAnalytics from 'getsentry/utils/trackGetsentryAnalytics';

function StripePaymentIntentForm(props: StripeIntentFormProps) {
const {organization, referrer, onSuccess} = props;
const isNewBillingUI = hasNewBillingUI(organization);
const [errorMessage, setErrorMessage] = useState<string | undefined>(undefined);
const [isSubmitting, setIsSubmitting] = useState(false);

Expand Down Expand Up @@ -76,7 +74,6 @@ function StripePaymentIntentForm(props: StripeIntentFormProps) {
organization,
referrer: decodeScalar(referrer),
isStripeComponent: true,
isNewBillingUI,
});
addSuccessMessage(t('Payment sent successfully.'));
onSuccess?.();
Expand Down
41 changes: 39 additions & 2 deletions static/gsApp/components/subscriptionSettingsLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import styled from '@emotion/styled';

import {Button} from '@sentry/scraps/button';

import {Flex} from 'sentry/components/core/layout';
import {IconMegaphone} from 'sentry/icons';
import {t} from 'sentry/locale';
import {useFeedbackForm} from 'sentry/utils/useFeedbackForm';
import {useLocation} from 'sentry/utils/useLocation';
import useOrganization from 'sentry/utils/useOrganization';
import {useParams} from 'sentry/utils/useParams';
import useRouter from 'sentry/utils/useRouter';
import {useRoutes} from 'sentry/utils/useRoutes';
import SettingsBreadcrumb from 'sentry/views/settings/components/settingsBreadcrumb';
import type {RouteWithName} from 'sentry/views/settings/components/settingsBreadcrumb/types';
import SettingsHeader from 'sentry/views/settings/components/settingsHeader';
import SettingsSearch from 'sentry/views/settings/components/settingsSearch';
import OrganizationSettingsLayout from 'sentry/views/settings/organization/organizationSettingsLayout';
Expand All @@ -20,13 +26,21 @@ type Props = {
function SubscriptionSettingsLayout(props: Props) {
const organization = useOrganization();
const isNewBillingUI = hasNewBillingUI(organization);
const openFeedbackForm = useFeedbackForm();

const location = useLocation();
const params = useParams();
const routes = useRoutes();
const router = useRouter();
const {children} = props;

let feedbackSource = location.pathname;
for (let i = routes.length - 1; i >= 0; i--) {
const route = routes[i] as RouteWithName;
if (route?.name) {
feedbackSource = route.name;
break;
}
}
Comment on lines +37 to +43
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the route name we desire for feedbackSource is always the last route in routes with a name

if (!isNewBillingUI) {
return (
<OrganizationSettingsLayout
Expand All @@ -46,7 +60,30 @@ function SubscriptionSettingsLayout(props: Props) {
<StyledSettingsHeader>
<Flex align="center" justify="between">
<StyledSettingsBreadcrumb params={params} routes={routes} />
<SettingsSearch />
<Flex align="center" gap="xl">
{openFeedbackForm ? (
<Button
size="sm"
icon={<IconMegaphone />}
onClick={() => {
openFeedbackForm({
formTitle: t('Give feedback'),
messagePlaceholder: t(
'How can we make the %s page better for you?',
feedbackSource
),
tags: {
['feedback.source']: feedbackSource,
['feedback.owner']: 'billing',
},
});
}}
>
{t('Give feedback')}
</Button>
) : null}
<SettingsSearch />
</Flex>
</Flex>
</StyledSettingsHeader>
<Flex minWidth={0} flex="1" direction="column">
Expand Down
8 changes: 8 additions & 0 deletions static/gsApp/utils/rawTrackAnalyticsEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import localStorage from 'sentry/utils/localStorage';
import sessionStorage from 'sentry/utils/sessionStorage';

import type {Subscription} from 'getsentry/types';
import {hasNewBillingUI} from 'getsentry/utils/billing';
import {GETSENTRY_EVENT_MAP} from 'getsentry/utils/trackGetsentryAnalytics';
import {hasNewCheckout} from 'getsentry/views/amCheckout/utils';

import trackAmplitudeEvent from './trackAmplitudeEvent';
import trackMarketingEvent from './trackMarketingEvent';
Expand Down Expand Up @@ -179,6 +182,11 @@ export default function rawTrackAnalyticsEvent(
// pass in properties if we have the full organization
if (isFullOrganization(organization)) {
data.role = organization.orgRole;

if (eventKey in GETSENTRY_EVENT_MAP) {
data.isNewCheckout = hasNewCheckout(organization);
data.isNewBillingUI = hasNewBillingUI(organization);
}
}

// add in plan information
Expand Down
71 changes: 42 additions & 29 deletions static/gsApp/utils/trackGetsentryAnalytics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ type AddEventCTA = HasSub & {
source: string;
event_types?: string;
};
type CheckoutUI = {
isNewCheckout: boolean;
};
type BillingInfoUpdateEvent = {
isNewBillingUI: boolean;
isStripeComponent: boolean;
referrer?: string;
};
Expand All @@ -51,7 +47,7 @@ export type ProductUnavailableUpsellAlert = {

type GetsentryEventParameters = {
'add_event_cta.clicked_cta': AddEventCTA;
'am_checkout.viewed': HasSub & CheckoutUI;
'am_checkout.viewed': HasSub;
'billing_details.updated_billing_details': BillingInfoUpdateEvent;
'billing_details.updated_cc': BillingInfoUpdateEvent;
'billing_failure.button_clicked': {
Expand Down Expand Up @@ -80,16 +76,15 @@ type GetsentryEventParameters = {
'checkout.change_contract': Checkout;
'checkout.change_plan': Checkout;
'checkout.click_continue': {step_number: number; step_id?: string} & Checkout;
'checkout.data_slider_changed': {data_type: string; quantity: number} & CheckoutUI;
'checkout.data_slider_changed': {data_type: string; quantity: number};
// no sub here;
'checkout.data_sliders_viewed': Record<PropertyKey, unknown> & CheckoutUI;
'checkout.data_sliders_viewed': Record<PropertyKey, unknown>;
// only used for checkout v3
'checkout.exit': HasSub;
'checkout.ondemand_budget.turned_off': Record<PropertyKey, unknown> & CheckoutUI;
'checkout.ondemand_budget.update': OnDemandBudgetUpdate & CheckoutUI;
'checkout.ondemand_budget.turned_off': Record<PropertyKey, unknown>;
'checkout.ondemand_budget.update': OnDemandBudgetUpdate;
'checkout.ondemand_changed': {cents: number} & Checkout;
'checkout.payg_changed': {cents: number; method?: 'button' | 'textbox'} & Checkout &
CheckoutUI;
'checkout.payg_changed': {cents: number; method?: 'button' | 'textbox'} & Checkout;
'checkout.product_select': Partial<
Record<
AddOnCategory,
Expand All @@ -99,8 +94,7 @@ type GetsentryEventParameters = {
}
>
> &
HasSub &
CheckoutUI;
HasSub;
'checkout.transactions_upgrade': {
previous_transactions: number;
transactions: number;
Expand All @@ -110,8 +104,7 @@ type GetsentryEventParameters = {
// no sub here
'checkout.upgrade': Partial<
Record<DataCategory | `previous_${DataCategory}`, number | undefined>
> & {previous_plan: string} & Checkout &
CheckoutUI;
> & {previous_plan: string} & Checkout;
'data_consent_modal.learn_more': Record<PropertyKey, unknown>;
'data_consent_priority.viewed': Record<PropertyKey, unknown>;
'data_consent_settings.updated': {setting: string; value: FieldValue};
Expand Down Expand Up @@ -165,13 +158,14 @@ type GetsentryEventParameters = {
applyNow: boolean;
daysLeft: number;
partner: undefined | string;
} & HasSub &
CheckoutUI;
} & HasSub;
'partner_billing_migration.modal.clicked_cta': {
daysLeft: number;
partner: undefined | string;
} & HasSub;
'past_due_modal.seen': HasSub;
'payg_inline_form.ondemand_budget.turned_off': Record<PropertyKey, unknown>;
'payg_inline_form.ondemand_budget.update': OnDemandBudgetUpdate;
'performance.quota_exceeded_alert.displayed': {
referrer: string;
traceItemDataset: string;
Expand All @@ -196,17 +190,26 @@ type GetsentryEventParameters = {
'replay.list_page.viewed': UpdateProps;
'sales.contact_us_clicked': {
source: string;
} & HasSub &
CheckoutUI;
} & HasSub;
'spend_allocations.open_form': {create_or_edit: string} & HasSub;
'spend_allocations.submit': {create_or_edit: string} & HasSub;
'subscription_page.display_mode.changed': {
display_mode: 'usage' | 'cost';
} & HasSub;
'subscription_page.usagelog_filter.clicked': {selection: string};
'subscription_page.viewed': {
page_tab: string;
'subscription_page.download_reports.clicked': {
reportType: 'summary' | 'project_breakdown';
};
'subscription_page.usage_overview.add_on_toggled': {
addOnCategory: AddOnCategory;
isOpen: boolean;
} & HasSub;
'subscription_page.usage_overview.row_clicked': {
dataCategory: DataCategory;
} & HasSub;
'subscription_page.usage_overview.transform_changed': {
transform: string;
} & HasSub;
'subscription_page.usagelog_filter.clicked': {selection: string};
'trial_ended_notice.dismissed_understood': HasSub;
'trial_reset_notification.modal_dismissed': HasSub;
'upgrade_now.alert.dismiss': UpdateProps;
Expand Down Expand Up @@ -240,7 +243,7 @@ type UpdateProps = Pick<Subscription, 'planTier' | 'canSelfServe' | 'channel'> &

export type GetsentryEventKey = keyof GetsentryEventParameters;

const getsentryEventMap: Record<GetsentryEventKey, string> = {
export const GETSENTRY_EVENT_MAP: Record<GetsentryEventKey, string> = {
'power_icon.clicked': 'Clicked Power Icon',
'github.multi_org.upsell': 'Github Multi-Org Upsell Clicked',
'growth.clicked_enter_sandbox': 'Growth: Clicked Enter Sandbox',
Expand Down Expand Up @@ -306,16 +309,20 @@ const getsentryEventMap: Record<GetsentryEventKey, string> = {
'billing_failure.updated_cc': 'Billing Failure: Updated CC',
'add_event_cta.clicked_cta': 'Add Event CTA: Clicked CTA',
'subscription_page.usagelog_filter.clicked': 'Usage Log Filter: Clicked',
'subscription_page.viewed': 'Subscription Page: Viewed',
'subscription_page.download_reports.clicked':
'Subscription Page: Download Reports Clicked',
'sales.contact_us_clicked': 'Clicked Contact Sales',
'disabled_member_view.loaded': 'Disabled Member View: Loaded',
'disabled_member_view.clicked_upgrade_request':
'Disabled Member View: Clicked Upgrade Request',
'disabled_member_view.clicked_leave_org': 'Disabled Member View: Clicked Leave Org',
'ondemand_budget_modal.ondemand_budget.turned_off': 'Disabled On-demand Budget',
'ondemand_budget_modal.ondemand_budget.update': 'Update On-demand Budget',
'checkout.ondemand_budget.turned_off': 'Checkout: Disabled On-demand Budget',
'checkout.ondemand_budget.update': 'Checkout: Update On-demand Budget',
'ondemand_budget_modal.ondemand_budget.turned_off': 'Disabled PAYG Budget',
'ondemand_budget_modal.ondemand_budget.update': 'Update PAYG Budget',
'payg_inline_form.ondemand_budget.turned_off':
'PAYG In-line Form: Disabled PAYG Budget',
'payg_inline_form.ondemand_budget.update': 'PAYG In-line Form: Update PAYG Budget',
'checkout.ondemand_budget.turned_off': 'Checkout: Disabled PAYG Budget',
'checkout.ondemand_budget.update': 'Checkout: Update PAYG Budget',
'trial_reset_notification.modal_dismissed': 'Trial Reset Notification: Modal Dismissed',
'growth.disabled_dashboard.viewed': 'Growth: Disabled Dashboard Viewed',
'product_unavailable_upsell_alert.viewed': 'Product Unavailable Upsell: Viewed Alert',
Expand Down Expand Up @@ -352,11 +359,17 @@ const getsentryEventMap: Record<GetsentryEventKey, string> = {
'gen_ai_consent.in_drawer_clicked': 'Gen AI Consent: Clicked In Drawer',
'gen_ai_consent.view_in_settings_clicked': 'Gen AI Consent: View in Settings Clicked',
'subscription_page.display_mode.changed': 'Subscription Page: Display Mode Changed',
'subscription_page.usage_overview.row_clicked':
'Subscription Page: Usage Overview Row Clicked',
'subscription_page.usage_overview.transform_changed':
'Subscription Page: Usage Overview Transform Changed',
'subscription_page.usage_overview.add_on_toggled':
'Subscription Page: Usage Overview Add On Toggled',
};

const trackGetsentryAnalytics = makeAnalyticsFunction<
GetsentryEventParameters,
{organization: Organization}
>(getsentryEventMap);
>(GETSENTRY_EVENT_MAP);

export default trackGetsentryAnalytics;
3 changes: 1 addition & 2 deletions static/gsApp/views/amCheckout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ class AMCheckout extends Component<Props, State> {
state: State;

componentDidMount() {
const {subscription, organization, isNewCheckout} = this.props;
const {subscription, organization} = this.props;
/**
* Preload Stripe so it's ready when the subscription + cc form becomes
* available. `loadStripe` ensures Stripe is not loaded multiple times
Expand All @@ -213,7 +213,6 @@ class AMCheckout extends Component<Props, State> {
trackGetsentryAnalytics('am_checkout.viewed', {
organization,
subscription,
isNewCheckout: !!isNewCheckout,
});
}
Sentry.getReplay()?.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ function ReserveAdditionalVolume({
organization,
data_type: category,
quantity: value,
isNewCheckout: true,
});
}
},
Expand Down
1 change: 0 additions & 1 deletion static/gsApp/views/amCheckout/steps/planSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@ function PlanSelect({
organization,
subscription,
source: 'checkout.plan_select',
isNewCheckout: false,
});
}}
/>
Expand Down
Loading
Loading