1
0
mirror of https://github.com/bitwarden/browser synced 2025-01-22 17:22:56 +01:00
bitwarden-estensione-browser/apps/web/src/app/layouts/user-layout.component.ts
Matt Gibson 62ad39e697
Ps/pm 5965/better config polling (#8325)
* Create tracker that can await until expected observables are received.

* Test dates are almost equal

* Remove unused class method

* Allow for updating active account in accout service fake

* Correct observable tracker behavior

Clarify documentation

* Transition config service to state provider

Updates the config fetching behavior to be lazy and ensure that any emitted value has been updated if older than a configurable value (statically compiled).

If desired, config fetching can be ensured fresh through an async.

* Update calls to config service in DI and bootstrapping

* Migrate account server configs

* Fix global config fetching

* Test migration rollback

* Adhere to implementation naming convention

* Adhere to abstract class naming convention

* Complete config abstraction rename

* Remove unnecessary cli config service

* Fix builds

* Validate observable does not complete

* Use token service to determine authed or unauthed config pull

* Remove superfluous factory config

* Name describe blocks after the thing they test

* Remove implementation documentation

Unfortunately the experience when linking to external documentation is quite poor. Instead of following the link and retrieving docs, you get a link that can be clicked to take you out of context to the docs. No link _does_ retrieve docs, but lacks indication in the implementation that documentation exists at all.

On the balance, removing the link is the better experience.

* Fix storybook
2024-03-27 10:03:09 -07:00

101 lines
3.8 KiB
TypeScript

import { CommonModule } from "@angular/common";
import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
import { RouterModule } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { IconModule, LayoutComponent, NavigationModule } from "@bitwarden/components";
import { PaymentMethodWarningsModule } from "../billing/shared";
import { PasswordManagerLogo } from "./password-manager-logo";
const BroadcasterSubscriptionId = "UserLayoutComponent";
@Component({
selector: "app-user-layout",
templateUrl: "user-layout.component.html",
standalone: true,
imports: [
CommonModule,
RouterModule,
JslibModule,
LayoutComponent,
IconModule,
NavigationModule,
PaymentMethodWarningsModule,
],
})
export class UserLayoutComponent implements OnInit, OnDestroy {
protected readonly logo = PasswordManagerLogo;
hasFamilySponsorshipAvailable: boolean;
hideSubscription: boolean;
protected showPaymentMethodWarningBanners$ = this.configService.getFeatureFlag$(
FeatureFlag.ShowPaymentMethodWarningBanners,
false,
);
constructor(
private broadcasterService: BroadcasterService,
private ngZone: NgZone,
private platformUtilsService: PlatformUtilsService,
private organizationService: OrganizationService,
private apiService: ApiService,
private syncService: SyncService,
private configService: ConfigService,
private billingAccountProfileStateService: BillingAccountProfileStateService,
) {}
async ngOnInit() {
document.body.classList.remove("layout_frontend");
this.broadcasterService.subscribe(BroadcasterSubscriptionId, async (message: any) => {
// 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.ngZone.run(async () => {
switch (message.command) {
case "purchasedPremium":
await this.load();
break;
default:
}
});
});
await this.syncService.fullSync(false);
await this.load();
}
ngOnDestroy() {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
}
async load() {
const hasPremiumPersonally = await firstValueFrom(
this.billingAccountProfileStateService.hasPremiumPersonally$,
);
const hasPremiumFromOrg = await firstValueFrom(
this.billingAccountProfileStateService.hasPremiumFromAnyOrganization$,
);
const selfHosted = this.platformUtilsService.isSelfHost();
this.hasFamilySponsorshipAvailable = await this.organizationService.canManageSponsorships();
let billing = null;
if (!selfHosted) {
// TODO: We should remove the need to call this!
billing = await this.apiService.getUserBillingHistory();
}
this.hideSubscription =
!hasPremiumPersonally && hasPremiumFromOrg && (selfHosted || billing?.hasNoHistory);
}
}