diff --git a/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.html b/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.html index 6426a8958f7..ea71829c9aa 100644 --- a/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.html +++ b/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.html @@ -10,11 +10,12 @@ } -@if (showTasksResolved()) { +@if (showTasksResolvedBanner) { {{ "atRiskLoginsSecured" | i18n }} diff --git a/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.ts b/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.ts index 873271f6342..5347690824b 100644 --- a/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.ts +++ b/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.ts @@ -1,12 +1,11 @@ import { CommonModule } from "@angular/common"; -import { Component, computed, inject, effect } from "@angular/core"; +import { Component, inject, effect } from "@angular/core"; import { toSignal } from "@angular/core/rxjs-interop"; import { RouterModule } from "@angular/router"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { StateProvider } from "@bitwarden/common/platform/state"; import { AnchorLinkDirective, CalloutModule, BannerModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; import { @@ -35,6 +34,13 @@ export class AtRiskPasswordCalloutComponent { private atRiskPasswordStateSignal = toSignal( this.atRiskPasswordCalloutService.atRiskPasswordState(this.userIdSignal()!).state$, + { + initialValue: { + hadPendingTasks: false, + showTasksCompleteBanner: false, + tasksBannerDismissed: false, + } as AtRiskPasswordCalloutData, + }, ); currentPendingTasks = toSignal( @@ -44,14 +50,37 @@ export class AtRiskPasswordCalloutComponent { }, ); - showTasksResolved = computed(() => { - if (this.atRiskPasswordStateSignal() && this.currentPendingTasks().length === 0) { - return true; - } - }); + showTasksResolvedBanner: boolean = false; - constructor(private stateProvider: StateProvider) { + constructor() { effect(() => { + // If the user had the banner showing and left the extension, when they come back the banner should still appear + if ( + this.atRiskPasswordStateSignal()?.showTasksCompleteBanner && + this.currentPendingTasks().length === 0 && + !this.atRiskPasswordStateSignal()?.hadPendingTasks + ) { + this.showTasksResolvedBanner = true; + } + + // If the user has resolved all tasks, we will show the banner + if ( + this.atRiskPasswordStateSignal()?.hadPendingTasks && + this.currentPendingTasks().length === 0 + ) { + const updateObject: AtRiskPasswordCalloutData = { + hadPendingTasks: false, + showTasksCompleteBanner: true, + tasksBannerDismissed: false, + }; + this.atRiskPasswordCalloutService.updateAtRiskPasswordState( + this.userIdSignal()!, + updateObject, + ); + this.showTasksResolvedBanner = true; + } + + // Will show callout, will remove any previous dismissed banner state if (this.currentPendingTasks().length > 0) { const updateObject: AtRiskPasswordCalloutData = { hadPendingTasks: true, @@ -65,4 +94,15 @@ export class AtRiskPasswordCalloutComponent { } }); } + + successBannerDismissed() { + // If the user dismisses the banner, we will update the state to reflect that + const updateObject: AtRiskPasswordCalloutData = { + hadPendingTasks: false, + showTasksCompleteBanner: false, + tasksBannerDismissed: true, + }; + this.atRiskPasswordCalloutService.updateAtRiskPasswordState(this.userIdSignal()!, updateObject); + this.showTasksResolvedBanner = false; + } } diff --git a/apps/web/src/app/vault/services/at-risk-password-callout.service.ts b/apps/web/src/app/vault/services/at-risk-password-callout.service.ts index 3af5433adf7..a0a306c5837 100644 --- a/apps/web/src/app/vault/services/at-risk-password-callout.service.ts +++ b/apps/web/src/app/vault/services/at-risk-password-callout.service.ts @@ -2,13 +2,14 @@ import { Injectable } from "@angular/core"; import { combineLatest, map, Observable } from "rxjs"; import { + SingleUserState, StateProvider, UserKeyDefinition, VAULT_AT_RISK_PASSWORDS_DISK, } from "@bitwarden/common/platform/state"; -import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { SecurityTask, SecurityTaskType, TaskService } from "@bitwarden/common/vault/tasks"; +import { UserId } from "@bitwarden/user-core"; export type AtRiskPasswordCalloutData = { hadPendingTasks: boolean; @@ -52,7 +53,7 @@ export class AtRiskPasswordCalloutService { ); } - atRiskPasswordState(userId: UserId) { + atRiskPasswordState(userId: UserId): SingleUserState { return this.stateProvider.getUser(userId, AT_RISK_PASSWORD_CALLOUT_KEY); }