bitwarden-estensione-browser/apps/web/src/app/billing/organizations/organization-subscription-s...

183 lines
6.5 KiB
TypeScript

import { Component, OnDestroy, OnInit } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { ActivatedRoute } from "@angular/router";
import { concatMap, firstValueFrom, Subject, takeUntil } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { OrganizationConnectionType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { OrganizationConnectionResponse } from "@bitwarden/common/admin-console/models/response/organization-connection.response";
import { BillingSyncConfigApi } from "@bitwarden/common/billing/models/api/billing-sync-config.api";
import { SelfHostedOrganizationSubscriptionView } from "@bitwarden/common/billing/models/view/self-hosted-organization-subscription.view";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService } from "@bitwarden/components";
import { BillingSyncKeyComponent } from "./billing-sync-key.component";
enum LicenseOptions {
SYNC = 0,
UPLOAD = 1,
}
@Component({
templateUrl: "organization-subscription-selfhost.component.html",
})
export class OrganizationSubscriptionSelfhostComponent implements OnInit, OnDestroy {
subscription: SelfHostedOrganizationSubscriptionView;
organizationId: string;
userOrg: Organization;
cloudWebVaultUrl: string;
licenseOptions = LicenseOptions;
form = new FormGroup({
updateMethod: new FormControl(LicenseOptions.UPLOAD),
});
disableLicenseSyncControl = false;
firstLoaded = false;
loading = false;
private _existingBillingSyncConnection: OrganizationConnectionResponse<BillingSyncConfigApi>;
private destroy$ = new Subject<void>();
set existingBillingSyncConnection(value: OrganizationConnectionResponse<BillingSyncConfigApi>) {
this._existingBillingSyncConnection = value;
this.form
.get("updateMethod")
.setValue(this.billingSyncEnabled ? LicenseOptions.SYNC : LicenseOptions.UPLOAD);
}
get existingBillingSyncConnection() {
return this._existingBillingSyncConnection;
}
get billingSyncEnabled() {
return this.existingBillingSyncConnection?.enabled;
}
/**
* Render the subscription as expired.
*/
get showAsExpired() {
return this.subscription.hasSeparateGracePeriod
? this.subscription.isExpiredWithoutGracePeriod
: this.subscription.isExpiredAndOutsideGracePeriod;
}
constructor(
private messagingService: MessagingService,
private apiService: ApiService,
private organizationService: OrganizationService,
private route: ActivatedRoute,
private organizationApiService: OrganizationApiServiceAbstraction,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private environmentService: EnvironmentService,
private dialogService: DialogService,
) {}
async ngOnInit() {
this.cloudWebVaultUrl = await firstValueFrom(this.environmentService.cloudWebVaultUrl$);
this.route.params
.pipe(
concatMap(async (params) => {
this.organizationId = params.organizationId;
await this.load();
await this.loadOrganizationConnection();
this.firstLoaded = true;
}),
takeUntil(this.destroy$),
)
.subscribe();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
async load() {
if (this.loading) {
return;
}
this.loading = true;
this.userOrg = await this.organizationService.get(this.organizationId);
if (this.userOrg.canViewSubscription) {
const subscriptionResponse = await this.organizationApiService.getSubscription(
this.organizationId,
);
this.subscription = new SelfHostedOrganizationSubscriptionView(subscriptionResponse);
}
this.loading = false;
}
async loadOrganizationConnection() {
if (!this.firstLoaded) {
const cloudCommunicationEnabled = await this.apiService.getCloudCommunicationsEnabled();
this.disableLicenseSyncControl = !cloudCommunicationEnabled;
}
if (this.disableLicenseSyncControl) {
return;
}
this.existingBillingSyncConnection = await this.apiService.getOrganizationConnection(
this.organizationId,
OrganizationConnectionType.CloudBillingSync,
BillingSyncConfigApi,
);
}
licenseUploaded() {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.load();
this.messagingService.send("updatedOrgLicense");
}
manageBillingSyncSelfHosted() {
BillingSyncKeyComponent.open(this.dialogService, {
entityId: this.organizationId,
existingConnectionId: this.existingBillingSyncConnection?.id,
billingSyncKey: this.existingBillingSyncConnection?.config?.billingSyncKey,
setParentConnection: (connection: OrganizationConnectionResponse<BillingSyncConfigApi>) => {
this.existingBillingSyncConnection = connection;
},
});
}
syncLicense = async () => {
this.form.get("updateMethod").setValue(LicenseOptions.SYNC);
await this.organizationApiService.selfHostedSyncLicense(this.organizationId);
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.load();
await this.loadOrganizationConnection();
this.messagingService.send("updatedOrgLicense");
this.platformUtilsService.showToast("success", null, this.i18nService.t("licenseSyncSuccess"));
};
get billingSyncSetUp() {
return this.existingBillingSyncConnection?.id != null;
}
get updateMethod() {
return this.form.get("updateMethod").value;
}
get lastLicenseSync() {
return this.existingBillingSyncConnection?.config?.lastLicenseSync;
}
}