diff --git a/apps/web/src/app/vault/individual-vault/vault-onboarding/services/abstraction/vault-onboarding.service.ts b/apps/web/src/app/vault/individual-vault/vault-onboarding/services/abstraction/vault-onboarding.service.ts index 379c97672e7..7d3ff32c0f8 100644 --- a/apps/web/src/app/vault/individual-vault/vault-onboarding/services/abstraction/vault-onboarding.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-onboarding/services/abstraction/vault-onboarding.service.ts @@ -1,10 +1,10 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { Observable } from "rxjs"; +import { UserId } from "@bitwarden/common/types/guid"; + import { VaultOnboardingTasks } from "../vault-onboarding.service"; export abstract class VaultOnboardingService { - vaultOnboardingState$: Observable; - abstract setVaultOnboardingTasks(newState: VaultOnboardingTasks): Promise; + abstract setVaultOnboardingTasks(userId: UserId, newState: VaultOnboardingTasks): Promise; + abstract vaultOnboardingState$(userId: UserId): Observable; } diff --git a/apps/web/src/app/vault/individual-vault/vault-onboarding/services/vault-onboarding.service.ts b/apps/web/src/app/vault/individual-vault/vault-onboarding/services/vault-onboarding.service.ts index 95cb568a840..e6f8b815484 100644 --- a/apps/web/src/app/vault/individual-vault/vault-onboarding/services/vault-onboarding.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-onboarding/services/vault-onboarding.service.ts @@ -1,14 +1,13 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { Injectable } from "@angular/core"; import { Observable } from "rxjs"; import { - ActiveUserState, + SingleUserState, StateProvider, UserKeyDefinition, VAULT_ONBOARDING, } from "@bitwarden/common/platform/state"; +import { UserId } from "@bitwarden/common/types/guid"; import { VaultOnboardingService as VaultOnboardingServiceAbstraction } from "./abstraction/vault-onboarding.service"; @@ -26,20 +25,20 @@ const VAULT_ONBOARDING_KEY = new UserKeyDefinition( clearOn: [], // do not clear tutorials }, ); - @Injectable() export class VaultOnboardingService implements VaultOnboardingServiceAbstraction { - private vaultOnboardingState: ActiveUserState; - vaultOnboardingState$: Observable; + constructor(private stateProvider: StateProvider) {} + + private vaultOnboardingState(userId: UserId): SingleUserState { + return this.stateProvider.getUser(userId, VAULT_ONBOARDING_KEY); + } - constructor(private stateProvider: StateProvider) { - this.vaultOnboardingState = this.stateProvider.getActive(VAULT_ONBOARDING_KEY); - this.vaultOnboardingState$ = this.vaultOnboardingState.state$; + vaultOnboardingState$(userId: UserId): Observable { + return this.vaultOnboardingState(userId).state$; } - async setVaultOnboardingTasks(newState: VaultOnboardingTasks): Promise { - await this.vaultOnboardingState.update(() => { - return { ...newState }; - }); + async setVaultOnboardingTasks(userId: UserId, newState: VaultOnboardingTasks): Promise { + const state = this.vaultOnboardingState(userId); + await state.update(() => ({ ...newState })); } } diff --git a/apps/web/src/app/vault/individual-vault/vault-onboarding/vault-onboarding.component.spec.ts b/apps/web/src/app/vault/individual-vault/vault-onboarding/vault-onboarding.component.spec.ts index e017bc9b35d..330b2d3f2d5 100644 --- a/apps/web/src/app/vault/individual-vault/vault-onboarding/vault-onboarding.component.spec.ts +++ b/apps/web/src/app/vault/individual-vault/vault-onboarding/vault-onboarding.component.spec.ts @@ -7,10 +7,18 @@ import { Subject, of } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; import { StateProvider } from "@bitwarden/common/platform/state"; +import { + FakeAccountService, + FakeStateProvider, + mockAccountServiceWith, +} from "@bitwarden/common/spec"; +import { UserId } from "@bitwarden/common/types/guid"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { VaultOnboardingMessages } from "@bitwarden/common/vault/enums/vault-onboarding.enum"; @@ -25,10 +33,11 @@ describe("VaultOnboardingComponent", () => { let mockPolicyService: MockProxy; let mockI18nService: MockProxy; let mockVaultOnboardingService: MockProxy; - let mockStateProvider: Partial; let setInstallExtLinkSpy: any; let individualVaultPolicyCheckSpy: any; let mockConfigService: MockProxy; + const mockAccountService: FakeAccountService = mockAccountServiceWith(Utils.newGuid() as UserId); + const fakeStateProvider = new FakeStateProvider(mockAccountService); beforeEach(() => { mockPolicyService = mock(); @@ -38,15 +47,6 @@ describe("VaultOnboardingComponent", () => { getProfile: jest.fn(), }; mockVaultOnboardingService = mock(); - mockStateProvider = { - getActive: jest.fn().mockReturnValue( - of({ - createAccount: true, - importData: false, - installExtension: false, - }), - ), - }; mockConfigService = mock(); // eslint-disable-next-line @typescript-eslint/no-floating-promises @@ -59,8 +59,9 @@ describe("VaultOnboardingComponent", () => { { provide: VaultOnboardingServiceAbstraction, useValue: mockVaultOnboardingService }, { provide: I18nService, useValue: mockI18nService }, { provide: ApiService, useValue: mockApiService }, - { provide: StateProvider, useValue: mockStateProvider }, + { provide: StateProvider, useValue: fakeStateProvider }, { provide: ConfigService, useValue: mockConfigService }, + { provide: AccountService, useValue: mockAccountService }, ], }).compileComponents(); fixture = TestBed.createComponent(VaultOnboardingComponent); @@ -71,11 +72,15 @@ describe("VaultOnboardingComponent", () => { .mockReturnValue(undefined); jest.spyOn(component, "checkCreationDate").mockReturnValue(null); jest.spyOn(window, "postMessage").mockImplementation(jest.fn()); - (component as any).vaultOnboardingService.vaultOnboardingState$ = of({ - createAccount: true, - importData: false, - installExtension: false, - }); + (component as any).vaultOnboardingService.vaultOnboardingState$ = jest + .fn() + .mockImplementation(() => { + return of({ + createAccount: true, + importData: false, + installExtension: false, + }); + }); }); it("should create", () => { @@ -169,12 +174,15 @@ describe("VaultOnboardingComponent", () => { .spyOn((component as any).vaultOnboardingService, "setVaultOnboardingTasks") .mockReturnValue(Promise.resolve()); - (component as any).vaultOnboardingService.vaultOnboardingState$ = of({ - createAccount: true, - importData: false, - installExtension: false, - }); - + (component as any).vaultOnboardingService.vaultOnboardingState$ = jest + .fn() + .mockImplementation(() => { + return of({ + createAccount: true, + importData: false, + installExtension: false, + }); + }); const eventData = { data: { command: VaultOnboardingMessages.HasBwInstalled } }; (component as any).showOnboarding = true; diff --git a/apps/web/src/app/vault/individual-vault/vault-onboarding/vault-onboarding.component.ts b/apps/web/src/app/vault/individual-vault/vault-onboarding/vault-onboarding.component.ts index 3535d31852e..dd17998f516 100644 --- a/apps/web/src/app/vault/individual-vault/vault-onboarding/vault-onboarding.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-onboarding/vault-onboarding.component.ts @@ -18,6 +18,8 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -66,10 +68,13 @@ export class VaultOnboardingComponent implements OnInit, OnChanges, OnDestroy { private apiService: ApiService, private vaultOnboardingService: VaultOnboardingServiceAbstraction, private configService: ConfigService, + private accountService: AccountService, ) {} async ngOnInit() { - this.onboardingTasks$ = this.vaultOnboardingService.vaultOnboardingState$; + const activeId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); + this.onboardingTasks$ = this.vaultOnboardingService.vaultOnboardingState$(activeId); + await this.setOnboardingTasks(); this.setInstallExtLink(); this.individualVaultPolicyCheck(); @@ -81,13 +86,14 @@ export class VaultOnboardingComponent implements OnInit, OnChanges, OnDestroy { async ngOnChanges(changes: SimpleChanges) { if (this.showOnboarding && changes?.ciphers) { + const activeId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); const currentTasks = await firstValueFrom(this.onboardingTasks$); const updatedTasks = { createAccount: true, importData: this.ciphers.length > 0, installExtension: currentTasks.installExtension, }; - await this.vaultOnboardingService.setVaultOnboardingTasks(updatedTasks); + await this.vaultOnboardingService.setVaultOnboardingTasks(activeId, updatedTasks); } } @@ -110,13 +116,14 @@ export class VaultOnboardingComponent implements OnInit, OnChanges, OnDestroy { async getMessages(event: any) { if (event.data.command === VaultOnboardingMessages.HasBwInstalled && this.showOnboarding) { + const activeId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); const currentTasks = await firstValueFrom(this.onboardingTasks$); const updatedTasks = { createAccount: currentTasks.createAccount, importData: currentTasks.importData, installExtension: true, }; - await this.vaultOnboardingService.setVaultOnboardingTasks(updatedTasks); + await this.vaultOnboardingService.setVaultOnboardingTasks(activeId, updatedTasks); } } @@ -159,7 +166,8 @@ export class VaultOnboardingComponent implements OnInit, OnChanges, OnDestroy { private async saveCompletedTasks(vaultTasks: VaultOnboardingTasks) { this.showOnboarding = Object.values(vaultTasks).includes(false); - await this.vaultOnboardingService.setVaultOnboardingTasks(vaultTasks); + const activeId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); + await this.vaultOnboardingService.setVaultOnboardingTasks(activeId, vaultTasks); } individualVaultPolicyCheck() {