From 9b2fbdba1c028bf3394064609630d2ec224baefa Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Thu, 16 Oct 2025 12:08:19 -0400 Subject: [PATCH] [PM-26947] Fix Billing Address Defect (#16872) * fix(billing): Add Billing Address component * fix(billing): Update tax refresh logic and swap billing address component * fix(billing): Fix headers * fix(billing): Do not show bank payment option for premium upgrade --- .../upgrade-payment.component.html | 10 +++- .../upgrade-payment.component.ts | 54 +++++++++++-------- 2 files changed, 42 insertions(+), 22 deletions(-) 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 + }), + ); } }