mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 22:03:36 +00:00
[PM-21663] nudge service name refactor (#14789)
* update names of vault nudge service and their corresponding files, convert components using showNudge$ to instead target spotlight and badges directly with new observables. Core logic for dismiss remains the same
This commit is contained in:
@@ -4,14 +4,14 @@ import { CommonModule } from "@angular/common";
|
|||||||
import { Component, DestroyRef, OnInit } from "@angular/core";
|
import { Component, DestroyRef, OnInit } from "@angular/core";
|
||||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
import {
|
import {
|
||||||
|
FormBuilder,
|
||||||
|
FormControl,
|
||||||
|
FormGroup,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
FormBuilder,
|
|
||||||
FormGroup,
|
|
||||||
FormControl,
|
|
||||||
} from "@angular/forms";
|
} from "@angular/forms";
|
||||||
import { RouterModule } from "@angular/router";
|
import { RouterModule } from "@angular/router";
|
||||||
import { Observable, filter, firstValueFrom, map, switchMap } from "rxjs";
|
import { filter, firstValueFrom, Observable, switchMap } from "rxjs";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
@@ -55,7 +55,7 @@ import {
|
|||||||
SelectModule,
|
SelectModule,
|
||||||
TypographyModule,
|
TypographyModule,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import { SpotlightComponent, VaultNudgesService, VaultNudgeType } from "@bitwarden/vault";
|
import { NudgesService, NudgeType, SpotlightComponent } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { AutofillBrowserSettingsService } from "../../../autofill/services/autofill-browser-settings.service";
|
import { AutofillBrowserSettingsService } from "../../../autofill/services/autofill-browser-settings.service";
|
||||||
import { BrowserApi } from "../../../platform/browser/browser-api";
|
import { BrowserApi } from "../../../platform/browser/browser-api";
|
||||||
@@ -108,9 +108,7 @@ export class AutofillComponent implements OnInit {
|
|||||||
protected showSpotlightNudge$: Observable<boolean> = this.accountService.activeAccount$.pipe(
|
protected showSpotlightNudge$: Observable<boolean> = this.accountService.activeAccount$.pipe(
|
||||||
filter((account): account is Account => account !== null),
|
filter((account): account is Account => account !== null),
|
||||||
switchMap((account) =>
|
switchMap((account) =>
|
||||||
this.vaultNudgesService
|
this.nudgesService.showNudgeSpotlight$(NudgeType.AutofillNudge, account.id),
|
||||||
.showNudge$(VaultNudgeType.AutofillNudge, account.id)
|
|
||||||
.pipe(map((nudgeStatus) => !nudgeStatus.hasSpotlightDismissed)),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -155,7 +153,7 @@ export class AutofillComponent implements OnInit {
|
|||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private destroyRef: DestroyRef,
|
private destroyRef: DestroyRef,
|
||||||
private vaultNudgesService: VaultNudgesService,
|
private nudgesService: NudgesService,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
private autofillBrowserSettingsService: AutofillBrowserSettingsService,
|
private autofillBrowserSettingsService: AutofillBrowserSettingsService,
|
||||||
) {
|
) {
|
||||||
@@ -343,8 +341,8 @@ export class AutofillComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async dismissSpotlight() {
|
async dismissSpotlight() {
|
||||||
await this.vaultNudgesService.dismissNudge(
|
await this.nudgesService.dismissNudge(
|
||||||
VaultNudgeType.AutofillNudge,
|
NudgeType.AutofillNudge,
|
||||||
await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)),
|
await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
|||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { Icons } from "@bitwarden/components";
|
import { Icons } from "@bitwarden/components";
|
||||||
import { VaultNudgesService } from "@bitwarden/vault";
|
import { NudgesService } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { NavButton } from "../platform/popup/layout/popup-tab-navigation.component";
|
import { NavButton } from "../platform/popup/layout/popup-tab-navigation.component";
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ import { NavButton } from "../platform/popup/layout/popup-tab-navigation.compone
|
|||||||
export class TabsV2Component {
|
export class TabsV2Component {
|
||||||
private hasActiveBadges$ = this.accountService.activeAccount$
|
private hasActiveBadges$ = this.accountService.activeAccount$
|
||||||
.pipe(getUserId)
|
.pipe(getUserId)
|
||||||
.pipe(switchMap((userId) => this.vaultNudgesService.hasActiveBadges$(userId)));
|
.pipe(switchMap((userId) => this.nudgesService.hasActiveBadges$(userId)));
|
||||||
protected navButtons$: Observable<NavButton[]> = combineLatest([
|
protected navButtons$: Observable<NavButton[]> = combineLatest([
|
||||||
this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge),
|
this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge),
|
||||||
this.hasActiveBadges$,
|
this.hasActiveBadges$,
|
||||||
@@ -54,7 +54,7 @@ export class TabsV2Component {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
constructor(
|
constructor(
|
||||||
private vaultNudgesService: VaultNudgesService,
|
private nudgesService: NudgesService,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<a
|
<a
|
||||||
bit-item-content
|
bit-item-content
|
||||||
routerLink="/vault-settings"
|
routerLink="/vault-settings"
|
||||||
(click)="dismissBadge(VaultNudgeType.EmptyVaultNudge)"
|
(click)="dismissBadge(NudgeType.EmptyVaultNudge)"
|
||||||
>
|
>
|
||||||
<i slot="start" class="bwi bwi-vault" aria-hidden="true"></i>
|
<i slot="start" class="bwi bwi-vault" aria-hidden="true"></i>
|
||||||
<div class="tw-flex tw-items-center tw-justify-center">
|
<div class="tw-flex tw-items-center tw-justify-center">
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
Will make this dynamic when more nudges are added
|
Will make this dynamic when more nudges are added
|
||||||
-->
|
-->
|
||||||
<span
|
<span
|
||||||
*ngIf="!(showVaultBadge$ | async)?.hasBadgeDismissed"
|
*ngIf="showVaultBadge$ | async"
|
||||||
bitBadge
|
bitBadge
|
||||||
variant="notification"
|
variant="notification"
|
||||||
[attr.aria-label]="'nudgeBadgeAria' | i18n"
|
[attr.aria-label]="'nudgeBadgeAria' | i18n"
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
<div class="tw-flex tw-items-center tw-justify-center">
|
<div class="tw-flex tw-items-center tw-justify-center">
|
||||||
<p class="tw-pr-2">{{ "downloadBitwardenOnAllDevices" | i18n }}</p>
|
<p class="tw-pr-2">{{ "downloadBitwardenOnAllDevices" | i18n }}</p>
|
||||||
<span
|
<span
|
||||||
*ngIf="(downloadBitwardenNudgeStatus$ | async)?.hasBadgeDismissed === false"
|
*ngIf="downloadBitwardenNudgeStatus$ | async"
|
||||||
bitBadge
|
bitBadge
|
||||||
variant="notification"
|
variant="notification"
|
||||||
[attr.aria-label]="'nudgeBadgeAria' | i18n"
|
[attr.aria-label]="'nudgeBadgeAria' | i18n"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
|||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { BadgeComponent, ItemModule } from "@bitwarden/components";
|
import { BadgeComponent, ItemModule } from "@bitwarden/components";
|
||||||
import { NudgeStatus, VaultNudgesService, VaultNudgeType } from "@bitwarden/vault";
|
import { NudgesService, NudgeType } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component";
|
import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component";
|
||||||
import { AutofillBrowserSettingsService } from "../../../autofill/services/autofill-browser-settings.service";
|
import { AutofillBrowserSettingsService } from "../../../autofill/services/autofill-browser-settings.service";
|
||||||
@@ -42,7 +42,7 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SettingsV2Component implements OnInit {
|
export class SettingsV2Component implements OnInit {
|
||||||
VaultNudgeType = VaultNudgeType;
|
NudgeType = NudgeType;
|
||||||
activeUserId: UserId | null = null;
|
activeUserId: UserId | null = null;
|
||||||
protected isBrowserAutofillSettingOverridden = false;
|
protected isBrowserAutofillSettingOverridden = false;
|
||||||
|
|
||||||
@@ -51,15 +51,15 @@ export class SettingsV2Component implements OnInit {
|
|||||||
shareReplay({ bufferSize: 1, refCount: true }),
|
shareReplay({ bufferSize: 1, refCount: true }),
|
||||||
);
|
);
|
||||||
|
|
||||||
downloadBitwardenNudgeStatus$: Observable<NudgeStatus> = this.authenticatedAccount$.pipe(
|
downloadBitwardenNudgeStatus$: Observable<boolean> = this.authenticatedAccount$.pipe(
|
||||||
switchMap((account) =>
|
switchMap((account) =>
|
||||||
this.vaultNudgesService.showNudge$(VaultNudgeType.DownloadBitwarden, account.id),
|
this.nudgesService.showNudgeBadge$(NudgeType.DownloadBitwarden, account.id),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
showVaultBadge$: Observable<NudgeStatus> = this.authenticatedAccount$.pipe(
|
showVaultBadge$: Observable<boolean> = this.authenticatedAccount$.pipe(
|
||||||
switchMap((account) =>
|
switchMap((account) =>
|
||||||
this.vaultNudgesService.showNudge$(VaultNudgeType.EmptyVaultNudge, account.id),
|
this.nudgesService.showNudgeBadge$(NudgeType.EmptyVaultNudge, account.id),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -68,9 +68,9 @@ export class SettingsV2Component implements OnInit {
|
|||||||
this.authenticatedAccount$,
|
this.authenticatedAccount$,
|
||||||
]).pipe(
|
]).pipe(
|
||||||
switchMap(([defaultBrowserAutofillDisabled, account]) =>
|
switchMap(([defaultBrowserAutofillDisabled, account]) =>
|
||||||
this.vaultNudgesService.showNudge$(VaultNudgeType.AutofillNudge, account.id).pipe(
|
this.nudgesService.showNudgeBadge$(NudgeType.AutofillNudge, account.id).pipe(
|
||||||
map((nudgeStatus) => {
|
map((badgeStatus) => {
|
||||||
return !defaultBrowserAutofillDisabled && nudgeStatus.hasBadgeDismissed === false;
|
return !defaultBrowserAutofillDisabled && badgeStatus;
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -81,7 +81,7 @@ export class SettingsV2Component implements OnInit {
|
|||||||
);
|
);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly vaultNudgesService: VaultNudgesService,
|
private readonly nudgesService: NudgesService,
|
||||||
private readonly accountService: AccountService,
|
private readonly accountService: AccountService,
|
||||||
private readonly autofillBrowserSettingsService: AutofillBrowserSettingsService,
|
private readonly autofillBrowserSettingsService: AutofillBrowserSettingsService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
@@ -94,10 +94,10 @@ export class SettingsV2Component implements OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async dismissBadge(type: VaultNudgeType) {
|
async dismissBadge(type: NudgeType) {
|
||||||
if (!(await firstValueFrom(this.showVaultBadge$)).hasBadgeDismissed) {
|
if (await firstValueFrom(this.showVaultBadge$)) {
|
||||||
const account = await firstValueFrom(this.authenticatedAccount$);
|
const account = await firstValueFrom(this.authenticatedAccount$);
|
||||||
await this.vaultNudgesService.dismissNudge(type, account.id as UserId, true);
|
await this.nudgesService.dismissNudge(type, account.id as UserId, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
[subtitle]="'emptyVaultNudgeBody' | i18n"
|
[subtitle]="'emptyVaultNudgeBody' | i18n"
|
||||||
[buttonText]="'emptyVaultNudgeButton' | i18n"
|
[buttonText]="'emptyVaultNudgeButton' | i18n"
|
||||||
(onButtonClick)="navigateToImport()"
|
(onButtonClick)="navigateToImport()"
|
||||||
(onDismiss)="dismissVaultNudgeSpotlight(VaultNudgeType.EmptyVaultNudge)"
|
(onDismiss)="dismissVaultNudgeSpotlight(NudgeType.EmptyVaultNudge)"
|
||||||
>
|
>
|
||||||
</bit-spotlight>
|
</bit-spotlight>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<div class="tw-mb-4" *ngIf="showHasItemsVaultSpotlight$ | async">
|
<div class="tw-mb-4" *ngIf="showHasItemsVaultSpotlight$ | async">
|
||||||
<bit-spotlight
|
<bit-spotlight
|
||||||
[title]="'hasItemsVaultNudgeTitle' | i18n"
|
[title]="'hasItemsVaultNudgeTitle' | i18n"
|
||||||
(onDismiss)="dismissVaultNudgeSpotlight(VaultNudgeType.HasVaultItems)"
|
(onDismiss)="dismissVaultNudgeSpotlight(NudgeType.HasVaultItems)"
|
||||||
>
|
>
|
||||||
<ul class="tw-pl-4 tw-text-main" bitTypography="body2">
|
<ul class="tw-pl-4 tw-text-main" bitTypography="body2">
|
||||||
<li>{{ "hasItemsVaultNudgeBodyOne" | i18n }}</li>
|
<li>{{ "hasItemsVaultNudgeBodyOne" | i18n }}</li>
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ import {
|
|||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import {
|
import {
|
||||||
DecryptionFailureDialogComponent,
|
DecryptionFailureDialogComponent,
|
||||||
|
NudgesService,
|
||||||
|
NudgeType,
|
||||||
SpotlightComponent,
|
SpotlightComponent,
|
||||||
VaultIcons,
|
VaultIcons,
|
||||||
VaultNudgesService,
|
|
||||||
VaultNudgeType,
|
|
||||||
} from "@bitwarden/vault";
|
} from "@bitwarden/vault";
|
||||||
|
|
||||||
import { CurrentAccountComponent } from "../../../../auth/popup/account-switching/current-account.component";
|
import { CurrentAccountComponent } from "../../../../auth/popup/account-switching/current-account.component";
|
||||||
@@ -96,18 +96,16 @@ enum VaultState {
|
|||||||
export class VaultV2Component implements OnInit, AfterViewInit, OnDestroy {
|
export class VaultV2Component implements OnInit, AfterViewInit, OnDestroy {
|
||||||
@ViewChild(CdkVirtualScrollableElement) virtualScrollElement?: CdkVirtualScrollableElement;
|
@ViewChild(CdkVirtualScrollableElement) virtualScrollElement?: CdkVirtualScrollableElement;
|
||||||
|
|
||||||
VaultNudgeType = VaultNudgeType;
|
NudgeType = NudgeType;
|
||||||
cipherType = CipherType;
|
cipherType = CipherType;
|
||||||
private activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
|
private activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
|
||||||
showEmptyVaultSpotlight$: Observable<boolean> = this.activeUserId$.pipe(
|
showEmptyVaultSpotlight$: Observable<boolean> = this.activeUserId$.pipe(
|
||||||
switchMap((userId) =>
|
switchMap((userId) =>
|
||||||
this.vaultNudgesService.showNudge$(VaultNudgeType.EmptyVaultNudge, userId),
|
this.nudgesService.showNudgeSpotlight$(NudgeType.EmptyVaultNudge, userId),
|
||||||
),
|
),
|
||||||
map((nudgeStatus) => !nudgeStatus.hasSpotlightDismissed),
|
|
||||||
);
|
);
|
||||||
showHasItemsVaultSpotlight$: Observable<boolean> = this.activeUserId$.pipe(
|
showHasItemsVaultSpotlight$: Observable<boolean> = this.activeUserId$.pipe(
|
||||||
switchMap((userId) => this.vaultNudgesService.showNudge$(VaultNudgeType.HasVaultItems, userId)),
|
switchMap((userId) => this.nudgesService.showNudgeSpotlight$(NudgeType.HasVaultItems, userId)),
|
||||||
map((nudgeStatus) => !nudgeStatus.hasSpotlightDismissed),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
activeUserId: UserId | null = null;
|
activeUserId: UserId | null = null;
|
||||||
@@ -159,7 +157,7 @@ export class VaultV2Component implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
private vaultCopyButtonsService: VaultPopupCopyButtonsService,
|
private vaultCopyButtonsService: VaultPopupCopyButtonsService,
|
||||||
private introCarouselService: IntroCarouselService,
|
private introCarouselService: IntroCarouselService,
|
||||||
private vaultNudgesService: VaultNudgesService,
|
private nudgesService: NudgesService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
) {
|
) {
|
||||||
@@ -229,8 +227,8 @@ export class VaultV2Component implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async dismissVaultNudgeSpotlight(type: VaultNudgeType) {
|
async dismissVaultNudgeSpotlight(type: NudgeType) {
|
||||||
await this.vaultNudgesService.dismissNudge(type, this.activeUserId as UserId);
|
await this.nudgesService.dismissNudge(type, this.activeUserId as UserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected readonly FeatureFlag = FeatureFlag;
|
protected readonly FeatureFlag = FeatureFlag;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { JslibModule } from "@bitwarden/angular/jslib.module";
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||||
import { CardComponent, LinkModule, TypographyModule } from "@bitwarden/components";
|
import { CardComponent, LinkModule, TypographyModule } from "@bitwarden/components";
|
||||||
import { VaultNudgesService, VaultNudgeType } from "@bitwarden/vault";
|
import { NudgesService, NudgeType } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component";
|
import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component";
|
||||||
import { PopOutComponent } from "../../../platform/popup/components/pop-out.component";
|
import { PopOutComponent } from "../../../platform/popup/components/pop-out.component";
|
||||||
@@ -32,12 +32,12 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co
|
|||||||
})
|
})
|
||||||
export class DownloadBitwardenComponent implements OnInit {
|
export class DownloadBitwardenComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private vaultNudgeService: VaultNudgesService,
|
private nudgesService: NudgesService,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||||
await this.vaultNudgeService.dismissNudge(VaultNudgeType.DownloadBitwarden, userId);
|
await this.nudgesService.dismissNudge(NudgeType.DownloadBitwarden, userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ export const VAULT_APPEARANCE = new StateDefinition("vaultAppearance", "disk");
|
|||||||
export const SECURITY_TASKS_DISK = new StateDefinition("securityTasks", "disk");
|
export const SECURITY_TASKS_DISK = new StateDefinition("securityTasks", "disk");
|
||||||
export const AT_RISK_PASSWORDS_PAGE_DISK = new StateDefinition("atRiskPasswordsPage", "disk");
|
export const AT_RISK_PASSWORDS_PAGE_DISK = new StateDefinition("atRiskPasswordsPage", "disk");
|
||||||
export const NOTIFICATION_DISK = new StateDefinition("notifications", "disk");
|
export const NOTIFICATION_DISK = new StateDefinition("notifications", "disk");
|
||||||
export const VAULT_NUDGES_DISK = new StateDefinition("vaultNudges", "disk", { web: "disk-local" });
|
export const NUDGES_DISK = new StateDefinition("nudges", "disk", { web: "disk-local" });
|
||||||
export const VAULT_BROWSER_INTRO_CAROUSEL = new StateDefinition(
|
export const VAULT_BROWSER_INTRO_CAROUSEL = new StateDefinition(
|
||||||
"vaultBrowserIntroCarousel",
|
"vaultBrowserIntroCarousel",
|
||||||
"disk",
|
"disk",
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import {
|
|||||||
CipherFormGenerationService,
|
CipherFormGenerationService,
|
||||||
NudgeStatus,
|
NudgeStatus,
|
||||||
PasswordRepromptService,
|
PasswordRepromptService,
|
||||||
VaultNudgesService,
|
NudgesService,
|
||||||
} from "@bitwarden/vault";
|
} from "@bitwarden/vault";
|
||||||
// FIXME: remove `/apps` import from `/libs`
|
// FIXME: remove `/apps` import from `/libs`
|
||||||
// FIXME: remove `src` and fix import
|
// FIXME: remove `src` and fix import
|
||||||
@@ -144,7 +144,7 @@ export default {
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: VaultNudgesService,
|
provide: NudgesService,
|
||||||
useValue: {
|
useValue: {
|
||||||
showNudge$: new BehaviorSubject({
|
showNudge$: new BehaviorSubject({
|
||||||
hasBadgeDismissed: true,
|
hasBadgeDismissed: true,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { CipherType } from "@bitwarden/sdk-internal";
|
import { CipherType } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
import { VaultNudgesService, VaultNudgeType } from "../../../services/vault-nudges.service";
|
import { NudgesService, NudgeType } from "../../../services/nudges.service";
|
||||||
|
|
||||||
import { NewItemNudgeComponent } from "./new-item-nudge.component";
|
import { NewItemNudgeComponent } from "./new-item-nudge.component";
|
||||||
|
|
||||||
@@ -18,19 +18,19 @@ describe("NewItemNudgeComponent", () => {
|
|||||||
|
|
||||||
let i18nService: MockProxy<I18nService>;
|
let i18nService: MockProxy<I18nService>;
|
||||||
let accountService: MockProxy<AccountService>;
|
let accountService: MockProxy<AccountService>;
|
||||||
let vaultNudgesService: MockProxy<VaultNudgesService>;
|
let nudgesService: MockProxy<NudgesService>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
i18nService = mock<I18nService>({ t: (key: string) => key });
|
i18nService = mock<I18nService>({ t: (key: string) => key });
|
||||||
accountService = mock<AccountService>();
|
accountService = mock<AccountService>();
|
||||||
vaultNudgesService = mock<VaultNudgesService>();
|
nudgesService = mock<NudgesService>();
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [NewItemNudgeComponent, CommonModule],
|
imports: [NewItemNudgeComponent, CommonModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: I18nService, useValue: i18nService },
|
{ provide: I18nService, useValue: i18nService },
|
||||||
{ provide: AccountService, useValue: accountService },
|
{ provide: AccountService, useValue: accountService },
|
||||||
{ provide: VaultNudgesService, useValue: vaultNudgesService },
|
{ provide: NudgesService, useValue: nudgesService },
|
||||||
],
|
],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
});
|
});
|
||||||
@@ -58,7 +58,7 @@ describe("NewItemNudgeComponent", () => {
|
|||||||
expect(component.nudgeBody).toBe(
|
expect(component.nudgeBody).toBe(
|
||||||
"newLoginNudgeBodyOne <strong>newLoginNudgeBodyBold</strong> newLoginNudgeBodyTwo",
|
"newLoginNudgeBodyOne <strong>newLoginNudgeBodyBold</strong> newLoginNudgeBodyTwo",
|
||||||
);
|
);
|
||||||
expect(component.dismissalNudgeType).toBe(VaultNudgeType.newLoginItemStatus);
|
expect(component.dismissalNudgeType).toBe(NudgeType.NewLoginItemStatus);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set nudge title and body for CipherType.Card type", async () => {
|
it("should set nudge title and body for CipherType.Card type", async () => {
|
||||||
@@ -71,7 +71,7 @@ describe("NewItemNudgeComponent", () => {
|
|||||||
expect(component.showNewItemSpotlight).toBe(true);
|
expect(component.showNewItemSpotlight).toBe(true);
|
||||||
expect(component.nudgeTitle).toBe("newCardNudgeTitle");
|
expect(component.nudgeTitle).toBe("newCardNudgeTitle");
|
||||||
expect(component.nudgeBody).toBe("newCardNudgeBody");
|
expect(component.nudgeBody).toBe("newCardNudgeBody");
|
||||||
expect(component.dismissalNudgeType).toBe(VaultNudgeType.newCardItemStatus);
|
expect(component.dismissalNudgeType).toBe(NudgeType.NewCardItemStatus);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not show anything if spotlight has been dismissed", async () => {
|
it("should not show anything if spotlight has been dismissed", async () => {
|
||||||
@@ -82,22 +82,19 @@ describe("NewItemNudgeComponent", () => {
|
|||||||
await component.ngOnInit();
|
await component.ngOnInit();
|
||||||
|
|
||||||
expect(component.showNewItemSpotlight).toBe(false);
|
expect(component.showNewItemSpotlight).toBe(false);
|
||||||
expect(component.dismissalNudgeType).toBe(VaultNudgeType.newIdentityItemStatus);
|
expect(component.dismissalNudgeType).toBe(NudgeType.NewIdentityItemStatus);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set showNewItemSpotlight to false when user dismisses spotlight", async () => {
|
it("should set showNewItemSpotlight to false when user dismisses spotlight", async () => {
|
||||||
component.showNewItemSpotlight = true;
|
component.showNewItemSpotlight = true;
|
||||||
component.dismissalNudgeType = VaultNudgeType.newLoginItemStatus;
|
component.dismissalNudgeType = NudgeType.NewLoginItemStatus;
|
||||||
component.activeUserId = "test-user-id" as UserId;
|
component.activeUserId = "test-user-id" as UserId;
|
||||||
|
|
||||||
const dismissSpy = jest.spyOn(vaultNudgesService, "dismissNudge").mockResolvedValue();
|
const dismissSpy = jest.spyOn(nudgesService, "dismissNudge").mockResolvedValue();
|
||||||
|
|
||||||
await component.dismissNewItemSpotlight();
|
await component.dismissNewItemSpotlight();
|
||||||
|
|
||||||
expect(component.showNewItemSpotlight).toBe(false);
|
expect(component.showNewItemSpotlight).toBe(false);
|
||||||
expect(dismissSpy).toHaveBeenCalledWith(
|
expect(dismissSpy).toHaveBeenCalledWith(NudgeType.NewLoginItemStatus, component.activeUserId);
|
||||||
VaultNudgeType.newLoginItemStatus,
|
|
||||||
component.activeUserId,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { UserId } from "@bitwarden/common/types/guid";
|
|||||||
import { CipherType } from "@bitwarden/sdk-internal";
|
import { CipherType } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
import { SpotlightComponent } from "../../../components/spotlight/spotlight.component";
|
import { SpotlightComponent } from "../../../components/spotlight/spotlight.component";
|
||||||
import { VaultNudgesService, VaultNudgeType } from "../../../services/vault-nudges.service";
|
import { NudgesService, NudgeType } from "../../../services/nudges.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "vault-new-item-nudge",
|
selector: "vault-new-item-nudge",
|
||||||
@@ -23,12 +23,12 @@ export class NewItemNudgeComponent implements OnInit {
|
|||||||
showNewItemSpotlight: boolean = false;
|
showNewItemSpotlight: boolean = false;
|
||||||
nudgeTitle: string = "";
|
nudgeTitle: string = "";
|
||||||
nudgeBody: string = "";
|
nudgeBody: string = "";
|
||||||
dismissalNudgeType: VaultNudgeType | null = null;
|
dismissalNudgeType: NudgeType | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
private vaultNudgesService: VaultNudgesService,
|
private nudgesService: NudgesService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -39,25 +39,25 @@ export class NewItemNudgeComponent implements OnInit {
|
|||||||
const nudgeBodyOne = this.i18nService.t("newLoginNudgeBodyOne");
|
const nudgeBodyOne = this.i18nService.t("newLoginNudgeBodyOne");
|
||||||
const nudgeBodyBold = this.i18nService.t("newLoginNudgeBodyBold");
|
const nudgeBodyBold = this.i18nService.t("newLoginNudgeBodyBold");
|
||||||
const nudgeBodyTwo = this.i18nService.t("newLoginNudgeBodyTwo");
|
const nudgeBodyTwo = this.i18nService.t("newLoginNudgeBodyTwo");
|
||||||
this.dismissalNudgeType = VaultNudgeType.newLoginItemStatus;
|
this.dismissalNudgeType = NudgeType.NewLoginItemStatus;
|
||||||
this.nudgeTitle = this.i18nService.t("newLoginNudgeTitle");
|
this.nudgeTitle = this.i18nService.t("newLoginNudgeTitle");
|
||||||
this.nudgeBody = `${nudgeBodyOne} <strong>${nudgeBodyBold}</strong> ${nudgeBodyTwo}`;
|
this.nudgeBody = `${nudgeBodyOne} <strong>${nudgeBodyBold}</strong> ${nudgeBodyTwo}`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CipherType.Card:
|
case CipherType.Card:
|
||||||
this.dismissalNudgeType = VaultNudgeType.newCardItemStatus;
|
this.dismissalNudgeType = NudgeType.NewCardItemStatus;
|
||||||
this.nudgeTitle = this.i18nService.t("newCardNudgeTitle");
|
this.nudgeTitle = this.i18nService.t("newCardNudgeTitle");
|
||||||
this.nudgeBody = this.i18nService.t("newCardNudgeBody");
|
this.nudgeBody = this.i18nService.t("newCardNudgeBody");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
this.dismissalNudgeType = VaultNudgeType.newIdentityItemStatus;
|
this.dismissalNudgeType = NudgeType.NewIdentityItemStatus;
|
||||||
this.nudgeTitle = this.i18nService.t("newIdentityNudgeTitle");
|
this.nudgeTitle = this.i18nService.t("newIdentityNudgeTitle");
|
||||||
this.nudgeBody = this.i18nService.t("newIdentityNudgeBody");
|
this.nudgeBody = this.i18nService.t("newIdentityNudgeBody");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CipherType.SecureNote:
|
case CipherType.SecureNote:
|
||||||
this.dismissalNudgeType = VaultNudgeType.newNoteItemStatus;
|
this.dismissalNudgeType = NudgeType.NewNoteItemStatus;
|
||||||
this.nudgeTitle = this.i18nService.t("newNoteNudgeTitle");
|
this.nudgeTitle = this.i18nService.t("newNoteNudgeTitle");
|
||||||
this.nudgeBody = this.i18nService.t("newNoteNudgeBody");
|
this.nudgeBody = this.i18nService.t("newNoteNudgeBody");
|
||||||
break;
|
break;
|
||||||
@@ -66,7 +66,7 @@ export class NewItemNudgeComponent implements OnInit {
|
|||||||
const sshPartOne = this.i18nService.t("newSshNudgeBodyOne");
|
const sshPartOne = this.i18nService.t("newSshNudgeBodyOne");
|
||||||
const sshPartTwo = this.i18nService.t("newSshNudgeBodyTwo");
|
const sshPartTwo = this.i18nService.t("newSshNudgeBodyTwo");
|
||||||
|
|
||||||
this.dismissalNudgeType = VaultNudgeType.newSshItemStatus;
|
this.dismissalNudgeType = NudgeType.NewSshItemStatus;
|
||||||
this.nudgeTitle = this.i18nService.t("newSshNudgeTitle");
|
this.nudgeTitle = this.i18nService.t("newSshNudgeTitle");
|
||||||
this.nudgeBody = `${sshPartOne} <a href="https://bitwarden.com/help/ssh-agent" class="tw-text-primary-600 tw-font-bold" target="_blank">${sshPartTwo}</a>`;
|
this.nudgeBody = `${sshPartOne} <a href="https://bitwarden.com/help/ssh-agent" class="tw-text-primary-600 tw-font-bold" target="_blank">${sshPartTwo}</a>`;
|
||||||
break;
|
break;
|
||||||
@@ -75,23 +75,19 @@ export class NewItemNudgeComponent implements OnInit {
|
|||||||
throw new Error("Unsupported cipher type");
|
throw new Error("Unsupported cipher type");
|
||||||
}
|
}
|
||||||
this.showNewItemSpotlight = await this.checkHasSpotlightDismissed(
|
this.showNewItemSpotlight = await this.checkHasSpotlightDismissed(
|
||||||
this.dismissalNudgeType as VaultNudgeType,
|
this.dismissalNudgeType as NudgeType,
|
||||||
this.activeUserId,
|
this.activeUserId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async dismissNewItemSpotlight() {
|
async dismissNewItemSpotlight() {
|
||||||
if (this.dismissalNudgeType && this.activeUserId) {
|
if (this.dismissalNudgeType && this.activeUserId) {
|
||||||
await this.vaultNudgesService.dismissNudge(
|
await this.nudgesService.dismissNudge(this.dismissalNudgeType, this.activeUserId as UserId);
|
||||||
this.dismissalNudgeType,
|
|
||||||
this.activeUserId as UserId,
|
|
||||||
);
|
|
||||||
this.showNewItemSpotlight = false;
|
this.showNewItemSpotlight = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkHasSpotlightDismissed(nudgeType: VaultNudgeType, userId: UserId): Promise<boolean> {
|
async checkHasSpotlightDismissed(nudgeType: NudgeType, userId: UserId): Promise<boolean> {
|
||||||
return !(await firstValueFrom(this.vaultNudgesService.showNudge$(nudgeType, userId)))
|
return await firstValueFrom(this.nudgesService.showNudgeSpotlight$(nudgeType, userId));
|
||||||
.hasSpotlightDismissed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export * from "./components/add-edit-folder-dialog/add-edit-folder-dialog.compon
|
|||||||
export * from "./components/carousel";
|
export * from "./components/carousel";
|
||||||
|
|
||||||
export * as VaultIcons from "./icons";
|
export * as VaultIcons from "./icons";
|
||||||
export * from "./services/vault-nudges.service";
|
export * from "./services/nudges.service";
|
||||||
export * from "./services/custom-nudges-services";
|
export * from "./services/custom-nudges-services";
|
||||||
|
|
||||||
export { DefaultSshImportPromptService } from "./services/default-ssh-import-prompt.service";
|
export { DefaultSshImportPromptService } from "./services/default-ssh-import-prompt.service";
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
|||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
|
|
||||||
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
||||||
import { NudgeStatus, VaultNudgeType } from "../vault-nudges.service";
|
import { NudgeStatus, NudgeType } from "../nudges.service";
|
||||||
|
|
||||||
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ export class AutofillNudgeService extends DefaultSingleNudgeService {
|
|||||||
vaultProfileService = inject(VaultProfileService);
|
vaultProfileService = inject(VaultProfileService);
|
||||||
logService = inject(LogService);
|
logService = inject(LogService);
|
||||||
|
|
||||||
nudgeStatus$(_: VaultNudgeType, userId: UserId): Observable<NudgeStatus> {
|
nudgeStatus$(_: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||||
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
|
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
|
||||||
catchError(() => {
|
catchError(() => {
|
||||||
this.logService.error("Error getting profile creation date");
|
this.logService.error("Error getting profile creation date");
|
||||||
@@ -32,7 +32,7 @@ export class AutofillNudgeService extends DefaultSingleNudgeService {
|
|||||||
|
|
||||||
return combineLatest([
|
return combineLatest([
|
||||||
profileDate$,
|
profileDate$,
|
||||||
this.getNudgeStatus$(VaultNudgeType.AutofillNudge, userId),
|
this.getNudgeStatus$(NudgeType.AutofillNudge, userId),
|
||||||
of(Date.now() - THIRTY_DAYS_MS),
|
of(Date.now() - THIRTY_DAYS_MS),
|
||||||
]).pipe(
|
]).pipe(
|
||||||
map(([profileCreationDate, status, profileCutoff]) => {
|
map(([profileCreationDate, status, profileCutoff]) => {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
|||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
|
|
||||||
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
||||||
import { NudgeStatus, VaultNudgeType } from "../vault-nudges.service";
|
import { NudgeStatus, NudgeType } from "../nudges.service";
|
||||||
|
|
||||||
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ export class DownloadBitwardenNudgeService extends DefaultSingleNudgeService {
|
|||||||
private vaultProfileService = inject(VaultProfileService);
|
private vaultProfileService = inject(VaultProfileService);
|
||||||
private logService = inject(LogService);
|
private logService = inject(LogService);
|
||||||
|
|
||||||
nudgeStatus$(nudgeType: VaultNudgeType, userId: UserId): Observable<NudgeStatus> {
|
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||||
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
|
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
|
||||||
catchError(() => {
|
catchError(() => {
|
||||||
this.logService.error("Failed to load profile date:");
|
this.logService.error("Failed to load profile date:");
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { UserId } from "@bitwarden/common/types/guid";
|
|||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
|
||||||
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
||||||
import { NudgeStatus, VaultNudgeType } from "../vault-nudges.service";
|
import { NudgeStatus, NudgeType } from "../nudges.service";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom Nudge Service Checking Nudge Status For Empty Vault
|
* Custom Nudge Service Checking Nudge Status For Empty Vault
|
||||||
@@ -20,7 +20,7 @@ export class EmptyVaultNudgeService extends DefaultSingleNudgeService {
|
|||||||
organizationService = inject(OrganizationService);
|
organizationService = inject(OrganizationService);
|
||||||
collectionService = inject(CollectionService);
|
collectionService = inject(CollectionService);
|
||||||
|
|
||||||
nudgeStatus$(nudgeType: VaultNudgeType, userId: UserId): Observable<NudgeStatus> {
|
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||||
return combineLatest([
|
return combineLatest([
|
||||||
this.getNudgeStatus$(nudgeType, userId),
|
this.getNudgeStatus$(nudgeType, userId),
|
||||||
this.cipherService.cipherViews$(userId),
|
this.cipherService.cipherViews$(userId),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { UserId } from "@bitwarden/common/types/guid";
|
|||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
|
||||||
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
||||||
import { NudgeStatus, VaultNudgeType } from "../vault-nudges.service";
|
import { NudgeStatus, NudgeType } from "../nudges.service";
|
||||||
|
|
||||||
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ export class HasItemsNudgeService extends DefaultSingleNudgeService {
|
|||||||
vaultProfileService = inject(VaultProfileService);
|
vaultProfileService = inject(VaultProfileService);
|
||||||
logService = inject(LogService);
|
logService = inject(LogService);
|
||||||
|
|
||||||
nudgeStatus$(nudgeType: VaultNudgeType, userId: UserId): Observable<NudgeStatus> {
|
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||||
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
|
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
|
||||||
catchError(() => {
|
catchError(() => {
|
||||||
this.logService.error("Error getting profile creation date");
|
this.logService.error("Error getting profile creation date");
|
||||||
@@ -51,7 +51,7 @@ export class HasItemsNudgeService extends DefaultSingleNudgeService {
|
|||||||
};
|
};
|
||||||
// permanently dismiss both the Empty Vault Nudge and Has Items Vault Nudge if the profile is older than 30 days
|
// 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(nudgeType, dismissedStatus, userId);
|
||||||
await this.setNudgeStatus(VaultNudgeType.EmptyVaultNudge, dismissedStatus, userId);
|
await this.setNudgeStatus(NudgeType.EmptyVaultNudge, dismissedStatus, userId);
|
||||||
return dismissedStatus;
|
return dismissedStatus;
|
||||||
} else if (nudgeStatus.hasSpotlightDismissed) {
|
} else if (nudgeStatus.hasSpotlightDismissed) {
|
||||||
return nudgeStatus;
|
return nudgeStatus;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi
|
|||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
|
|
||||||
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
||||||
import { NudgeStatus, VaultNudgeType } from "../vault-nudges.service";
|
import { NudgeStatus, NudgeType } from "../nudges.service";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom Nudge Service Checking Nudge Status For Vault New Item Types
|
* Custom Nudge Service Checking Nudge Status For Vault New Item Types
|
||||||
@@ -17,7 +17,7 @@ import { NudgeStatus, VaultNudgeType } from "../vault-nudges.service";
|
|||||||
export class NewItemNudgeService extends DefaultSingleNudgeService {
|
export class NewItemNudgeService extends DefaultSingleNudgeService {
|
||||||
cipherService = inject(CipherService);
|
cipherService = inject(CipherService);
|
||||||
|
|
||||||
nudgeStatus$(nudgeType: VaultNudgeType, userId: UserId): Observable<NudgeStatus> {
|
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||||
return combineLatest([
|
return combineLatest([
|
||||||
this.getNudgeStatus$(nudgeType, userId),
|
this.getNudgeStatus$(nudgeType, userId),
|
||||||
this.cipherService.cipherViews$(userId),
|
this.cipherService.cipherViews$(userId),
|
||||||
@@ -30,19 +30,19 @@ export class NewItemNudgeService extends DefaultSingleNudgeService {
|
|||||||
let currentType: CipherType;
|
let currentType: CipherType;
|
||||||
|
|
||||||
switch (nudgeType) {
|
switch (nudgeType) {
|
||||||
case VaultNudgeType.newLoginItemStatus:
|
case NudgeType.NewLoginItemStatus:
|
||||||
currentType = CipherType.Login;
|
currentType = CipherType.Login;
|
||||||
break;
|
break;
|
||||||
case VaultNudgeType.newCardItemStatus:
|
case NudgeType.NewCardItemStatus:
|
||||||
currentType = CipherType.Card;
|
currentType = CipherType.Card;
|
||||||
break;
|
break;
|
||||||
case VaultNudgeType.newIdentityItemStatus:
|
case NudgeType.NewIdentityItemStatus:
|
||||||
currentType = CipherType.Identity;
|
currentType = CipherType.Identity;
|
||||||
break;
|
break;
|
||||||
case VaultNudgeType.newNoteItemStatus:
|
case NudgeType.NewNoteItemStatus:
|
||||||
currentType = CipherType.SecureNote;
|
currentType = CipherType.SecureNote;
|
||||||
break;
|
break;
|
||||||
case VaultNudgeType.newSshItemStatus:
|
case NudgeType.NewSshItemStatus:
|
||||||
currentType = CipherType.SshKey;
|
currentType = CipherType.SshKey;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,19 +4,15 @@ import { map, Observable } from "rxjs";
|
|||||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
|
|
||||||
import {
|
import { NudgeStatus, NUDGE_DISMISSED_DISK_KEY, NudgeType } from "./nudges.service";
|
||||||
NudgeStatus,
|
|
||||||
VAULT_NUDGE_DISMISSED_DISK_KEY,
|
|
||||||
VaultNudgeType,
|
|
||||||
} from "./vault-nudges.service";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base interface for handling a nudge's status
|
* Base interface for handling a nudge's status
|
||||||
*/
|
*/
|
||||||
export interface SingleNudgeService {
|
export interface SingleNudgeService {
|
||||||
nudgeStatus$(nudgeType: VaultNudgeType, userId: UserId): Observable<NudgeStatus>;
|
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus>;
|
||||||
|
|
||||||
setNudgeStatus(nudgeType: VaultNudgeType, newStatus: NudgeStatus, userId: UserId): Promise<void>;
|
setNudgeStatus(nudgeType: NudgeType, newStatus: NudgeStatus, userId: UserId): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,9 +24,9 @@ export interface SingleNudgeService {
|
|||||||
export class DefaultSingleNudgeService implements SingleNudgeService {
|
export class DefaultSingleNudgeService implements SingleNudgeService {
|
||||||
stateProvider = inject(StateProvider);
|
stateProvider = inject(StateProvider);
|
||||||
|
|
||||||
protected getNudgeStatus$(nudgeType: VaultNudgeType, userId: UserId): Observable<NudgeStatus> {
|
protected getNudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||||
return this.stateProvider
|
return this.stateProvider
|
||||||
.getUser(userId, VAULT_NUDGE_DISMISSED_DISK_KEY)
|
.getUser(userId, NUDGE_DISMISSED_DISK_KEY)
|
||||||
.state$.pipe(
|
.state$.pipe(
|
||||||
map(
|
map(
|
||||||
(nudges) =>
|
(nudges) =>
|
||||||
@@ -39,16 +35,12 @@ export class DefaultSingleNudgeService implements SingleNudgeService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
nudgeStatus$(nudgeType: VaultNudgeType, userId: UserId): Observable<NudgeStatus> {
|
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||||
return this.getNudgeStatus$(nudgeType, userId);
|
return this.getNudgeStatus$(nudgeType, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setNudgeStatus(
|
async setNudgeStatus(nudgeType: NudgeType, status: NudgeStatus, userId: UserId): Promise<void> {
|
||||||
nudgeType: VaultNudgeType,
|
await this.stateProvider.getUser(userId, NUDGE_DISMISSED_DISK_KEY).update((nudges) => {
|
||||||
status: NudgeStatus,
|
|
||||||
userId: UserId,
|
|
||||||
): Promise<void> {
|
|
||||||
await this.stateProvider.getUser(userId, VAULT_NUDGE_DISMISSED_DISK_KEY).update((nudges) => {
|
|
||||||
nudges ??= {};
|
nudges ??= {};
|
||||||
nudges[nudgeType] = status;
|
nudges[nudgeType] = status;
|
||||||
return nudges;
|
return nudges;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
DownloadBitwardenNudgeService,
|
DownloadBitwardenNudgeService,
|
||||||
} from "./custom-nudges-services";
|
} from "./custom-nudges-services";
|
||||||
import { DefaultSingleNudgeService } from "./default-single-nudge.service";
|
import { DefaultSingleNudgeService } from "./default-single-nudge.service";
|
||||||
import { VaultNudgesService, VaultNudgeType } from "./vault-nudges.service";
|
import { NudgesService, NudgeType } from "./nudges.service";
|
||||||
|
|
||||||
describe("Vault Nudges Service", () => {
|
describe("Vault Nudges Service", () => {
|
||||||
let fakeStateProvider: FakeStateProvider;
|
let fakeStateProvider: FakeStateProvider;
|
||||||
@@ -29,7 +29,7 @@ describe("Vault Nudges Service", () => {
|
|||||||
getFeatureFlag: jest.fn().mockReturnValue(true),
|
getFeatureFlag: jest.fn().mockReturnValue(true),
|
||||||
};
|
};
|
||||||
|
|
||||||
const vaultNudgeServices = [EmptyVaultNudgeService, DownloadBitwardenNudgeService];
|
const nudgeServices = [EmptyVaultNudgeService, DownloadBitwardenNudgeService];
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
fakeStateProvider = new FakeStateProvider(mockAccountServiceWith("user-id" as UserId));
|
fakeStateProvider = new FakeStateProvider(mockAccountServiceWith("user-id" as UserId));
|
||||||
@@ -38,7 +38,7 @@ describe("Vault Nudges Service", () => {
|
|||||||
imports: [],
|
imports: [],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: VaultNudgesService,
|
provide: NudgesService,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: DefaultSingleNudgeService,
|
provide: DefaultSingleNudgeService,
|
||||||
@@ -83,13 +83,13 @@ describe("Vault Nudges Service", () => {
|
|||||||
const service = testBed.inject(DefaultSingleNudgeService);
|
const service = testBed.inject(DefaultSingleNudgeService);
|
||||||
|
|
||||||
await service.setNudgeStatus(
|
await service.setNudgeStatus(
|
||||||
VaultNudgeType.EmptyVaultNudge,
|
NudgeType.EmptyVaultNudge,
|
||||||
{ hasBadgeDismissed: true, hasSpotlightDismissed: true },
|
{ hasBadgeDismissed: true, hasSpotlightDismissed: true },
|
||||||
"user-id" as UserId,
|
"user-id" as UserId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await firstValueFrom(
|
const result = await firstValueFrom(
|
||||||
service.nudgeStatus$(VaultNudgeType.EmptyVaultNudge, "user-id" as UserId),
|
service.nudgeStatus$(NudgeType.EmptyVaultNudge, "user-id" as UserId),
|
||||||
);
|
);
|
||||||
expect(result).toEqual({ hasBadgeDismissed: true, hasSpotlightDismissed: true });
|
expect(result).toEqual({ hasBadgeDismissed: true, hasSpotlightDismissed: true });
|
||||||
});
|
});
|
||||||
@@ -98,27 +98,27 @@ describe("Vault Nudges Service", () => {
|
|||||||
const service = testBed.inject(DefaultSingleNudgeService);
|
const service = testBed.inject(DefaultSingleNudgeService);
|
||||||
|
|
||||||
await service.setNudgeStatus(
|
await service.setNudgeStatus(
|
||||||
VaultNudgeType.EmptyVaultNudge,
|
NudgeType.EmptyVaultNudge,
|
||||||
{ hasBadgeDismissed: false, hasSpotlightDismissed: false },
|
{ hasBadgeDismissed: false, hasSpotlightDismissed: false },
|
||||||
"user-id" as UserId,
|
"user-id" as UserId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await firstValueFrom(
|
const result = await firstValueFrom(
|
||||||
service.nudgeStatus$(VaultNudgeType.EmptyVaultNudge, "user-id" as UserId),
|
service.nudgeStatus$(NudgeType.EmptyVaultNudge, "user-id" as UserId),
|
||||||
);
|
);
|
||||||
expect(result).toEqual({ hasBadgeDismissed: false, hasSpotlightDismissed: false });
|
expect(result).toEqual({ hasBadgeDismissed: false, hasSpotlightDismissed: false });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("VaultNudgesService", () => {
|
describe("NudgesService", () => {
|
||||||
it("should return true, the proper value from the custom nudge service nudgeStatus$", async () => {
|
it("should return true, the proper value from the custom nudge service nudgeStatus$", async () => {
|
||||||
TestBed.overrideProvider(HasItemsNudgeService, {
|
TestBed.overrideProvider(HasItemsNudgeService, {
|
||||||
useValue: { nudgeStatus$: () => of(true) },
|
useValue: { nudgeStatus$: () => of(true) },
|
||||||
});
|
});
|
||||||
const service = testBed.inject(VaultNudgesService);
|
const service = testBed.inject(NudgesService);
|
||||||
|
|
||||||
const result = await firstValueFrom(
|
const result = await firstValueFrom(
|
||||||
service.showNudge$(VaultNudgeType.HasVaultItems, "user-id" as UserId),
|
service.showNudgeStatus$(NudgeType.HasVaultItems, "user-id" as UserId),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
@@ -128,10 +128,40 @@ describe("Vault Nudges Service", () => {
|
|||||||
TestBed.overrideProvider(HasItemsNudgeService, {
|
TestBed.overrideProvider(HasItemsNudgeService, {
|
||||||
useValue: { nudgeStatus$: () => of(false) },
|
useValue: { nudgeStatus$: () => of(false) },
|
||||||
});
|
});
|
||||||
const service = testBed.inject(VaultNudgesService);
|
const service = testBed.inject(NudgesService);
|
||||||
|
|
||||||
const result = await firstValueFrom(
|
const result = await firstValueFrom(
|
||||||
service.showNudge$(VaultNudgeType.HasVaultItems, "user-id" as UserId),
|
service.showNudgeStatus$(NudgeType.HasVaultItems, "user-id" as UserId),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return showNudgeSpotlight$ false if hasSpotLightDismissed is true", async () => {
|
||||||
|
TestBed.overrideProvider(HasItemsNudgeService, {
|
||||||
|
useValue: {
|
||||||
|
nudgeStatus$: () => of({ hasSpotlightDismissed: true, hasBadgeDismissed: true }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const service = testBed.inject(NudgesService);
|
||||||
|
|
||||||
|
const result = await firstValueFrom(
|
||||||
|
service.showNudgeSpotlight$(NudgeType.HasVaultItems, "user-id" as UserId),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return showNudgeBadge$ false when hasBadgeDismissed is true", async () => {
|
||||||
|
TestBed.overrideProvider(HasItemsNudgeService, {
|
||||||
|
useValue: {
|
||||||
|
nudgeStatus$: () => of({ hasSpotlightDismissed: true, hasBadgeDismissed: true }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const service = testBed.inject(NudgesService);
|
||||||
|
|
||||||
|
const result = await firstValueFrom(
|
||||||
|
service.showNudgeBadge$(NudgeType.HasVaultItems, "user-id" as UserId),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).toBe(false);
|
expect(result).toBe(false);
|
||||||
@@ -140,7 +170,7 @@ describe("Vault Nudges Service", () => {
|
|||||||
|
|
||||||
describe("HasActiveBadges", () => {
|
describe("HasActiveBadges", () => {
|
||||||
it("should return true if a nudgeType with hasBadgeDismissed === false", async () => {
|
it("should return true if a nudgeType with hasBadgeDismissed === false", async () => {
|
||||||
vaultNudgeServices.forEach((service) => {
|
nudgeServices.forEach((service) => {
|
||||||
TestBed.overrideProvider(service, {
|
TestBed.overrideProvider(service, {
|
||||||
useValue: {
|
useValue: {
|
||||||
nudgeStatus$: () => of({ hasBadgeDismissed: false, hasSpotlightDismissed: false }),
|
nudgeStatus$: () => of({ hasBadgeDismissed: false, hasSpotlightDismissed: false }),
|
||||||
@@ -148,21 +178,21 @@ describe("Vault Nudges Service", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const service = testBed.inject(VaultNudgesService);
|
const service = testBed.inject(NudgesService);
|
||||||
|
|
||||||
const result = await firstValueFrom(service.hasActiveBadges$("user-id" as UserId));
|
const result = await firstValueFrom(service.hasActiveBadges$("user-id" as UserId));
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
it("should return false if all nudgeTypes have hasBadgeDismissed === true", async () => {
|
it("should return false if all nudgeTypes have hasBadgeDismissed === true", async () => {
|
||||||
vaultNudgeServices.forEach((service) => {
|
nudgeServices.forEach((service) => {
|
||||||
TestBed.overrideProvider(service, {
|
TestBed.overrideProvider(service, {
|
||||||
useValue: {
|
useValue: {
|
||||||
nudgeStatus$: () => of({ hasBadgeDismissed: true, hasSpotlightDismissed: false }),
|
nudgeStatus$: () => of({ hasBadgeDismissed: true, hasSpotlightDismissed: false }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const service = testBed.inject(VaultNudgesService);
|
const service = testBed.inject(NudgesService);
|
||||||
|
|
||||||
const result = await firstValueFrom(service.hasActiveBadges$("user-id" as UserId));
|
const result = await firstValueFrom(service.hasActiveBadges$("user-id" as UserId));
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@ import { combineLatest, map, Observable, of, shareReplay, switchMap } from "rxjs
|
|||||||
|
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { UserKeyDefinition, VAULT_NUDGES_DISK } from "@bitwarden/common/platform/state";
|
import { UserKeyDefinition, NUDGES_DISK } from "@bitwarden/common/platform/state";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -25,7 +25,7 @@ export type NudgeStatus = {
|
|||||||
*/
|
*/
|
||||||
// FIXME: update to use a const object instead of a typescript enum
|
// FIXME: update to use a const object instead of a typescript enum
|
||||||
// eslint-disable-next-line @bitwarden/platform/no-enums
|
// eslint-disable-next-line @bitwarden/platform/no-enums
|
||||||
export enum VaultNudgeType {
|
export enum NudgeType {
|
||||||
/** Nudge to show when user has no items in their vault
|
/** Nudge to show when user has no items in their vault
|
||||||
* Add future nudges here
|
* Add future nudges here
|
||||||
*/
|
*/
|
||||||
@@ -33,16 +33,16 @@ export enum VaultNudgeType {
|
|||||||
HasVaultItems = "has-vault-items",
|
HasVaultItems = "has-vault-items",
|
||||||
AutofillNudge = "autofill-nudge",
|
AutofillNudge = "autofill-nudge",
|
||||||
DownloadBitwarden = "download-bitwarden",
|
DownloadBitwarden = "download-bitwarden",
|
||||||
newLoginItemStatus = "new-login-item-status",
|
NewLoginItemStatus = "new-login-item-status",
|
||||||
newCardItemStatus = "new-card-item-status",
|
NewCardItemStatus = "new-card-item-status",
|
||||||
newIdentityItemStatus = "new-identity-item-status",
|
NewIdentityItemStatus = "new-identity-item-status",
|
||||||
newNoteItemStatus = "new-note-item-status",
|
NewNoteItemStatus = "new-note-item-status",
|
||||||
newSshItemStatus = "new-ssh-item-status",
|
NewSshItemStatus = "new-ssh-item-status",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VAULT_NUDGE_DISMISSED_DISK_KEY = new UserKeyDefinition<
|
export const NUDGE_DISMISSED_DISK_KEY = new UserKeyDefinition<
|
||||||
Partial<Record<VaultNudgeType, NudgeStatus>>
|
Partial<Record<NudgeType, NudgeStatus>>
|
||||||
>(VAULT_NUDGES_DISK, "vaultNudgeDismissed", {
|
>(NUDGES_DISK, "vaultNudgeDismissed", {
|
||||||
deserializer: (nudge) => nudge,
|
deserializer: (nudge) => nudge,
|
||||||
clearOn: [], // Do not clear dismissals
|
clearOn: [], // Do not clear dismissals
|
||||||
});
|
});
|
||||||
@@ -50,7 +50,7 @@ export const VAULT_NUDGE_DISMISSED_DISK_KEY = new UserKeyDefinition<
|
|||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: "root",
|
providedIn: "root",
|
||||||
})
|
})
|
||||||
export class VaultNudgesService {
|
export class NudgesService {
|
||||||
private newItemNudgeService = inject(NewItemNudgeService);
|
private newItemNudgeService = inject(NewItemNudgeService);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,16 +58,16 @@ export class VaultNudgesService {
|
|||||||
* Each nudge type can have its own service to determine when to show the nudge
|
* Each nudge type can have its own service to determine when to show the nudge
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private customNudgeServices: Partial<Record<VaultNudgeType, SingleNudgeService>> = {
|
private customNudgeServices: Partial<Record<NudgeType, SingleNudgeService>> = {
|
||||||
[VaultNudgeType.HasVaultItems]: inject(HasItemsNudgeService),
|
[NudgeType.HasVaultItems]: inject(HasItemsNudgeService),
|
||||||
[VaultNudgeType.EmptyVaultNudge]: inject(EmptyVaultNudgeService),
|
[NudgeType.EmptyVaultNudge]: inject(EmptyVaultNudgeService),
|
||||||
[VaultNudgeType.AutofillNudge]: inject(AutofillNudgeService),
|
[NudgeType.AutofillNudge]: inject(AutofillNudgeService),
|
||||||
[VaultNudgeType.DownloadBitwarden]: inject(DownloadBitwardenNudgeService),
|
[NudgeType.DownloadBitwarden]: inject(DownloadBitwardenNudgeService),
|
||||||
[VaultNudgeType.newLoginItemStatus]: this.newItemNudgeService,
|
[NudgeType.NewLoginItemStatus]: this.newItemNudgeService,
|
||||||
[VaultNudgeType.newCardItemStatus]: this.newItemNudgeService,
|
[NudgeType.NewCardItemStatus]: this.newItemNudgeService,
|
||||||
[VaultNudgeType.newIdentityItemStatus]: this.newItemNudgeService,
|
[NudgeType.NewIdentityItemStatus]: this.newItemNudgeService,
|
||||||
[VaultNudgeType.newNoteItemStatus]: this.newItemNudgeService,
|
[NudgeType.NewNoteItemStatus]: this.newItemNudgeService,
|
||||||
[VaultNudgeType.newSshItemStatus]: this.newItemNudgeService,
|
[NudgeType.NewSshItemStatus]: this.newItemNudgeService,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,16 +78,52 @@ export class VaultNudgesService {
|
|||||||
private defaultNudgeService = inject(DefaultSingleNudgeService);
|
private defaultNudgeService = inject(DefaultSingleNudgeService);
|
||||||
private configService = inject(ConfigService);
|
private configService = inject(ConfigService);
|
||||||
|
|
||||||
private getNudgeService(nudge: VaultNudgeType): SingleNudgeService {
|
private getNudgeService(nudge: NudgeType): SingleNudgeService {
|
||||||
return this.customNudgeServices[nudge] ?? this.defaultNudgeService;
|
return this.customNudgeServices[nudge] ?? this.defaultNudgeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a nudge Spotlight should be shown to the user
|
||||||
|
* @param nudge
|
||||||
|
* @param userId
|
||||||
|
*/
|
||||||
|
showNudgeSpotlight$(nudge: NudgeType, userId: UserId): Observable<boolean> {
|
||||||
|
return this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge).pipe(
|
||||||
|
switchMap((hasVaultNudgeFlag) => {
|
||||||
|
if (!hasVaultNudgeFlag) {
|
||||||
|
return of(false);
|
||||||
|
}
|
||||||
|
return this.getNudgeService(nudge)
|
||||||
|
.nudgeStatus$(nudge, userId)
|
||||||
|
.pipe(map((nudgeStatus) => !nudgeStatus.hasSpotlightDismissed));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a nudge Badge should be shown to the user
|
||||||
|
* @param nudge
|
||||||
|
* @param userId
|
||||||
|
*/
|
||||||
|
showNudgeBadge$(nudge: NudgeType, userId: UserId): Observable<boolean> {
|
||||||
|
return this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge).pipe(
|
||||||
|
switchMap((hasVaultNudgeFlag) => {
|
||||||
|
if (!hasVaultNudgeFlag) {
|
||||||
|
return of(false);
|
||||||
|
}
|
||||||
|
return this.getNudgeService(nudge)
|
||||||
|
.nudgeStatus$(nudge, userId)
|
||||||
|
.pipe(map((nudgeStatus) => !nudgeStatus.hasBadgeDismissed));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a nudge should be shown to the user
|
* Check if a nudge should be shown to the user
|
||||||
* @param nudge
|
* @param nudge
|
||||||
* @param userId
|
* @param userId
|
||||||
*/
|
*/
|
||||||
showNudge$(nudge: VaultNudgeType, userId: UserId) {
|
showNudgeStatus$(nudge: NudgeType, userId: UserId) {
|
||||||
return this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge).pipe(
|
return this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge).pipe(
|
||||||
switchMap((hasVaultNudgeFlag) => {
|
switchMap((hasVaultNudgeFlag) => {
|
||||||
if (!hasVaultNudgeFlag) {
|
if (!hasVaultNudgeFlag) {
|
||||||
@@ -103,7 +139,7 @@ export class VaultNudgesService {
|
|||||||
* @param nudge
|
* @param nudge
|
||||||
* @param userId
|
* @param userId
|
||||||
*/
|
*/
|
||||||
async dismissNudge(nudge: VaultNudgeType, userId: UserId, onlyBadge: boolean = false) {
|
async dismissNudge(nudge: NudgeType, userId: UserId, onlyBadge: boolean = false) {
|
||||||
const dismissedStatus = onlyBadge
|
const dismissedStatus = onlyBadge
|
||||||
? { hasBadgeDismissed: true, hasSpotlightDismissed: false }
|
? { hasBadgeDismissed: true, hasSpotlightDismissed: false }
|
||||||
: { hasBadgeDismissed: true, hasSpotlightDismissed: true };
|
: { hasBadgeDismissed: true, hasSpotlightDismissed: true };
|
||||||
@@ -116,7 +152,7 @@ export class VaultNudgesService {
|
|||||||
*/
|
*/
|
||||||
hasActiveBadges$(userId: UserId): Observable<boolean> {
|
hasActiveBadges$(userId: UserId): Observable<boolean> {
|
||||||
// Add more nudge types here if they have the settings badge feature
|
// Add more nudge types here if they have the settings badge feature
|
||||||
const nudgeTypes = [VaultNudgeType.EmptyVaultNudge, VaultNudgeType.DownloadBitwarden];
|
const nudgeTypes = [NudgeType.EmptyVaultNudge, NudgeType.DownloadBitwarden];
|
||||||
|
|
||||||
const nudgeTypesWithBadge$ = nudgeTypes.map((nudge) => {
|
const nudgeTypesWithBadge$ = nudgeTypes.map((nudge) => {
|
||||||
return this.getNudgeService(nudge)
|
return this.getNudgeService(nudge)
|
||||||
Reference in New Issue
Block a user