move premium banner to a standalone observable

This commit is contained in:
nick-livefront 2024-04-25 14:22:03 -05:00
parent 5bc5649297
commit 93463d47e5
No known key found for this signature in database
GPG Key ID: FF670021ABCAB82E
5 changed files with 50 additions and 29 deletions

View File

@ -74,7 +74,7 @@ describe("VaultBannersService", () => {
service = TestBed.inject(VaultBannersService);
expect(await service.shouldShowPremiumBanner()).toBe(true);
expect(await firstValueFrom(service.shouldShowPremiumBanner())).toBe(true);
});
describe("dismissing", () => {

View File

@ -1,5 +1,5 @@
import { Injectable } from "@angular/core";
import { firstValueFrom } from "rxjs";
import { Observable, combineLatest, firstValueFrom, map } from "rxjs";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
@ -99,24 +99,25 @@ export class VaultBannersService {
}
/** Returns true when the premium banner should be shown */
async shouldShowPremiumBanner(): Promise<boolean> {
const canAccessPremium = await firstValueFrom(
shouldShowPremiumBanner(): Observable<boolean> {
return combineLatest([
this.billingAccountProfileStateService.hasPremiumFromAnySource$,
this.premiumBannerState.state$,
]).pipe(
map(([canAccessPremium, dismissedState]) => {
const shouldShowPremiumBanner =
!canAccessPremium && !this.platformUtilsService.isSelfHost();
// Check if nextPromptDate is in the past passed
if (shouldShowPremiumBanner && dismissedState?.nextPromptDate) {
const nextPromptDate = new Date(dismissedState.nextPromptDate);
const now = new Date();
return now >= nextPromptDate;
}
return shouldShowPremiumBanner;
}),
);
const shouldShowPremiumBanner = !canAccessPremium && !this.platformUtilsService.isSelfHost();
const dismissedState = await firstValueFrom(this.premiumBannerState.state$);
// Check if nextPromptDate is in the past passed
if (shouldShowPremiumBanner && dismissedState?.nextPromptDate) {
const nextPromptDate = new Date(dismissedState.nextPromptDate);
const now = new Date();
return now >= nextPromptDate;
}
return shouldShowPremiumBanner;
}
/** Dismiss the given banner and perform any respective side effects */

View File

@ -38,7 +38,7 @@
<bit-banner
class="-tw-m-6 tw-flex tw-flex-col tw-pb-6"
bannerType="premium"
*ngIf="visibleBanners.includes(VisibleVaultBanner.Premium)"
*ngIf="premiumBannerVisible$ | async"
(onClose)="dismissBanner(VisibleVaultBanner.Premium)"
>
{{ "premiumUpgradeUnlockFeatures" | i18n }}

View File

@ -1,12 +1,14 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { mock } from "jest-mock-extended";
import { BehaviorSubject } from "rxjs";
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { BannerModule } from "@bitwarden/components";
import { BannerComponent, BannerModule } from "@bitwarden/components";
import { LooseComponentsModule } from "../../../shared";
@ -16,6 +18,7 @@ import { VaultBannersComponent } from "./vault-banners.component";
describe("VaultBannersComponent", () => {
let component: VaultBannersComponent;
let fixture: ComponentFixture<VaultBannersComponent>;
const premiumBanner$ = new BehaviorSubject<boolean>(false);
const bannerService = mock<VaultBannersService>({
shouldShowPremiumBanner: jest.fn(),
@ -26,7 +29,7 @@ describe("VaultBannersComponent", () => {
});
beforeEach(async () => {
bannerService.shouldShowPremiumBanner.mockResolvedValue(false);
bannerService.shouldShowPremiumBanner.mockReturnValue(premiumBanner$);
bannerService.shouldShowUpdateBrowserBanner.mockResolvedValue(false);
bannerService.shouldShowVerifyEmailBanner.mockResolvedValue(false);
bannerService.shouldShowLowKDFBanner.mockResolvedValue(false);
@ -66,13 +69,28 @@ describe("VaultBannersComponent", () => {
fixture.detectChanges();
});
describe("premiumBannerVisible$", () => {
it("shows premium banner", async () => {
premiumBanner$.next(true);
fixture.detectChanges();
const banner = fixture.debugElement.query(By.directive(BannerComponent));
expect(banner.componentInstance.bannerType).toBe("premium");
});
it("dismisses premium banner", async () => {
premiumBanner$.next(false);
fixture.detectChanges();
const banner = fixture.debugElement.query(By.directive(BannerComponent));
expect(banner).toBeNull();
});
});
describe("determineVisibleBanner", () => {
[
{
name: "Premium",
method: bannerService.shouldShowPremiumBanner,
banner: VisibleVaultBanner.Premium,
},
{
name: "OutdatedBrowser",
method: bannerService.shouldShowUpdateBrowserBanner,

View File

@ -1,4 +1,5 @@
import { Component, OnInit } from "@angular/core";
import { Observable } from "rxjs";
import { VaultBannersService, VisibleVaultBanner } from "./services/vault-banners.service";
@ -8,9 +9,12 @@ import { VaultBannersService, VisibleVaultBanner } from "./services/vault-banner
})
export class VaultBannersComponent implements OnInit {
visibleBanners: VisibleVaultBanner[] = [];
premiumBannerVisible$: Observable<boolean>;
VisibleVaultBanner = VisibleVaultBanner;
constructor(private vaultBannerService: VaultBannersService) {}
constructor(private vaultBannerService: VaultBannersService) {
this.premiumBannerVisible$ = this.vaultBannerService.shouldShowPremiumBanner();
}
async ngOnInit(): Promise<void> {
await this.determineVisibleBanners();
@ -27,13 +31,11 @@ export class VaultBannersComponent implements OnInit {
const showBrowserOutdated = await this.vaultBannerService.shouldShowUpdateBrowserBanner();
const showVerifyEmail = await this.vaultBannerService.shouldShowVerifyEmailBanner();
const showLowKdf = await this.vaultBannerService.shouldShowLowKDFBanner();
const showPremiumBanner = await this.vaultBannerService.shouldShowPremiumBanner();
this.visibleBanners = [
showBrowserOutdated ? VisibleVaultBanner.OutdatedBrowser : null,
showVerifyEmail ? VisibleVaultBanner.VerifyEmail : null,
showLowKdf ? VisibleVaultBanner.KDFSettings : null,
showPremiumBanner ? VisibleVaultBanner.Premium : null,
].filter(Boolean); // remove all falsy values, i.e. null
}
}