mirror of
https://github.com/bitwarden/browser
synced 2026-03-01 11:01:17 +00:00
* fix(billing): only show Subscription menu option when premium user has subscription
* fix(billing): missed state service invocation changes
(cherry picked from commit b964cfc8e4)
This commit is contained in:
@@ -3,6 +3,7 @@ import { Component, DestroyRef, inject } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import {
|
||||
catchError,
|
||||
combineLatest,
|
||||
firstValueFrom,
|
||||
from,
|
||||
@@ -32,6 +33,7 @@ import {
|
||||
} from "@bitwarden/components";
|
||||
import { PricingCardComponent } from "@bitwarden/pricing";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
import { AccountBillingClient } from "@bitwarden/web-vault/app/billing/clients";
|
||||
|
||||
import { BitwardenSubscriber, mapAccountToSubscriber } from "../../types";
|
||||
import {
|
||||
@@ -63,10 +65,12 @@ const RouteParamValues = {
|
||||
I18nPipe,
|
||||
PricingCardComponent,
|
||||
],
|
||||
providers: [AccountBillingClient],
|
||||
})
|
||||
export class CloudHostedPremiumComponent {
|
||||
protected hasPremiumFromAnyOrganization$: Observable<boolean>;
|
||||
protected hasPremiumPersonally$: Observable<boolean>;
|
||||
protected hasSubscription$: Observable<boolean>;
|
||||
protected shouldShowNewDesign$: Observable<boolean>;
|
||||
protected shouldShowUpgradeDialogOnInit$: Observable<boolean>;
|
||||
protected personalPricingTiers$: Observable<PersonalSubscriptionPricingTier[]>;
|
||||
@@ -84,6 +88,7 @@ export class CloudHostedPremiumComponent {
|
||||
private destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(
|
||||
private accountBillingClient: AccountBillingClient,
|
||||
private accountService: AccountService,
|
||||
private apiService: ApiService,
|
||||
private dialogService: DialogService,
|
||||
@@ -109,6 +114,17 @@ export class CloudHostedPremiumComponent {
|
||||
),
|
||||
);
|
||||
|
||||
this.hasSubscription$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
account
|
||||
? from(this.accountBillingClient.getSubscription()).pipe(
|
||||
map((subscription) => !!subscription),
|
||||
catchError(() => of(false)),
|
||||
)
|
||||
: of(false),
|
||||
),
|
||||
);
|
||||
|
||||
this.accountService.activeAccount$
|
||||
.pipe(mapAccountToSubscriber, takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((subscriber) => {
|
||||
@@ -122,11 +138,15 @@ export class CloudHostedPremiumComponent {
|
||||
|
||||
// redirect to user subscription page if they already have premium personally
|
||||
// redirect to individual vault if they already have premium from an org
|
||||
combineLatest([this.hasPremiumFromAnyOrganization$, this.hasPremiumPersonally$])
|
||||
combineLatest([
|
||||
this.hasPremiumFromAnyOrganization$,
|
||||
this.hasPremiumPersonally$,
|
||||
this.hasSubscription$,
|
||||
])
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
switchMap(([hasPremiumFromOrg, hasPremiumPersonally]) => {
|
||||
if (hasPremiumPersonally) {
|
||||
switchMap(([hasPremiumFromOrg, hasPremiumPersonally, hasSubscription]) => {
|
||||
if (hasPremiumPersonally && hasSubscription) {
|
||||
return from(this.navigateToSubscriptionPage());
|
||||
}
|
||||
if (hasPremiumFromOrg) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit, Signal } from "@angular/core";
|
||||
import { toSignal } from "@angular/core/rxjs-interop";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import { map, Observable, switchMap } from "rxjs";
|
||||
import { catchError, combineLatest, from, map, Observable, of, switchMap } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { PasswordManagerLogo } from "@bitwarden/assets/svg";
|
||||
@@ -18,6 +18,8 @@ import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { SvgModule } from "@bitwarden/components";
|
||||
import { UserId } from "@bitwarden/user-core";
|
||||
import { AccountBillingClient } from "@bitwarden/web-vault/app/billing/clients";
|
||||
|
||||
import { BillingFreeFamiliesNavItemComponent } from "../billing/shared/billing-free-families-nav-item.component";
|
||||
|
||||
@@ -36,12 +38,11 @@ import { WebLayoutModule } from "./web-layout.module";
|
||||
SvgModule,
|
||||
BillingFreeFamiliesNavItemComponent,
|
||||
],
|
||||
providers: [AccountBillingClient],
|
||||
})
|
||||
export class UserLayoutComponent implements OnInit {
|
||||
protected readonly logo = PasswordManagerLogo;
|
||||
protected readonly showEmergencyAccess: Signal<boolean>;
|
||||
protected hasFamilySponsorshipAvailable$: Observable<boolean>;
|
||||
protected showSponsoredFamilies$: Observable<boolean>;
|
||||
protected showSubscription$: Observable<boolean>;
|
||||
protected readonly sendEnabled$: Observable<boolean> = this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
@@ -49,6 +50,9 @@ export class UserLayoutComponent implements OnInit {
|
||||
map((isDisabled) => !isDisabled),
|
||||
);
|
||||
protected consolidatedSessionTimeoutComponent$: Observable<boolean>;
|
||||
protected hasPremiumPersonally$: Observable<boolean>;
|
||||
protected hasPremiumFromAnyOrganization$: Observable<boolean>;
|
||||
protected hasSubscription$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
private syncService: SyncService,
|
||||
@@ -56,13 +60,8 @@ export class UserLayoutComponent implements OnInit {
|
||||
private accountService: AccountService,
|
||||
private policyService: PolicyService,
|
||||
private configService: ConfigService,
|
||||
private accountBillingClient: AccountBillingClient,
|
||||
) {
|
||||
this.showSubscription$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.billingAccountProfileStateService.canViewSubscription$(account.id),
|
||||
),
|
||||
);
|
||||
|
||||
this.showEmergencyAccess = toSignal(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
@@ -75,10 +74,44 @@ export class UserLayoutComponent implements OnInit {
|
||||
this.consolidatedSessionTimeoutComponent$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.ConsolidatedSessionTimeoutComponent,
|
||||
);
|
||||
|
||||
this.hasPremiumPersonally$ = this.ifAccountExistsCheck((userId) =>
|
||||
this.billingAccountProfileStateService.hasPremiumPersonally$(userId),
|
||||
);
|
||||
|
||||
this.hasPremiumFromAnyOrganization$ = this.ifAccountExistsCheck((userId) =>
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnyOrganization$(userId),
|
||||
);
|
||||
|
||||
this.hasSubscription$ = this.ifAccountExistsCheck(() =>
|
||||
from(this.accountBillingClient.getSubscription()).pipe(
|
||||
map((subscription) => !!subscription),
|
||||
catchError(() => of(false)),
|
||||
),
|
||||
);
|
||||
|
||||
this.showSubscription$ = combineLatest([
|
||||
this.hasPremiumPersonally$,
|
||||
this.hasPremiumFromAnyOrganization$,
|
||||
this.hasSubscription$,
|
||||
]).pipe(
|
||||
map(([hasPremiumPersonally, hasPremiumFromAnyOrganization, hasSubscription]) => {
|
||||
if (hasPremiumFromAnyOrganization && !hasPremiumPersonally) {
|
||||
return false;
|
||||
}
|
||||
return hasSubscription;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
document.body.classList.remove("layout_frontend");
|
||||
await this.syncService.fullSync(false);
|
||||
}
|
||||
|
||||
private ifAccountExistsCheck(predicate$: (userId: UserId) => Observable<boolean>) {
|
||||
return this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) => (account ? predicate$(account.id) : of(false))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user