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 => , {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 => , {modalCss, onClose});
}
export async function openForcedTrialModal(options: TrialModalProps) {
const {default: Modal, modalCss} = await import(
'getsentry/components/forcedTrialModal'
);
const onClose = genTrialModalOnClose(options, 'forcedTrial');
openModal(deps => , {
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 => , {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 => );
}
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 => );
}
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 => , {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 => , {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 => , {modalCss});
}
type PromotionModalOptions = {
organization: Organization;
price: number;
promotion: Promotion;
promptFeature: string;
PromotionModalBody?: ComponentType;
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 => , {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: (
{reminderText}
{t('Current Promotion:')}
{percentOff}% off (up to ${maxCentsPerPeriod / 100} per {intervalSingular}) for{' '}
{billingPeriods} {interval} starting on {date.toLocaleDateString('en-US')}