Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3e9ed40
refactor(pricing): misc
amorask-bitwarden Dec 23, 2025
9c163dc
refactor(pricing): discount-badge.component
amorask-bitwarden Dec 23, 2025
b5d1325
refactor(pricing): pricing-card.component
amorask-bitwarden Dec 23, 2025
5ca249c
refactor(pricing): cart-summary.component
amorask-bitwarden Dec 26, 2025
d613656
feat(subscription): misc
amorask-bitwarden Dec 26, 2025
524f2a3
feat(subscription): subscription-card.component
amorask-bitwarden Dec 29, 2025
bcfa140
feat(subscription): storage-card.component
amorask-bitwarden Dec 29, 2025
d89fa00
feat(subscription): additional-options-card.component
amorask-bitwarden Dec 29, 2025
3ef3800
Merge branch 'main' into billing/PM-29608-PM-29609/premium-subscriptiโ€ฆ
amorask-bitwarden Dec 29, 2025
fca4f5d
fix(pricing): cart-summary.component.stories.ts lint
amorask-bitwarden Dec 29, 2025
1936a5f
fix(pricing): discount-badge.component.stories.ts lint
amorask-bitwarden Dec 29, 2025
c7096e7
Merge branch 'main' into billing/PM-29608-PM-29609/premium-subscriptiโ€ฆ
amorask-bitwarden Dec 29, 2025
9b3f4fc
Merge branch 'main' into billing/PM-29608-PM-29609/premium-subscriptiโ€ฆ
amorask-bitwarden Dec 29, 2025
2e910c5
Merge branch 'main' into billing/PM-29608-PM-29609/premium-subscriptiโ€ฆ
amorask-bitwarden Dec 30, 2025
bc27e95
Merge branch 'main' into billing/PM-29608-PM-29609/premium-subscriptiโ€ฆ
amorask-bitwarden Dec 30, 2025
009bab6
fix(web): Resolve estimatedTax$ toSignal for use in cart on upgrade-pโ€ฆ
amorask-bitwarden Dec 30, 2025
542af24
feedback(design): Fix design issues
amorask-bitwarden Dec 30, 2025
34494b9
Merge branch 'main' into billing/PM-29608-PM-29609/premium-subscriptiโ€ฆ
amorask-bitwarden Dec 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const config: StorybookConfig = {
"../libs/dirt/card/src/**/*.stories.@(js|jsx|ts|tsx)",
"../libs/pricing/src/**/*.mdx",
"../libs/pricing/src/**/*.stories.@(js|jsx|ts|tsx)",
"../libs/subscription/src/**/*.mdx",
"../libs/subscription/src/**/*.stories.@(js|jsx|ts|tsx)",
"../libs/tools/send/send-ui/src/**/*.mdx",
"../libs/tools/send/send-ui/src/**/*.stories.@(js|jsx|ts|tsx)",
"../libs/vault/src/**/*.mdx",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,7 @@ <h5 bitTypography="h5" class="tw-pt-4 tw-pb-2">{{ "billingAddress" | i18n }}</h5
</section>

<section>
<billing-cart-summary
#cartSummaryComponent
[passwordManager]="passwordManager()"
[estimatedTax]="estimatedTax$ | async"
></billing-cart-summary>
<billing-cart-summary #cartSummaryComponent [cart]="cart()"></billing-cart-summary>
@if (isFamiliesPlan) {
<p bitTypography="helper" class="tw-italic tw-text-muted !tw-mb-0">
{{ "paymentChargedWithTrial" | i18n }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
signal,
viewChild,
} from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { takeUntilDestroyed, toSignal } from "@angular/core/rxjs-interop";
import { FormControl, FormGroup, Validators } from "@angular/forms";
import {
debounceTime,
Expand All @@ -22,6 +22,7 @@ import {
combineLatest,
map,
shareReplay,
defer,
} from "rxjs";

import { Account } from "@bitwarden/common/auth/abstractions/account.service";
Expand All @@ -35,7 +36,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values";
import { ButtonModule, DialogModule, ToastService } from "@bitwarden/components";
import { LogService } from "@bitwarden/logging";
import { CartSummaryComponent } from "@bitwarden/pricing";
import { Cart, CartSummaryComponent } from "@bitwarden/pricing";
import { SharedModule } from "@bitwarden/web-vault/app/shared";

import {
Expand Down Expand Up @@ -118,24 +119,49 @@ export class UpgradePaymentComponent implements OnInit, AfterViewInit {
protected readonly selectedPlan = signal<PlanDetails | null>(null);
protected readonly loading = signal(true);
protected readonly upgradeToMessage = signal("");

protected hasEnoughAccountCredit$!: Observable<boolean>;
private pricingTiers$!: Observable<PersonalSubscriptionPricingTier[]>;

// Use defer to lazily create the observable when subscribed to
protected estimatedTax$ = defer(() =>
this.formGroup.controls.billingAddress.valueChanges.pipe(
startWith(this.formGroup.controls.billingAddress.value),
debounceTime(1000),
switchMap(() => this.refreshSalesTax$()),
),
);

// Convert estimatedTax$ to signal for use in computed cart
protected readonly estimatedTax = toSignal(this.estimatedTax$, {
initialValue: this.INITIAL_TAX_VALUE,
});

// Cart Summary data
protected readonly passwordManager = computed(() => {
protected readonly cart = computed<Cart>(() => {
if (!this.selectedPlan()) {
return { name: "", cost: 0, quantity: 0, cadence: "year" as const };
return {
passwordManager: {
seats: { name: "", cost: 0, quantity: 0 },
},
cadence: "annually",
estimatedTax: 0,
};
}

return {
name: this.isFamiliesPlan ? "familiesMembership" : "premiumMembership",
cost: this.selectedPlan()!.details.passwordManager.annualPrice,
quantity: 1,
cadence: "year" as const,
passwordManager: {
seats: {
name: this.isFamiliesPlan ? "familiesMembership" : "premiumMembership",
cost: this.selectedPlan()!.details.passwordManager.annualPrice ?? 0,
quantity: 1,
},
},
cadence: "annually",
estimatedTax: this.estimatedTax() ?? 0,
};
});

protected hasEnoughAccountCredit$!: Observable<boolean>;
private pricingTiers$!: Observable<PersonalSubscriptionPricingTier[]>;
protected estimatedTax$!: Observable<number>;

constructor(
private i18nService: I18nService,
private subscriptionPricingService: SubscriptionPricingServiceAbstraction,
Expand Down Expand Up @@ -186,13 +212,6 @@ export class UpgradePaymentComponent implements OnInit, AfterViewInit {
}
});

this.estimatedTax$ = this.formGroup.controls.billingAddress.valueChanges.pipe(
startWith(this.formGroup.controls.billingAddress.value),
debounceTime(1000),
// Only proceed when form has required values
switchMap(() => this.refreshSalesTax$()),
);

this.loading.set(false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
}}
</span>
<billing-discount-badge
[discount]="getDiscountInfo(sub?.customerDiscount)"
[discount]="getDiscount(sub?.customerDiscount)"
></billing-discount-badge>
</div>
</ng-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService, ToastService } from "@bitwarden/components";
import { DiscountInfo } from "@bitwarden/pricing";
import { Discount, Maybe } from "@bitwarden/pricing";

import {
AdjustStorageDialogComponent,
Expand Down Expand Up @@ -251,15 +251,13 @@ export class UserSubscriptionComponent implements OnInit {
}
}

getDiscountInfo(discount: BillingCustomerDiscount | null): DiscountInfo | null {
getDiscount(discount: BillingCustomerDiscount | null): Maybe<Discount> {
if (!discount) {
return null;
}
return {
active: discount.active,
percentOff: discount.percentOff,
amountOff: discount.amountOff,
};
return discount.amountOff
? { type: "amount-off", active: discount.active, value: discount.amountOff }
: { type: "percent-off", active: discount.active, value: discount.percentOff };
}

get isSubscriptionActive(): boolean {
Expand Down
Loading
Loading