// NOTE@eamodio This file is referenced in the webviews to we can't use anything vscode or other imports that aren't available in the webviews import { getDateDifference } from './system/date'; export const enum SubscriptionPlanId { Free = 'free', FreePlus = 'free+', Pro = 'pro', Teams = 'teams', Enterprise = 'enterprise', } export type FreeSubscriptionPlans = Extract; export type PaidSubscriptionPlans = Exclude; export type RequiredSubscriptionPlans = Exclude; export interface Subscription { readonly plan: { readonly actual: SubscriptionPlan; readonly effective: SubscriptionPlan; }; account: SubscriptionAccount | undefined; previewTrial?: SubscriptionPreviewTrial; state: SubscriptionState; } export interface SubscriptionPlan { readonly id: SubscriptionPlanId; readonly name: string; readonly bundle: boolean; readonly cancelled: boolean; readonly startedOn: string; readonly expiresOn?: string | undefined; readonly organizationId: string | undefined; } export interface SubscriptionAccount { readonly id: string; readonly name: string; readonly email: string | undefined; readonly verified: boolean; readonly createdOn: string; readonly organizationIds: string[]; } export interface SubscriptionPreviewTrial { readonly startedOn: string; readonly expiresOn: string; } export const enum SubscriptionState { /** Indicates a user who hasn't verified their email address yet */ VerificationRequired = -1, /** Indicates a Free user who hasn't yet started the preview trial */ Free = 0, /** Indicates a Free user who is in preview trial */ FreeInPreviewTrial, /** Indicates a Free user who's preview has expired trial */ FreePreviewTrialExpired, /** Indicates a Free+ user with a completed trial */ FreePlusInTrial, /** Indicates a Free+ user who's trial has expired */ FreePlusTrialExpired, /** Indicates a Paid user */ Paid, } export function computeSubscriptionState(subscription: Optional): SubscriptionState { const { account, plan: { actual, effective }, previewTrial: preview, } = subscription; if (account?.verified === false) return SubscriptionState.VerificationRequired; if (actual.id === effective.id) { switch (effective.id) { case SubscriptionPlanId.Free: return preview == null ? SubscriptionState.Free : SubscriptionState.FreePreviewTrialExpired; case SubscriptionPlanId.FreePlus: return SubscriptionState.FreePlusTrialExpired; case SubscriptionPlanId.Pro: case SubscriptionPlanId.Teams: case SubscriptionPlanId.Enterprise: return SubscriptionState.Paid; } } switch (effective.id) { case SubscriptionPlanId.Free: return preview == null ? SubscriptionState.Free : SubscriptionState.FreeInPreviewTrial; case SubscriptionPlanId.FreePlus: return SubscriptionState.FreePlusTrialExpired; case SubscriptionPlanId.Pro: return actual.id === SubscriptionPlanId.Free ? SubscriptionState.FreeInPreviewTrial : SubscriptionState.FreePlusInTrial; case SubscriptionPlanId.Teams: case SubscriptionPlanId.Enterprise: return SubscriptionState.Paid; } } export function getSubscriptionPlan( id: SubscriptionPlanId, bundle: boolean, organizationId: string | undefined, startedOn?: Date, expiresOn?: Date, cancelled: boolean = false, ): SubscriptionPlan { return { id: id, name: getSubscriptionPlanName(id), bundle: bundle, cancelled: cancelled, organizationId: organizationId, startedOn: (startedOn ?? new Date()).toISOString(), expiresOn: expiresOn != null ? expiresOn.toISOString() : undefined, }; } export function getSubscriptionPlanName(id: SubscriptionPlanId) { switch (id) { case SubscriptionPlanId.FreePlus: return 'GitLens Free'; case SubscriptionPlanId.Pro: return 'GitLens Pro'; case SubscriptionPlanId.Teams: return 'GitLens Teams'; case SubscriptionPlanId.Enterprise: return 'GitLens Enterprise'; case SubscriptionPlanId.Free: default: return 'GitLens'; } } const plansPriority = new Map([ [undefined, -1], [SubscriptionPlanId.Free, 0], [SubscriptionPlanId.FreePlus, 1], [SubscriptionPlanId.Pro, 2], [SubscriptionPlanId.Teams, 3], [SubscriptionPlanId.Enterprise, 4], ]); export function getSubscriptionPlanPriority(id: SubscriptionPlanId | undefined): number { return plansPriority.get(id) ?? -1; } export function getSubscriptionTimeRemaining( subscription: Optional, unit?: 'days' | 'hours' | 'minutes' | 'seconds', ): number | undefined { return getTimeRemaining(subscription.plan.effective.expiresOn, unit); } export function getTimeRemaining( expiresOn: string | undefined, unit?: 'days' | 'hours' | 'minutes' | 'seconds', ): number | undefined { return expiresOn != null ? getDateDifference(Date.now(), new Date(expiresOn), unit) : undefined; } export function isSubscriptionPaid(subscription: Optional): boolean { return isSubscriptionPaidPlan(subscription.plan.effective.id); } export function isSubscriptionPaidPlan(id: SubscriptionPlanId): id is PaidSubscriptionPlans { return id !== SubscriptionPlanId.Free && id !== SubscriptionPlanId.FreePlus; } export function isSubscriptionExpired(subscription: Optional): boolean { const remaining = getSubscriptionTimeRemaining(subscription); return remaining != null && remaining <= 0; } export function isSubscriptionTrial(subscription: Optional): boolean { return subscription.plan.actual.id !== subscription.plan.effective.id; } export function isSubscriptionPreviewTrialExpired(subscription: Optional): boolean | undefined { const remaining = getTimeRemaining(subscription.previewTrial?.expiresOn); return remaining != null ? remaining <= 0 : undefined; }