1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-21395] Vault Nudges Bugs (#14737)

* updates to empty vault and has items nudges
This commit is contained in:
Jason Ng
2025-05-13 16:49:41 -04:00
committed by GitHub
parent 393926beec
commit d68574fc40
7 changed files with 69 additions and 23 deletions

View File

@@ -4,7 +4,13 @@
<div class="tw-flex tw-justify-between tw-items-start tw-flex-grow">
<div>
<h2 bitTypography="h4" class="tw-font-semibold !tw-mb-1">{{ title }}</h2>
<p class="tw-text-main tw-mb-0" bitTypography="body2" [innerHTML]="subtitle"></p>
<p
*ngIf="subtitle"
class="tw-text-main tw-mb-0"
bitTypography="body2"
[innerHTML]="subtitle"
></p>
<ng-content *ngIf="!subtitle"></ng-content>
</div>
<button
type="button"

View File

@@ -14,7 +14,7 @@ export class SpotlightComponent {
// The title of the component
@Input({ required: true }) title: string | null = null;
// The subtitle of the component
@Input({ required: true }) subtitle: string | null = null;
@Input() subtitle?: string | null = null;
// The text to display on the button
@Input() buttonText?: string;
// Wheter the component can be dismissed, if true, the component will not show a close button

View File

@@ -28,7 +28,10 @@ export class EmptyVaultNudgeService extends DefaultSingleNudgeService {
this.collectionService.decryptedCollections$,
]).pipe(
switchMap(([nudgeStatus, ciphers, orgs, collections]) => {
const vaultHasContents = !(ciphers == null || ciphers.length === 0);
const filteredCiphers = ciphers?.filter((cipher) => {
return cipher.deletedDate == null;
});
const vaultHasContents = !(filteredCiphers == null || filteredCiphers.length === 0);
if (orgs == null || orgs.length === 0) {
return nudgeStatus.hasBadgeDismissed || nudgeStatus.hasSpotlightDismissed
? of(nudgeStatus)

View File

@@ -1,5 +1,6 @@
import { inject, Injectable } from "@angular/core";
import { combineLatest, Observable, switchMap } from "rxjs";
import { combineLatest, from, Observable, of, switchMap } from "rxjs";
import { catchError } from "rxjs/operators";
import { VaultProfileService } from "@bitwarden/angular/vault/services/vault-profile.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -9,6 +10,8 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
import { NudgeStatus, VaultNudgeType } from "../vault-nudges.service";
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
/**
* Custom Nudge Service Checking Nudge Status For Welcome Nudge With Populated Vault
*/
@@ -21,27 +24,42 @@ export class HasItemsNudgeService extends DefaultSingleNudgeService {
logService = inject(LogService);
nudgeStatus$(nudgeType: VaultNudgeType, userId: UserId): Observable<NudgeStatus> {
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
catchError(() => {
this.logService.error("Error getting profile creation date");
// Default to today to ensure we show the nudge
return of(new Date());
}),
);
return combineLatest([
this.cipherService.cipherViews$(userId),
this.getNudgeStatus$(nudgeType, userId),
profileDate$,
of(Date.now() - THIRTY_DAYS_MS),
]).pipe(
switchMap(async ([ciphers, nudgeStatus]) => {
try {
const creationDate = await this.vaultProfileService.getProfileCreationDate(userId);
const thirtyDays = new Date(new Date().getTime() - 30 * 24 * 60 * 60 * 1000);
const isRecentAcct = creationDate >= thirtyDays;
switchMap(async ([ciphers, nudgeStatus, profileDate, profileCutoff]) => {
const profileOlderThanCutoff = profileDate.getTime() < profileCutoff;
const filteredCiphers = ciphers?.filter((cipher) => {
return cipher.deletedDate == null;
});
if (!isRecentAcct || nudgeStatus.hasSpotlightDismissed) {
return nudgeStatus;
} else {
return {
hasBadgeDismissed: ciphers == null || ciphers.length === 0,
hasSpotlightDismissed: ciphers == null || ciphers.length === 0,
};
}
} catch (error) {
this.logService.error("Failed to fetch profile creation date: ", error);
if (profileOlderThanCutoff && filteredCiphers.length > 0) {
const dismissedStatus = {
hasSpotlightDismissed: true,
hasBadgeDismissed: true,
};
// permanently dismiss both the Empty Vault Nudge and Has Items Vault Nudge if the profile is older than 30 days
await this.setNudgeStatus(nudgeType, dismissedStatus, userId);
await this.setNudgeStatus(VaultNudgeType.EmptyVaultNudge, dismissedStatus, userId);
return dismissedStatus;
} else if (nudgeStatus.hasSpotlightDismissed) {
return nudgeStatus;
} else {
return {
hasBadgeDismissed: filteredCiphers == null || filteredCiphers.length === 0,
hasSpotlightDismissed: filteredCiphers == null || filteredCiphers.length === 0,
};
}
}),
);