import { Component, OnInit, } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ToasterService } from 'angular2-toaster'; import { Angulartics2 } from 'angulartics2'; import { OrganizationSubscriptionResponse } from 'jslib/models/response/organizationSubscriptionResponse'; import { ApiService } from 'jslib/abstractions/api.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { MessagingService } from 'jslib/abstractions/messaging.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { TokenService } from 'jslib/abstractions/token.service'; import { PlanType } from 'jslib/enums/planType'; @Component({ selector: 'app-org-subscription', templateUrl: 'organization-subscription.component.html', }) export class OrganizationSubscriptionComponent implements OnInit { loading = false; firstLoaded = false; organizationId: string; adjustSeatsAdd = true; showAdjustSeats = false; adjustStorageAdd = true; showAdjustStorage = false; showUpdateLicense = false; showDownloadLicense = false; showChangePlan = false; sub: OrganizationSubscriptionResponse; selfHosted = false; cancelPromise: Promise; reinstatePromise: Promise; constructor(private tokenService: TokenService, private apiService: ApiService, private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, private analytics: Angulartics2, private toasterService: ToasterService, private messagingService: MessagingService, private route: ActivatedRoute) { this.selfHosted = platformUtilsService.isSelfHost(); } async ngOnInit() { this.route.parent.parent.params.subscribe(async (params) => { this.organizationId = params.organizationId; await this.load(); this.firstLoaded = true; }); } async load() { if (this.loading) { return; } this.loading = true; this.sub = await this.apiService.getOrganizationSubscription(this.organizationId); this.loading = false; } async reinstate() { if (this.loading) { return; } const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('reinstateConfirmation'), this.i18nService.t('reinstateSubscription'), this.i18nService.t('yes'), this.i18nService.t('cancel')); if (!confirmed) { return; } try { this.reinstatePromise = this.apiService.postOrganizationReinstate(this.organizationId); await this.reinstatePromise; this.analytics.eventTrack.next({ action: 'Reinstated Plan' }); this.toasterService.popAsync('success', null, this.i18nService.t('reinstated')); this.load(); } catch { } } async cancel() { if (this.loading) { return; } const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('cancelConfirmation'), this.i18nService.t('cancelSubscription'), this.i18nService.t('yes'), this.i18nService.t('no'), 'warning'); if (!confirmed) { return; } try { this.cancelPromise = this.apiService.postOrganizationCancel(this.organizationId); await this.cancelPromise; this.analytics.eventTrack.next({ action: 'Canceled Plan' }); this.toasterService.popAsync('success', null, this.i18nService.t('canceledSubscription')); this.load(); } catch { } } async changePlan() { if (this.subscription == null && this.sub.planType === PlanType.Free) { this.showChangePlan = !this.showChangePlan; return; } const contactSupport = await this.platformUtilsService.showDialog(this.i18nService.t('changeBillingPlanDesc'), this.i18nService.t('changeBillingPlan'), this.i18nService.t('contactSupport'), this.i18nService.t('close')); if (contactSupport) { this.platformUtilsService.launchUri('https://bitwarden.com/contact'); } } closeChangePlan(changed: boolean) { this.showChangePlan = false; } downloadLicense() { this.showDownloadLicense = !this.showDownloadLicense; } closeDownloadLicense() { this.showDownloadLicense = false; } updateLicense() { if (this.loading) { return; } this.showUpdateLicense = true; } closeUpdateLicense(updated: boolean) { this.showUpdateLicense = false; if (updated) { this.load(); this.messagingService.send('updatedOrgLicense'); } } adjustSeats(add: boolean) { this.adjustSeatsAdd = add; this.showAdjustSeats = true; } closeSeats(load: boolean) { this.showAdjustSeats = false; if (load) { this.load(); } } adjustStorage(add: boolean) { this.adjustStorageAdd = add; this.showAdjustStorage = true; } closeStorage(load: boolean) { this.showAdjustStorage = false; if (load) { this.load(); } } get isExpired() { return this.sub != null && this.sub.expiration != null && new Date(this.sub.expiration) < new Date(); } get subscriptionMarkedForCancel() { return this.subscription != null && !this.subscription.cancelled && this.subscription.cancelAtEndDate; } get subscription() { return this.sub != null ? this.sub.subscription : null; } get nextInvoice() { return this.sub != null ? this.sub.upcomingInvoice : null; } get storagePercentage() { return this.sub != null && this.sub.maxStorageGb ? +(100 * (this.sub.storageGb / this.sub.maxStorageGb)).toFixed(2) : 0; } get storageProgressWidth() { return this.storagePercentage < 5 ? 5 : 0; } get billingInterval() { const monthly = this.sub.planType === PlanType.EnterpriseMonthly || this.sub.planType === PlanType.TeamsMonthly; return monthly ? 'month' : 'year'; } get storageGbPrice() { return this.billingInterval === 'month' ? 0.5 : 4; } get seatPrice() { switch (this.sub.planType) { case PlanType.EnterpriseMonthly: return 4; case PlanType.EnterpriseAnnually: return 36; case PlanType.TeamsMonthly: return 2.5; case PlanType.TeamsAnnually: return 24; default: return 0; } } get canAdjustSeats() { return this.sub.planType === PlanType.EnterpriseMonthly || this.sub.planType === PlanType.EnterpriseAnnually || this.sub.planType === PlanType.TeamsMonthly || this.sub.planType === PlanType.TeamsAnnually; } get canDownloadLicense() { return (this.sub.planType !== PlanType.Free && this.subscription == null) || (this.subscription != null && !this.subscription.cancelled); } }