diff --git a/apps/web/src/app/billing/individual/upgrade/upgrade-payment/upgrade-payment.component.html b/apps/web/src/app/billing/individual/upgrade/upgrade-payment/upgrade-payment.component.html
index 7b92ae10947..fad883f942a 100644
--- a/apps/web/src/app/billing/individual/upgrade/upgrade-payment/upgrade-payment.component.html
+++ b/apps/web/src/app/billing/individual/upgrade/upgrade-payment/upgrade-payment.component.html
@@ -31,11 +31,19 @@
}
+
{{ "paymentMethod" | i18n }}
+
{{ "billingAddress" | i18n }}
+
+
diff --git a/apps/web/src/app/billing/individual/upgrade/upgrade-payment/upgrade-payment.component.ts b/apps/web/src/app/billing/individual/upgrade/upgrade-payment/upgrade-payment.component.ts
index 33568435d01..bd88c22f98d 100644
--- a/apps/web/src/app/billing/individual/upgrade/upgrade-payment/upgrade-payment.component.ts
+++ b/apps/web/src/app/billing/individual/upgrade/upgrade-payment/upgrade-payment.component.ts
@@ -10,7 +10,7 @@ import {
} from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { FormControl, FormGroup, Validators } from "@angular/forms";
-import { debounceTime, Observable } from "rxjs";
+import { catchError, debounceTime, from, Observable, of, switchMap } from "rxjs";
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -20,7 +20,10 @@ import { LogService } from "@bitwarden/logging";
import { CartSummaryComponent, LineItem } from "@bitwarden/pricing";
import { SharedModule } from "@bitwarden/web-vault/app/shared";
-import { EnterPaymentMethodComponent } from "../../../payment/components";
+import {
+ EnterBillingAddressComponent,
+ EnterPaymentMethodComponent,
+} from "../../../payment/components";
import { BillingServicesModule } from "../../../services";
import { SubscriptionPricingService } from "../../../services/subscription-pricing.service";
import { BitwardenSubscriber } from "../../../types";
@@ -65,6 +68,7 @@ export type UpgradePaymentParams = {
CartSummaryComponent,
ButtonModule,
EnterPaymentMethodComponent,
+ EnterBillingAddressComponent,
BillingServicesModule,
],
providers: [UpgradePaymentService],
@@ -83,6 +87,7 @@ export class UpgradePaymentComponent implements OnInit, AfterViewInit {
protected formGroup = new FormGroup({
organizationName: new FormControl("", [Validators.required]),
paymentForm: EnterPaymentMethodComponent.getFormGroup(),
+ billingAddress: EnterBillingAddressComponent.getFormGroup(),
});
protected loading = signal(true);
@@ -140,9 +145,16 @@ export class UpgradePaymentComponent implements OnInit, AfterViewInit {
}
});
- this.formGroup.valueChanges
- .pipe(debounceTime(1000), takeUntilDestroyed(this.destroyRef))
- .subscribe(() => this.refreshSalesTax());
+ this.formGroup.controls.billingAddress.valueChanges
+ .pipe(
+ debounceTime(1000),
+ // Only proceed when form has required values
+ switchMap(() => this.refreshSalesTax$()),
+ takeUntilDestroyed(this.destroyRef),
+ )
+ .subscribe((tax) => {
+ this.estimatedTax = tax;
+ });
this.loading.set(false);
}
@@ -199,8 +211,8 @@ export class UpgradePaymentComponent implements OnInit, AfterViewInit {
private async processUpgrade(): Promise {
// Get common values
- const country = this.formGroup.value?.paymentForm?.billingAddress?.country;
- const postalCode = this.formGroup.value?.paymentForm?.billingAddress?.postalCode;
+ const country = this.formGroup.value?.billingAddress?.country;
+ const postalCode = this.formGroup.value?.billingAddress?.postalCode;
if (!this.selectedPlan) {
throw new Error("No plan selected");
@@ -246,19 +258,20 @@ export class UpgradePaymentComponent implements OnInit, AfterViewInit {
}
}
- private async refreshSalesTax(): Promise {
+ // Create an observable for tax calculation
+ private refreshSalesTax$(): Observable {
const billingAddress = {
- country: this.formGroup.value.paymentForm?.billingAddress?.country,
- postalCode: this.formGroup.value.paymentForm?.billingAddress?.postalCode,
+ country: this.formGroup.value?.billingAddress?.country,
+ postalCode: this.formGroup.value?.billingAddress?.postalCode,
};
if (!this.selectedPlan || !billingAddress.country || !billingAddress.postalCode) {
- this.estimatedTax = 0;
- return;
+ return of(0);
}
- this.upgradePaymentService
- .calculateEstimatedTax(this.selectedPlan, {
+ // Convert Promise to Observable
+ return from(
+ this.upgradePaymentService.calculateEstimatedTax(this.selectedPlan, {
line1: null,
line2: null,
city: null,
@@ -266,17 +279,16 @@ export class UpgradePaymentComponent implements OnInit, AfterViewInit {
country: billingAddress.country,
postalCode: billingAddress.postalCode,
taxId: null,
- })
- .then((tax) => {
- this.estimatedTax = tax;
- })
- .catch((error: unknown) => {
+ }),
+ ).pipe(
+ catchError((error: unknown) => {
this.logService.error("Tax calculation failed:", error);
this.toastService.showToast({
variant: "error",
message: this.i18nService.t("taxCalculationError"),
});
- this.estimatedTax = 0;
- });
+ return of(0); // Return default value on error
+ }),
+ );
}
}