diff --git a/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options.component.ts b/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options.component.ts index 7fac9a42b0..60ac8579c9 100644 --- a/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options.component.ts +++ b/apps/browser/src/auth/popup/login-decryption-options/login-decryption-options.component.ts @@ -1,7 +1,10 @@ import { Component } from "@angular/core"; +import { firstValueFrom } from "rxjs"; import { BaseLoginDecryptionOptionsComponent } from "@bitwarden/angular/auth/components/base-login-decryption-options.component"; +import { postLogoutMessageListener$ } from "../utils/post-logout-message-listener"; + @Component({ selector: "browser-login-decryption-options", templateUrl: "login-decryption-options.component.html", @@ -15,4 +18,20 @@ export class LoginDecryptionOptionsComponent extends BaseLoginDecryptionOptionsC this.validationService.showError(error); } } + + override async logOut(): Promise { + // start listening for "switchAccountFinish" or "doneLoggingOut" + const messagePromise = firstValueFrom(postLogoutMessageListener$); + super.logOut(); + // wait for messages + const command = await messagePromise; + + // We should be routed/routing very soon but just in case, turn loading back off. + this.loading = false; + + // doneLoggingOut already has a message handler that will navigate us + if (command === "switchAccountFinish") { + this.router.navigate(["/"]); + } + } } diff --git a/apps/browser/src/auth/popup/utils/post-logout-message-listener.ts b/apps/browser/src/auth/popup/utils/post-logout-message-listener.ts new file mode 100644 index 0000000000..1f6b805316 --- /dev/null +++ b/apps/browser/src/auth/popup/utils/post-logout-message-listener.ts @@ -0,0 +1,24 @@ +import { filter, map, throwError, timeout } from "rxjs"; + +import { fromChromeEvent } from "../../../platform/browser/from-chrome-event"; + +/** + * Listens to `switchAccountFinish` and `doneLoggingOut` messages and returns which message was heard. + * + * @example + * ```ts + * const messagePromise = firstValueFrom(postLogoutMessageListener$); + * this.messagingService.send("logout"); + * const message = await messagePromise; + * ``` + */ +export const postLogoutMessageListener$ = fromChromeEvent< + [message?: { command: "switchAccountFinish" | "doneLoggingOut" }] +>(chrome.runtime.onMessage).pipe( + map(([message]) => message?.command), + filter((command) => command === "switchAccountFinish" || command === "doneLoggingOut"), + timeout({ + first: 60_000, + with: () => throwError(() => new Error("Did not receive message from logout.")), + }), +);