1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00
Files
browser/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.ts
Nick Krantz 729d5d3134 [PM-21546] Migrate from enum to constant object (#14975)
* add generic `union-of-values` helper

* migrate `GeneratorDialogAction` to a constant

* migrate `VaultState` to a constant

* migrate `AtRiskCarouselDialogResult` to a constant

* migrate `CredentialGeneratorDialogAction` to a constant

* migrate `FolderAddEditDialogResult` to a constant

* migrate `ViewCipherDialogResult` to a constant

* migrate `VisibleVaultBanner` to a constant

* migrate `VaultFilterLabel` to a constant

* migrate `WebVaultGeneratorDialogResult` to a constant

* migrate `BulkDeleteDialogResult` to a constant

* migrate `BulkMoveDialogResult` to a constant

* migrate `AddEditCipherDialogResult` to a constant

* migrate `VaultItemDialogResult` to a constant

* migrate `BrowserPromptState` to a constant

* migrate `NudgeType` to a constant

* migrate `SecurityTaskStatus` to a constant

* migrate `CipherRepromptType` to a constant

* migrate `SecureNoteType` to a constant

* migrate `FieldType` to a constant

* migrate `LinkedIdType` to a constant

* migrate `CollectionAssignmentResult` to a constant

* migrate `AddEditFolderDialogResult` to a constant

* migrate `AttachmentDialogResult` to a constant

* fix CipherType in delete organization dialog

* fix `in` statement in VaultFilter

* Fix build errors across enum updates

* fix two more CipherType castings

* update CipherResponse `CipherType`

* define type for `fieldType` parameter

* refine how `cipherTypeNames` is generated and add utility function for grabbing cipher type name

* use `CipherType` rather than `number`

* add stricter typing for `FieldType`

* add fixme for `CipherType` to be ADR-0025 compliant

* remove error throw for `toCipherTypeName` and instead update typing to have `| undefined`

* add helpers for CipherType conversions

* prefer `undefined`
2025-06-05 08:45:52 -05:00

122 lines
4.5 KiB
TypeScript

import { Component, Input, OnInit } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { Router } from "@angular/router";
import { firstValueFrom, map, Observable, switchMap, filter } from "rxjs";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessageListener } from "@bitwarden/common/platform/messaging";
import { UserId } from "@bitwarden/common/types/guid";
import { BannerModule } from "@bitwarden/components";
import { VerifyEmailComponent } from "../../../auth/settings/verify-email.component";
import { FreeTrial } from "../../../billing/types/free-trial";
import { SharedModule } from "../../../shared";
import { VaultBannersService, VisibleVaultBanner } from "./services/vault-banners.service";
@Component({
selector: "app-vault-banners",
templateUrl: "./vault-banners.component.html",
imports: [VerifyEmailComponent, SharedModule, BannerModule],
providers: [VaultBannersService],
})
export class VaultBannersComponent implements OnInit {
visibleBanners: VisibleVaultBanner[] = [];
premiumBannerVisible$: Observable<boolean>;
VisibleVaultBanner = VisibleVaultBanner;
@Input() organizationsPaymentStatus: FreeTrial[] = [];
private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id));
constructor(
private vaultBannerService: VaultBannersService,
private router: Router,
private i18nService: I18nService,
private accountService: AccountService,
private messageListener: MessageListener,
) {
this.premiumBannerVisible$ = this.activeUserId$.pipe(
filter((userId): userId is UserId => userId != null),
switchMap((userId) => this.vaultBannerService.shouldShowPremiumBanner$(userId)),
);
// Listen for auth request messages and show banner immediately
this.messageListener.allMessages$
.pipe(
filter((message: { command: string }) => message.command === "openLoginApproval"),
takeUntilDestroyed(),
)
.subscribe(() => {
if (!this.visibleBanners.includes(VisibleVaultBanner.PendingAuthRequest)) {
this.visibleBanners = [...this.visibleBanners, VisibleVaultBanner.PendingAuthRequest];
}
});
}
async ngOnInit(): Promise<void> {
await this.determineVisibleBanners();
}
async dismissBanner(banner: VisibleVaultBanner): Promise<void> {
const activeUserId = await firstValueFrom(this.activeUserId$);
if (!activeUserId) {
return;
}
await this.vaultBannerService.dismissBanner(activeUserId, banner);
await this.determineVisibleBanners();
}
async navigateToPaymentMethod(organizationId: string): Promise<void> {
const navigationExtras = {
state: { launchPaymentModalAutomatically: true },
};
await this.router.navigate(
["organizations", organizationId, "billing", "payment-method"],
navigationExtras,
);
}
/** Determine which banners should be present */
async determineVisibleBanners(): Promise<void> {
const activeUserId = await firstValueFrom(this.activeUserId$);
if (!activeUserId) {
return;
}
const showBrowserOutdated =
await this.vaultBannerService.shouldShowUpdateBrowserBanner(activeUserId);
const showVerifyEmail = await this.vaultBannerService.shouldShowVerifyEmailBanner(activeUserId);
const showLowKdf = await this.vaultBannerService.shouldShowLowKDFBanner(activeUserId);
const showPendingAuthRequest =
await this.vaultBannerService.shouldShowPendingAuthRequestBanner(activeUserId);
this.visibleBanners = [
showBrowserOutdated ? VisibleVaultBanner.OutdatedBrowser : null,
showVerifyEmail ? VisibleVaultBanner.VerifyEmail : null,
showLowKdf ? VisibleVaultBanner.KDFSettings : null,
showPendingAuthRequest ? VisibleVaultBanner.PendingAuthRequest : null,
].filter((banner) => banner !== null);
}
freeTrialMessage(organization: FreeTrial) {
if (organization.remainingDays >= 2) {
return this.i18nService.t(
"freeTrialEndPromptMultipleDays",
organization.organizationName,
organization.remainingDays.toString(),
);
} else if (organization.remainingDays === 1) {
return this.i18nService.t("freeTrialEndPromptTomorrow", organization.organizationName);
} else {
return this.i18nService.t("freeTrialEndPromptToday", organization.organizationName);
}
}
trackBy(index: number) {
return index;
}
}