mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
* 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`
122 lines
4.5 KiB
TypeScript
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;
|
|
}
|
|
}
|