+
+
{{ "passwordManagerPlanPrice" | i18n }}: {{ passwordManagerSubtotal | currency: "USD $" }}
@@ -405,8 +433,8 @@
{{ "estimatedTax" | i18n }}: {{ taxCharges | currency: "USD $" }}
-
-
+
+
{{ "total" | i18n }}: {{ total | currency: "USD $" }}/{{
selectedPlanInterval | i18n
}}
@@ -415,22 +443,29 @@
-
-
+
+
{{ "singleOrgBlockCreateMessage" | i18n }}
-
-
+
+
-
+
diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.ts b/apps/web/src/app/billing/organizations/organization-plans.component.ts
index 23d48d93be..992ee4f3a9 100644
--- a/apps/web/src/app/billing/organizations/organization-plans.component.ts
+++ b/apps/web/src/app/billing/organizations/organization-plans.component.ts
@@ -70,6 +70,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
@Input() showCancel = false;
@Input() acceptingSponsorship = false;
@Input() currentPlan: PlanResponse;
+ selectedFile: File;
@Input()
get product(): ProductType {
@@ -109,6 +110,10 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
secretsManagerSubscription = secretsManagerSubscribeFormFactory(this.formBuilder);
+ selfHostedForm = this.formBuilder.group({
+ file: [null, [Validators.required]],
+ });
+
formGroup = this.formBuilder.group({
name: [""],
billingEmail: ["", [Validators.email]],
@@ -527,72 +532,71 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
this.onCanceled.emit();
}
- async submit() {
+ setSelectedFile(event: Event) {
+ const fileInputEl =
event.target;
+ this.selectedFile = fileInputEl.files.length > 0 ? fileInputEl.files[0] : null;
+ }
+
+ submit = async () => {
if (this.singleOrgPolicyBlock) {
return;
}
+ const doSubmit = async (): Promise => {
+ let orgId: string = null;
+ if (this.createOrganization) {
+ const orgKey = await this.cryptoService.makeOrgKey();
+ const key = orgKey[0].encryptedString;
+ const collection = await this.cryptoService.encrypt(
+ this.i18nService.t("defaultCollection"),
+ orgKey[1],
+ );
+ const collectionCt = collection.encryptedString;
+ const orgKeys = await this.cryptoService.makeKeyPair(orgKey[1]);
- try {
- const doSubmit = async (): Promise => {
- let orgId: string = null;
- if (this.createOrganization) {
- const orgKey = await this.cryptoService.makeOrgKey();
- const key = orgKey[0].encryptedString;
- const collection = await this.cryptoService.encrypt(
- this.i18nService.t("defaultCollection"),
- orgKey[1],
- );
- const collectionCt = collection.encryptedString;
- const orgKeys = await this.cryptoService.makeKeyPair(orgKey[1]);
-
- if (this.selfHosted) {
- orgId = await this.createSelfHosted(key, collectionCt, orgKeys);
- } else {
- orgId = await this.createCloudHosted(key, collectionCt, orgKeys, orgKey[1]);
- }
-
- this.platformUtilsService.showToast(
- "success",
- this.i18nService.t("organizationCreated"),
- this.i18nService.t("organizationReadyToGo"),
- );
+ if (this.selfHosted) {
+ orgId = await this.createSelfHosted(key, collectionCt, orgKeys);
} else {
- orgId = await this.updateOrganization(orgId);
- this.platformUtilsService.showToast(
- "success",
- null,
- this.i18nService.t("organizationUpgraded"),
- );
+ orgId = await this.createCloudHosted(key, collectionCt, orgKeys, orgKey[1]);
}
- await this.apiService.refreshIdentityToken();
- await this.syncService.fullSync(true);
+ this.platformUtilsService.showToast(
+ "success",
+ this.i18nService.t("organizationCreated"),
+ this.i18nService.t("organizationReadyToGo"),
+ );
+ } else {
+ orgId = await this.updateOrganization(orgId);
+ this.platformUtilsService.showToast(
+ "success",
+ null,
+ this.i18nService.t("organizationUpgraded"),
+ );
+ }
- if (!this.acceptingSponsorship && !this.isInTrialFlow) {
- // 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.router.navigate(["/organizations/" + orgId]);
- }
+ await this.apiService.refreshIdentityToken();
+ await this.syncService.fullSync(true);
- if (this.isInTrialFlow) {
- this.onTrialBillingSuccess.emit({
- orgId: orgId,
- subLabelText: this.billingSubLabelText(),
- });
- }
+ if (!this.acceptingSponsorship && !this.isInTrialFlow) {
+ // 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.router.navigate(["/organizations/" + orgId]);
+ }
- return orgId;
- };
+ if (this.isInTrialFlow) {
+ this.onTrialBillingSuccess.emit({
+ orgId: orgId,
+ subLabelText: this.billingSubLabelText(),
+ });
+ }
- this.formPromise = doSubmit();
- const organizationId = await this.formPromise;
- this.onSuccess.emit({ organizationId: organizationId });
- // TODO: No one actually listening to this message?
- this.messagingService.send("organizationCreated", { organizationId });
- } catch (e) {
- this.logService.error(e);
- }
- }
+ return orgId;
+ };
+
+ this.formPromise = doSubmit();
+ const organizationId = await this.formPromise;
+ this.onSuccess.emit({ organizationId: organizationId });
+ this.messagingService.send("organizationCreated", organizationId);
+ };
private async updateOrganization(orgId: string) {
const request = new OrganizationUpgradeRequest();
@@ -693,14 +697,12 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
}
private async createSelfHosted(key: string, collectionCt: string, orgKeys: [string, EncString]) {
- const fileEl = document.getElementById("file") as HTMLInputElement;
- const files = fileEl.files;
- if (files == null || files.length === 0) {
+ if (!this.selectedFile) {
throw new Error(this.i18nService.t("selectFile"));
}
const fd = new FormData();
- fd.append("license", files[0]);
+ fd.append("license", this.selectedFile);
fd.append("key", key);
fd.append("collectionName", collectionCt);
const response = await this.organizationApiService.createLicense(fd);