123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- import type {ComponentType} from 'react';
- import styled from '@emotion/styled';
- import type {Location} from 'history';
- import {openModal} from 'sentry/actionCreators/modal';
- import {promptsUpdate} from 'sentry/actionCreators/prompts';
- import {Client} from 'sentry/api';
- import {openConfirmModal} from 'sentry/components/confirm';
- import {t} from 'sentry/locale';
- import type {Organization} from 'sentry/types/organization';
- import type {PromotionModalBodyProps} from 'getsentry/components/promotionModal';
- import type {Reservations} from 'getsentry/components/upgradeNowModal/types';
- import SubscriptionStore from 'getsentry/stores/subscriptionStore';
- import type {
- Invoice,
- Plan,
- PreviewData,
- Promotion,
- PromotionClaimed,
- Subscription,
- } from 'getsentry/types';
- import type {AM2UpdateSurfaces} from 'getsentry/utils/trackGetsentryAnalytics';
- type UpsellModalOptions = {
- organization: Organization;
- source: string;
- defaultSelection?: string;
- };
- export async function openUpsellModal(options: UpsellModalOptions) {
- const {default: Modal, modalCss} = await import('getsentry/components/upsellModal');
- openModal(deps => <Modal {...deps} {...options} />, {modalCss});
- }
- type TrialModalProps = {
- organization: Organization;
- };
- type PartnerPlanModalProps = {
- organization: Organization;
- subscription: Subscription;
- };
- function genTrialModalOnClose(
- options: TrialModalProps,
- type: 'trialEnd' | 'forcedTrial'
- ) {
- let feature: string, subField: string;
- switch (type) {
- case 'trialEnd':
- feature = 'trial_ended_notice';
- subField = 'hasDismissedTrialEndingNotice';
- break;
- case 'forcedTrial':
- feature = 'forced_trial_notice';
- subField = 'hasDismissedForcedTrialNotice';
- break;
- default:
- throw new Error('Unexpected type');
- }
- const api = new Client();
- const promptParams = {
- organization: options.organization,
- feature,
- status: 'dismissed',
- } as const;
- const subUpdate = {
- [subField]: true,
- } as const;
- // Handle marking the feature prompt as seen when the modal is
- // closed
- return () => {
- promptsUpdate(api, promptParams);
- SubscriptionStore.set(options.organization.slug, subUpdate);
- };
- }
- export async function openTrialEndingModal(options: TrialModalProps) {
- const {default: Modal, modalCss} = await import(
- 'getsentry/components/trialEndingModal'
- );
- const onClose = genTrialModalOnClose(options, 'trialEnd');
- openModal(deps => <Modal {...deps} {...options} />, {modalCss, onClose});
- }
- export async function openForcedTrialModal(options: TrialModalProps) {
- const {default: Modal, modalCss} = await import(
- 'getsentry/components/forcedTrialModal'
- );
- const onClose = genTrialModalOnClose(options, 'forcedTrial');
- openModal(deps => <Modal {...deps} {...options} />, {
- modalCss,
- onClose,
- });
- }
- export async function openPartnerPlanEndingModal(options: PartnerPlanModalProps) {
- const {default: Modal, modalCss} = await import(
- 'getsentry/components/partnerPlanEndingModal'
- );
- const api = new Client();
- const promptParams = {
- organization: options.organization,
- feature: 'partner_plan_ending_modal',
- status: 'dismissed',
- } as const;
- const onClose = () => {
- promptsUpdate(api, promptParams);
- };
- openModal(deps => <Modal {...deps} {...options} />, {modalCss, onClose});
- }
- type EditCreditCardOptions = {
- onSuccess: (data: Subscription) => void;
- organization: Organization;
- location?: Location;
- };
- export async function openEditCreditCard(options: EditCreditCardOptions) {
- const {default: Modal} = await import('getsentry/components/creditCardEditModal');
- openModal(deps => <Modal {...deps} {...options} />);
- }
- type OpenInvoicePaymentOptions = {
- invoice: Invoice;
- organization: Organization;
- reloadInvoice: () => void;
- };
- export async function openInvoicePaymentModal(options: OpenInvoicePaymentOptions) {
- const {default: Modal} = await import('getsentry/views/invoiceDetails/paymentForm');
- openModal(deps => <Modal {...deps} {...options} />);
- }
- type UpsellModalProps = {
- organization: Organization;
- plan: Plan;
- previewData: PreviewData;
- reservations: Reservations;
- subscription: Subscription;
- surface: AM2UpdateSurfaces;
- isActionDisabled?: boolean;
- onComplete?: () => void;
- };
- export async function openAM2UpsellModal(options: UpsellModalProps) {
- const {default: Modal, modalCss} = await import(
- 'getsentry/components/upgradeNowModal/index'
- );
- openModal(deps => <Modal {...deps} {...options} />, {modalCss});
- }
- export type UpsellModalSamePriceProps = {
- organization: Organization;
- plan: Plan;
- previewData: PreviewData;
- reservations: Reservations;
- subscription: Subscription;
- surface: AM2UpdateSurfaces;
- onComplete?: () => void;
- };
- export async function openAM2UpsellModalSamePrice(options: UpsellModalSamePriceProps) {
- const {default: Modal, modalCss} = await import(
- 'getsentry/components/upgradeNowModal/modalSamePrice'
- );
- openModal(deps => <Modal {...deps} {...options} />, {modalCss});
- }
- type ProfilingUpsellModalProps = {
- organization: Organization;
- subscription: Subscription;
- isActionDisabled?: boolean;
- onComplete?: () => void;
- };
- export async function openAM2ProfilingUpsellModal(options: ProfilingUpsellModalProps) {
- const {default: Modal, modalCss} = await import(
- 'getsentry/components/profiling/profilingUpgradeModal'
- );
- openModal(deps => <Modal {...deps} {...options} />, {modalCss});
- }
- type PromotionModalOptions = {
- organization: Organization;
- price: number;
- promotion: Promotion;
- promptFeature: string;
- PromotionModalBody?: ComponentType<PromotionModalBodyProps>;
- acceptButtonText?: string;
- api?: Client;
- declineButtonText?: string;
- onAccept?: () => void;
- };
- export async function openPromotionModal(options: PromotionModalOptions) {
- const {default: Modal, modalCss} = await import('getsentry/components/promotionModal');
- openModal(deps => <Modal {...deps} {...options} />, {closeEvents: 'none', modalCss});
- }
- export function openPromotionReminderModal(
- promotionClaimed: PromotionClaimed,
- onCancel?: () => void,
- onConfirm?: () => void
- ) {
- const {dateCompleted} = promotionClaimed;
- const promo = promotionClaimed.promotion;
- const {amount, billingInterval, billingPeriods, maxCentsPerPeriod, reminderText} =
- promo.discountInfo;
- const date = new Date(dateCompleted);
- const percentOff = amount / 100;
- const interval = billingInterval === 'monthly' ? t('months') : t('years');
- const intervalSingular = interval.slice(0, -1);
- /**
- * Removed translation because of complicated pluralization and lots of changing
- * parameters from the different promotions we can use this for
- */
- openConfirmModal({
- message: (
- <div>
- <p>{reminderText}</p>
- <Subheader>{t('Current Promotion:')} </Subheader>
- <p>
- {percentOff}% off (up to ${maxCentsPerPeriod / 100} per {intervalSingular}) for{' '}
- {billingPeriods} {interval} starting on {date.toLocaleDateString('en-US')}
- </p>
- </div>
- ),
- header: <HeaderText>Promotion Conflict</HeaderText>,
- priority: 'danger',
- confirmText: 'Downgrade Anyway',
- onCancel: () => onCancel?.(),
- onConfirm: () => onConfirm?.(),
- });
- }
- export async function openCodecovModal(options: {organization: Organization}) {
- const {default: Modal, modalCss} = await import(
- 'getsentry/components/codecovPromotionModal'
- );
- openModal(deps => <Modal {...deps} {...options} />, {modalCss, closeEvents: 'none'});
- }
- const HeaderText = styled('div')`
- font-size: ${p => p.theme.fontSizeExtraLarge};
- font-weight: bold;
- `;
- const Subheader = styled('div')`
- font-weight: bold;
- font-size: ${p => p.theme.fontSizeMedium};
- `;
- export async function openDataConsentModal() {
- const {default: Modal} = await import('getsentry/components/dataConsentModal');
- openModal(deps => <Modal {...deps} />);
- }
|