import {useCallback, useEffect, useMemo, useState} from 'react';
import styled from '@emotion/styled';
import {Button, LinkButton} from 'sentry/components/button';
import {Alert} from 'sentry/components/core/alert';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Organization} from 'sentry/types/organization';
import useApi from 'sentry/utils/useApi';
import {
sendReplayOnboardRequest,
sendUpgradeRequest,
} from 'getsentry/actionCreators/upsell';
import withSubscription from 'getsentry/components/withSubscription';
import {useAM2UpsellModal} from 'getsentry/hooks/useAM2UpsellModal';
import type {Subscription} from 'getsentry/types';
import {PlanTier} from 'getsentry/types';
import type {ProductUnavailableUpsellAlert} from 'getsentry/utils/trackGetsentryAnalytics';
import trackGetsentryAnalytics from 'getsentry/utils/trackGetsentryAnalytics';
function getUpdatePlanLabel({
hasSessionReplay,
hasPerformanceView,
}: {
hasPerformanceView: boolean;
hasSessionReplay: boolean;
}) {
if (!hasSessionReplay && !hasPerformanceView) {
return t(
'Update your organization to the latest version of its plan to use Performance and Session Replay.'
);
}
if (!hasSessionReplay) {
return t(
'Update your organization to the latest version of its plan to use Session Replay.'
);
}
return t(
'Update your organization to the latest version of its plan to use Performance.'
);
}
function getRequestUpdateLabel({
hasSessionReplay,
hasPerformanceView,
}: {
hasPerformanceView: boolean;
hasSessionReplay: boolean;
}) {
if (!hasSessionReplay && !hasPerformanceView) {
return t(
'To use Performance and Session Replay, request an owner in your organization to update its plan to the latest version.'
);
}
if (!hasSessionReplay) {
return t(
'To use Session Replay, request an owner in your organization to update its plan to the latest version.'
);
}
return t(
'To use Performance, request an owner in your organization to update its plan to the latest version.'
);
}
function RequestUpdateAlert({
children,
organization,
isAncientPlan,
hasPerformanceView,
hasSessionReplay,
}: {
children: React.ReactNode;
hasPerformanceView: boolean;
hasSessionReplay: boolean;
isAncientPlan: boolean;
organization: Organization;
}) {
const api = useApi();
const [loading, setLoading] = useState(false);
const [requestSent, setRequestSent] = useState(false);
const analyticsCommonProps: ProductUnavailableUpsellAlert & {
organization: Organization;
} = useMemo(
() => ({
organization,
has_performance: hasPerformanceView,
has_session_replay: hasSessionReplay,
action: 'request_update',
}),
[organization, hasPerformanceView, hasSessionReplay]
);
useEffect(() => {
trackGetsentryAnalytics(
'product_unavailable_upsell_alert.viewed',
analyticsCommonProps
);
}, [analyticsCommonProps]);
const handleClick = useCallback(async () => {
setLoading(true);
trackGetsentryAnalytics(
'product_unavailable_upsell_alert_button.clicked',
analyticsCommonProps
);
if (isAncientPlan) {
await sendUpgradeRequest({
api,
organization,
handleSuccess: () => setRequestSent(true),
});
} else {
await sendReplayOnboardRequest({
api,
orgSlug: organization.slug,
currentPlan: 'am1-non-beta',
onSuccess: () => setRequestSent(true),
});
}
setLoading(false);
}, [api, isAncientPlan, organization, analyticsCommonProps]);
return (
{t('Request Update')}
}
>
{children}
);
}
function UpdatePlanAlert({
children,
organization,
subscription,
isAncientPlan,
canSelfServe,
hasPerformanceView,
hasSessionReplay,
}: {
canSelfServe: boolean;
children: React.ReactNode;
hasPerformanceView: boolean;
hasSessionReplay: boolean;
isAncientPlan: boolean;
organization: Organization;
subscription: Subscription;
}) {
const am2UpsellModal = useAM2UpsellModal({
subscription,
surface: 'replay_project_creation',
onComplete: () => {
window.location.reload();
},
});
const analyticsCommonProps: ProductUnavailableUpsellAlert & {
organization: Organization;
} = useMemo(
() => ({
organization,
has_performance: hasPerformanceView,
has_session_replay: hasSessionReplay,
action: isAncientPlan || !canSelfServe ? 'manage_subscription' : 'update_plan',
}),
[organization, hasPerformanceView, hasSessionReplay, isAncientPlan, canSelfServe]
);
useEffect(() => {
trackGetsentryAnalytics(
'product_unavailable_upsell_alert.viewed',
analyticsCommonProps
);
}, [analyticsCommonProps]);
const handleClick = useCallback(() => {
trackGetsentryAnalytics(
'product_unavailable_upsell_alert_button.clicked',
analyticsCommonProps
);
if (isAncientPlan || !canSelfServe) {
return;
}
am2UpsellModal.showModal();
}, [analyticsCommonProps, canSelfServe, isAncientPlan, am2UpsellModal]);
return (
{t('Manage Subscription')}
) : (
)
}
>
{children}
);
}
function ProductUnavailableCTAContainer({
organization,
subscription,
}: {
organization: Organization;
subscription: Subscription;
}) {
const hasSessionReplay = organization.features.includes('session-replay');
const hasPerformanceView = organization.features.includes('performance-view');
if (hasSessionReplay && hasPerformanceView) {
return null;
}
// MM1 & MM2 plans have no direct update path into AM2, prices could be wildly different
// Members can email owners requesting a plan upgrade and owners can manage subscription
const isAncientPlan = [PlanTier.MM1, PlanTier.MM2].includes(
subscription.planTier as PlanTier
);
const hasBillingAccess = organization.access?.includes('org:billing');
const canSelfServe = subscription.canSelfServe;
return hasBillingAccess ? (
{getUpdatePlanLabel({hasSessionReplay, hasPerformanceView})}
) : (
{getRequestUpdateLabel({hasSessionReplay, hasPerformanceView})}
);
}
export const ProductUnavailableCTA = withSubscription(ProductUnavailableCTAContainer, {
noLoader: true,
});
const AlertWithCustomMargin = styled(Alert)`
margin: -${space(3)} -${space(4)} ${space(2)} -${space(4)};
`;