mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 00:03:56 +00:00
[PM-14366] Deprecated active user state from billing state service (#12273)
* Updated billing state provider to not rely on ActiveUserStateProvider * Updated usages * Resolved browser build * Resolved web build * Resolved CLI build * resolved desktop build * Update apps/cli/src/tools/send/commands/create.command.ts Co-authored-by: ✨ Audrey ✨ <ajensen@bitwarden.com> * Move subscription visibility logic from component to service * Resolved unit test failures. Using existing userIds where present * Simplified activeUserId access * Resolved typescript strict errors * Resolved broken unit test * Resolved ts strict error --------- Co-authored-by: ✨ Audrey ✨ <ajensen@bitwarden.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { TwoFactorDuoResponse } from "@bitwarden/common/auth/models/response/two-factor-duo.response";
|
||||
import { AuthResponse } from "@bitwarden/common/auth/types/auth-response";
|
||||
@@ -37,6 +38,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme
|
||||
private route: ActivatedRoute,
|
||||
private organizationService: OrganizationService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
accountService: AccountService,
|
||||
) {
|
||||
super(
|
||||
dialogService,
|
||||
@@ -45,6 +47,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme
|
||||
messagingService,
|
||||
policyService,
|
||||
billingAccountProfileStateService,
|
||||
accountService,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { lastValueFrom, Observable, firstValueFrom } from "rxjs";
|
||||
import { lastValueFrom, Observable, firstValueFrom, switchMap } from "rxjs";
|
||||
|
||||
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -69,8 +70,13 @@ export class EmergencyAccessComponent implements OnInit {
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
protected organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||
private toastService: ToastService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
|
||||
this.canAccessPremium$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$(account.id),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Subject,
|
||||
Subscription,
|
||||
takeUntil,
|
||||
switchMap,
|
||||
} from "rxjs";
|
||||
|
||||
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
|
||||
@@ -18,6 +19,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/auth/models/response/two-factor-authenticator.response";
|
||||
import { TwoFactorDuoResponse } from "@bitwarden/common/auth/models/response/two-factor-duo.response";
|
||||
@@ -69,8 +71,13 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
||||
protected messagingService: MessagingService,
|
||||
protected policyService: PolicyService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
|
||||
this.canAccessPremium$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$(account.id),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
|
||||
@@ -4,10 +4,11 @@ import { Component, ViewChild } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { combineLatest, concatMap, from, Observable, of } from "rxjs";
|
||||
import { combineLatest, concatMap, from, Observable, of, switchMap } from "rxjs";
|
||||
import { debounceTime } from "rxjs/operators";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||
import { TaxServiceAbstraction } from "@bitwarden/common/billing/abstractions/tax.service.abstraction";
|
||||
@@ -65,14 +66,22 @@ export class PremiumV2Component {
|
||||
private toastService: ToastService,
|
||||
private tokenService: TokenService,
|
||||
private taxService: TaxServiceAbstraction,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.isSelfHost = this.platformUtilsService.isSelfHost();
|
||||
|
||||
this.hasPremiumFromAnyOrganization$ =
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnyOrganization$;
|
||||
this.hasPremiumFromAnyOrganization$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnyOrganization$(account.id),
|
||||
),
|
||||
);
|
||||
|
||||
combineLatest([
|
||||
this.billingAccountProfileStateService.hasPremiumPersonally$,
|
||||
this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.billingAccountProfileStateService.hasPremiumPersonally$(account.id),
|
||||
),
|
||||
),
|
||||
this.environmentService.cloudWebVaultUrl$,
|
||||
])
|
||||
.pipe(
|
||||
|
||||
@@ -4,10 +4,11 @@ import { Component, OnInit, ViewChild } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom, Observable } from "rxjs";
|
||||
import { firstValueFrom, Observable, switchMap } from "rxjs";
|
||||
import { debounceTime } from "rxjs/operators";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { TaxServiceAbstraction } from "@bitwarden/common/billing/abstractions/tax.service.abstraction";
|
||||
@@ -58,9 +59,14 @@ export class PremiumComponent implements OnInit {
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
private toastService: ToastService,
|
||||
private taxService: TaxServiceAbstraction,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.selfHosted = platformUtilsService.isSelfHost();
|
||||
this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$;
|
||||
this.canAccessPremium$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$(account.id),
|
||||
),
|
||||
);
|
||||
|
||||
this.addonForm.controls.additionalStorage.valueChanges
|
||||
.pipe(debounceTime(1000), takeUntilDestroyed())
|
||||
@@ -75,7 +81,10 @@ export class PremiumComponent implements OnInit {
|
||||
}
|
||||
async ngOnInit() {
|
||||
this.cloudWebVaultUrl = await firstValueFrom(this.environmentService.cloudWebVaultUrl$);
|
||||
if (await firstValueFrom(this.billingAccountProfileStateService.hasPremiumPersonally$)) {
|
||||
const account = await firstValueFrom(this.accountService.activeAccount$);
|
||||
if (
|
||||
await firstValueFrom(this.billingAccountProfileStateService.hasPremiumPersonally$(account.id))
|
||||
) {
|
||||
// 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(["/settings/subscription/user-subscription"]);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { Observable } from "rxjs";
|
||||
import { Observable, switchMap } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
@@ -16,8 +17,11 @@ export class SubscriptionComponent implements OnInit {
|
||||
constructor(
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
accountService: AccountService,
|
||||
) {
|
||||
this.hasPremium$ = billingAccountProfileStateService.hasPremiumPersonally$;
|
||||
this.hasPremium$ = accountService.activeAccount$.pipe(
|
||||
switchMap((account) => billingAccountProfileStateService.hasPremiumPersonally$(account.id)),
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Router } from "@angular/router";
|
||||
import { firstValueFrom, lastValueFrom } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { SubscriptionResponse } from "@bitwarden/common/billing/models/response/subscription.response";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
@@ -60,6 +61,7 @@ export class UserSubscriptionComponent implements OnInit {
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
private toastService: ToastService,
|
||||
private configService: ConfigService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.selfHosted = this.platformUtilsService.isSelfHost();
|
||||
}
|
||||
@@ -75,7 +77,10 @@ export class UserSubscriptionComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
if (await firstValueFrom(this.billingAccountProfileStateService.hasPremiumPersonally$)) {
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$);
|
||||
if (
|
||||
await firstValueFrom(this.billingAccountProfileStateService.hasPremiumPersonally$(userId.id))
|
||||
) {
|
||||
this.loading = true;
|
||||
this.sub = await this.apiService.getUserSubscription();
|
||||
} else {
|
||||
|
||||
@@ -6,9 +6,10 @@ import {
|
||||
CanActivateFn,
|
||||
UrlTree,
|
||||
} from "@angular/router";
|
||||
import { Observable } from "rxjs";
|
||||
import { tap } from "rxjs/operators";
|
||||
import { Observable, of } from "rxjs";
|
||||
import { switchMap, tap } from "rxjs/operators";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
|
||||
@@ -24,8 +25,14 @@ export function hasPremiumGuard(): CanActivateFn {
|
||||
const router = inject(Router);
|
||||
const messagingService = inject(MessagingService);
|
||||
const billingAccountProfileStateService = inject(BillingAccountProfileStateService);
|
||||
const accountService = inject(AccountService);
|
||||
|
||||
return billingAccountProfileStateService.hasPremiumFromAnySource$.pipe(
|
||||
return accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
account
|
||||
? billingAccountProfileStateService.hasPremiumFromAnySource$(account.id)
|
||||
: of(false),
|
||||
),
|
||||
tap((userHasPremium: boolean) => {
|
||||
if (!userHasPremium) {
|
||||
messagingService.send("premiumRequired");
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import { Observable, concatMap, combineLatest } from "rxjs";
|
||||
import { Observable, switchMap } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { IconModule } from "@bitwarden/components";
|
||||
|
||||
@@ -38,35 +37,19 @@ export class UserLayoutComponent implements OnInit {
|
||||
protected showSubscription$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private apiService: ApiService,
|
||||
private syncService: SyncService,
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {}
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.showSubscription$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.billingAccountProfileStateService.canViewSubscription$(account.id),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
document.body.classList.remove("layout_frontend");
|
||||
|
||||
await this.syncService.fullSync(false);
|
||||
|
||||
// We want to hide the subscription menu for organizations that provide premium.
|
||||
// Except if the user has premium personally or has a billing history.
|
||||
this.showSubscription$ = combineLatest([
|
||||
this.billingAccountProfileStateService.hasPremiumPersonally$,
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnyOrganization$,
|
||||
]).pipe(
|
||||
concatMap(async ([hasPremiumPersonally, hasPremiumFromOrg]) => {
|
||||
const isCloud = !this.platformUtilsService.isSelfHost();
|
||||
|
||||
let billing = null;
|
||||
if (isCloud) {
|
||||
// TODO: We should remove the need to call this!
|
||||
billing = await this.apiService.getUserBillingHistory();
|
||||
}
|
||||
|
||||
const cloudAndBillingHistory = isCloud && !billing?.hasNoHistory;
|
||||
return hasPremiumPersonally || !hasPremiumFromOrg || cloudAndBillingHistory;
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
|
||||
import { reports, ReportType } from "../reports";
|
||||
@@ -15,11 +16,15 @@ import { ReportEntry, ReportVariant } from "../shared";
|
||||
export class ReportsHomeComponent implements OnInit {
|
||||
reports: ReportEntry[];
|
||||
|
||||
constructor(private billingAccountProfileStateService: BillingAccountProfileStateService) {}
|
||||
constructor(
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
const account = await firstValueFrom(this.accountService.activeAccount$);
|
||||
const userHasPremium = await firstValueFrom(
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$,
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$(account.id),
|
||||
);
|
||||
const reportRequiresPremium = userHasPremium
|
||||
? ReportVariant.Enabled
|
||||
|
||||
@@ -4,7 +4,7 @@ import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom, Observable, Subject } from "rxjs";
|
||||
import { firstValueFrom, Observable, Subject, switchMap } from "rxjs";
|
||||
import { map } from "rxjs/operators";
|
||||
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
@@ -183,7 +183,11 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
|
||||
* Flag to indicate if the user has access to attachments via a premium subscription.
|
||||
* @protected
|
||||
*/
|
||||
protected canAccessAttachments$ = this.billingAccountProfileStateService.hasPremiumFromAnySource$;
|
||||
protected canAccessAttachments$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$(account.id),
|
||||
),
|
||||
);
|
||||
|
||||
protected get loadingForm() {
|
||||
return this.loadForm && !this.formReady;
|
||||
|
||||
@@ -9,6 +9,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
@@ -34,6 +35,7 @@ describe("AddEditComponentV2", () => {
|
||||
let messagingService: MockProxy<MessagingService>;
|
||||
let folderService: MockProxy<FolderService>;
|
||||
let collectionService: MockProxy<CollectionService>;
|
||||
let accountService: MockProxy<AccountService>;
|
||||
|
||||
const mockParams = {
|
||||
cloneMode: false,
|
||||
@@ -55,7 +57,9 @@ describe("AddEditComponentV2", () => {
|
||||
);
|
||||
|
||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$.mockImplementation((userId) =>
|
||||
of(true),
|
||||
);
|
||||
|
||||
activatedRoute = mock<ActivatedRoute>();
|
||||
activatedRoute.queryParams = of({});
|
||||
@@ -68,6 +72,9 @@ describe("AddEditComponentV2", () => {
|
||||
collectionService = mock<CollectionService>();
|
||||
collectionService.decryptedCollections$ = of([]);
|
||||
|
||||
accountService = mock<AccountService>();
|
||||
accountService.activeAccount$ = of({ id: "test-id" } as any);
|
||||
|
||||
const mockDefaultCipherFormConfigService = {
|
||||
buildConfig: jest.fn().mockResolvedValue({
|
||||
allowPersonal: true,
|
||||
@@ -97,6 +104,7 @@ describe("AddEditComponentV2", () => {
|
||||
provide: PasswordGenerationServiceAbstraction,
|
||||
useValue: mock<PasswordGenerationServiceAbstraction>(),
|
||||
},
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, Inject, OnInit } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { switchMap } from "rxjs";
|
||||
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherId } from "@bitwarden/common/types/guid";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
@@ -85,10 +87,16 @@ export class AddEditComponentV2 implements OnInit {
|
||||
private i18nService: I18nService,
|
||||
private dialogService: DialogService,
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe((canAccessPremium) => {
|
||||
this.accountService.activeAccount$
|
||||
.pipe(
|
||||
switchMap((account) =>
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$(account.id),
|
||||
),
|
||||
takeUntilDestroyed(),
|
||||
)
|
||||
.subscribe((canAccessPremium: boolean) => {
|
||||
this.canAccessAttachments = canAccessPremium;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// @ts-strict-ignore
|
||||
import { DatePipe } from "@angular/common";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
|
||||
@@ -116,9 +116,14 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On
|
||||
this.hasPasswordHistory = this.cipher.hasPasswordHistory;
|
||||
this.cleanUp();
|
||||
|
||||
this.canAccessPremium = await firstValueFrom(
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$,
|
||||
const activeUserId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a.id)),
|
||||
);
|
||||
|
||||
this.canAccessPremium = await firstValueFrom(
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$(activeUserId),
|
||||
);
|
||||
|
||||
if (this.showTotp()) {
|
||||
await this.totpUpdateCode();
|
||||
const interval = this.totpService.getTimeInterval(this.cipher.login.totp);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { TestBed } from "@angular/core/testing";
|
||||
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
@@ -21,7 +22,8 @@ describe("VaultBannersService", () => {
|
||||
let service: VaultBannersService;
|
||||
const isSelfHost = jest.fn().mockReturnValue(false);
|
||||
const hasPremiumFromAnySource$ = new BehaviorSubject<boolean>(false);
|
||||
const fakeStateProvider = new FakeStateProvider(mockAccountServiceWith("user-id" as UserId));
|
||||
const userId = "user-id" as UserId;
|
||||
const fakeStateProvider = new FakeStateProvider(mockAccountServiceWith(userId));
|
||||
const getEmailVerified = jest.fn().mockResolvedValue(true);
|
||||
const hasMasterPassword = jest.fn().mockResolvedValue(true);
|
||||
const getKdfConfig = jest
|
||||
@@ -44,15 +46,15 @@ describe("VaultBannersService", () => {
|
||||
},
|
||||
{
|
||||
provide: BillingAccountProfileStateService,
|
||||
useValue: { hasPremiumFromAnySource$: hasPremiumFromAnySource$ },
|
||||
useValue: { hasPremiumFromAnySource$: () => hasPremiumFromAnySource$ },
|
||||
},
|
||||
{
|
||||
provide: StateProvider,
|
||||
useValue: fakeStateProvider,
|
||||
},
|
||||
{
|
||||
provide: PlatformUtilsService,
|
||||
useValue: { isSelfHost },
|
||||
provide: AccountService,
|
||||
useValue: mockAccountServiceWith(userId),
|
||||
},
|
||||
{
|
||||
provide: TokenService,
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Subject, Observable, combineLatest, firstValueFrom, map } from "rxjs";
|
||||
import { mergeMap, take } from "rxjs/operators";
|
||||
import {
|
||||
Subject,
|
||||
Observable,
|
||||
combineLatest,
|
||||
firstValueFrom,
|
||||
map,
|
||||
mergeMap,
|
||||
take,
|
||||
switchMap,
|
||||
of,
|
||||
} from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
@@ -74,15 +84,23 @@ export class VaultBannersService {
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
private syncService: SyncService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.pollUntilSynced();
|
||||
this.premiumBannerState = this.stateProvider.getActive(PREMIUM_BANNER_REPROMPT_KEY);
|
||||
this.sessionBannerState = this.stateProvider.getActive(BANNERS_DISMISSED_DISK_KEY);
|
||||
|
||||
const premiumSources$ = combineLatest([
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$,
|
||||
this.premiumBannerState.state$,
|
||||
]);
|
||||
const premiumSources$ = this.accountService.activeAccount$.pipe(
|
||||
take(1),
|
||||
switchMap((account) => {
|
||||
return combineLatest([
|
||||
account
|
||||
? this.billingAccountProfileStateService.hasPremiumFromAnySource$(account.id)
|
||||
: of(false),
|
||||
this.premiumBannerState.state$,
|
||||
]);
|
||||
}),
|
||||
);
|
||||
|
||||
this.shouldShowPremiumBanner$ = this.syncCompleted$.pipe(
|
||||
take(1), // Wait until the first sync is complete before considering the premium status
|
||||
|
||||
@@ -467,7 +467,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
switchMap(() =>
|
||||
combineLatest([
|
||||
filter$,
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$,
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$(this.activeUserId),
|
||||
allCollections$,
|
||||
this.organizationService.organizations$,
|
||||
ciphers$,
|
||||
|
||||
Reference in New Issue
Block a user