diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 553055439c..4a89889810 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -166,15 +166,21 @@ "confirmIdentity": { "message": "Confirm your identity to continue." }, - "account": { - "message": "Account" - }, "changeMasterPassword": { "message": "Change master password" }, "continueToWebApp": { "message": "Continue to web app?" }, + "continueToWebAppDesc": { + "message": "Explore more features of your Bitwarden account on the web app." + }, + "continueToHelpCenter": { + "message": "Continue to Help Center?" + }, + "continueToHelpCenterDesc": { + "message": "Learn more about how to use Bitwarden on the Help Center." + }, "changeMasterPasswordOnWebConfirmation": { "message": "You can change your master password on the Bitwarden web app." }, @@ -192,9 +198,45 @@ "logOut": { "message": "Log out" }, + "aboutBitwarden": { + "message": "About Bitwarden" + }, "about": { "message": "About" }, + "moreFromBitwarden": { + "message": "More from Bitwarden" + }, + "continueToBitwardenDotCom": { + "message": "Continue to bitwarden.com?" + }, + "bitwardenForBusiness": { + "message": "Bitwarden for Business" + }, + "bitwardenAuthenticator": { + "message": "Bitwarden Authenticator" + }, + "continueToAuthenticatorPageDesc": { + "message": "Bitwarden Authenticator allows you to store authenticator keys and generate TOTP codes for 2-step verification flows. Learn more on the bitwarden.com website" + }, + "bitwardenSecretsManager": { + "message": "Bitwarden Secrets Manager" + }, + "continueToSecretsManagerPageDesc": { + "message": "Securely store, manage, and share developer secrets with Bitwarden Secrets Manager. Learn more on the bitwarden.com website." + }, + "passwordlessDotDev": { + "message": "Passwordless.dev" + }, + "continueToPasswordlessDotDevPageDesc": { + "message": "Create smooth and secure login experiences free from traditional passwords with Passwordless.dev. Learn more on the bitwarden.com website." + }, + "freeBitwardenFamilies": { + "message": "Free Bitwarden Families" + }, + "freeBitwardenFamiliesPageDesc": { + "message": "You are eligible for Free Bitwarden Families. Redeem this offer today in the web app." + }, "version": { "message": "Version" }, @@ -253,8 +295,8 @@ "passGenInfo": { "message": "Automatically generate strong, unique passwords for your logins." }, - "bitWebVault": { - "message": "Bitwarden web vault" + "bitWebVaultApp": { + "message": "Bitwarden web app" }, "importItems": { "message": "Import items" @@ -779,11 +821,8 @@ "shared": { "message": "Shared" }, - "learnOrg": { - "message": "Learn about organizations" - }, - "learnOrgConfirmation": { - "message": "Bitwarden allows you to share your vault items with others by using an organization. Would you like to visit the bitwarden.com website to learn more?" + "bitwardenForBusinessPageDesc": { + "message": "Bitwarden for Business allows you to share your vault items with others by using an organization. Learn more on the bitwarden.com website." }, "moveToOrganization": { "message": "Move to organization" diff --git a/apps/browser/src/popup/app-routing.animations.ts b/apps/browser/src/popup/app-routing.animations.ts index 96e5dbbe37..b2fa53caba 100644 --- a/apps/browser/src/popup/app-routing.animations.ts +++ b/apps/browser/src/popup/app-routing.animations.ts @@ -208,8 +208,8 @@ export const routerTransition = trigger("routerTransition", [ transition("tabs => lock", inSlideDown), - transition("tabs => help-and-feedback", inSlideLeft), - transition("help-and-feedback => tabs", outSlideRight), + transition("tabs => about", inSlideLeft), + transition("about => tabs", outSlideRight), transition("tabs => send-type", inSlideLeft), transition("send-type => tabs", outSlideRight), diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index b4445430a6..deafbb9753 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -36,6 +36,8 @@ import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/pass import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component"; import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component"; import { SendTypeComponent } from "../tools/popup/send/send-type.component"; +import { AboutPageComponent } from "../tools/popup/settings/about-page/about-page.component"; +import { MoreFromBitwardenPageComponent } from "../tools/popup/settings/about-page/more-from-bitwarden-page.component"; import { ExportComponent } from "../tools/popup/settings/export.component"; import { ImportBrowserComponent } from "../tools/popup/settings/import/import-browser.component"; import { SettingsV2Component } from "../tools/popup/settings/settings-v2.component"; @@ -60,7 +62,6 @@ import { VaultSettingsComponent } from "../vault/popup/settings/vault-settings.c import { extensionRefreshRedirect, extensionRefreshSwap } from "./extension-refresh-route-utils"; import { debounceNavigationGuard } from "./services/debounce-navigation.service"; -import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component"; import { OptionsComponent } from "./settings/options.component"; import { TabsV2Component } from "./tabs-v2.component"; import { TabsComponent } from "./tabs.component"; @@ -349,10 +350,16 @@ const routes: Routes = [ data: { state: "update-temp-password" }, }, { - path: "help-and-feedback", - component: HelpAndFeedbackComponent, + path: "about", + component: AboutPageComponent, canActivate: [AuthGuard], - data: { state: "help-and-feedback" }, + data: { state: "about" }, + }, + { + path: "more-from-bitwarden", + component: MoreFromBitwardenPageComponent, + canActivate: [AuthGuard], + data: { state: "moreFromBitwarden" }, }, ...extensionRefreshSwap(TabsComponent, TabsV2Component, { path: "tabs", diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index 4381dddf0c..54a9da028f 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -84,7 +84,6 @@ import { AppRoutingModule } from "./app-routing.module"; import { AppComponent } from "./app.component"; import { UserVerificationComponent } from "./components/user-verification.component"; import { ServicesModule } from "./services/services.module"; -import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component"; import { OptionsComponent } from "./settings/options.component"; import { TabsV2Component } from "./tabs-v2.component"; import { TabsComponent } from "./tabs.component"; @@ -185,7 +184,6 @@ import "../platform/popup/locales"; RemovePasswordComponent, VaultSelectComponent, Fido2Component, - HelpAndFeedbackComponent, AutofillComponent, EnvironmentSelectorComponent, AccountSwitcherComponent, diff --git a/apps/browser/src/popup/settings/help-and-feedback.component.ts b/apps/browser/src/popup/settings/help-and-feedback.component.ts deleted file mode 100644 index cba57529f0..0000000000 --- a/apps/browser/src/popup/settings/help-and-feedback.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Component } from "@angular/core"; - -import { BrowserApi } from "../../platform/browser/browser-api"; - -@Component({ - selector: "app-help-and-feedback", - templateUrl: "help-and-feedback.component.html", -}) -export class HelpAndFeedbackComponent { - launchHelp() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.createNewTab("https://bitwarden.com/help/"); - } - launchContactForm() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.createNewTab("https://bitwarden.com/contact/"); - } - - launchForums() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.createNewTab("https://bitwarden.com/getinvolved/"); - } -} diff --git a/apps/browser/src/popup/settings/help-and-feedback.component.html b/apps/browser/src/tools/popup/settings/about-page/about-page.component.html similarity index 51% rename from apps/browser/src/popup/settings/help-and-feedback.component.html rename to apps/browser/src/tools/popup/settings/about-page/about-page.component.html index f2cbfa9355..3ab41cee11 100644 --- a/apps/browser/src/popup/settings/help-and-feedback.component.html +++ b/apps/browser/src/tools/popup/settings/about-page/about-page.component.html @@ -6,34 +6,47 @@

- {{ "helpFeedback" | i18n }} + {{ "about" | i18n }}

-
+
+ +
+ + @@ -43,12 +56,26 @@ appStopClick (click)="launchContactForm()" > -
- -
{{ "contactSupport" | i18n }}
+ +
diff --git a/apps/browser/src/tools/popup/settings/about-page/about-page.component.ts b/apps/browser/src/tools/popup/settings/about-page/about-page.component.ts new file mode 100644 index 0000000000..d87a26948d --- /dev/null +++ b/apps/browser/src/tools/popup/settings/about-page/about-page.component.ts @@ -0,0 +1,84 @@ +import { CommonModule } from "@angular/common"; +import { Component } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { firstValueFrom } from "rxjs"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { DeviceType } from "@bitwarden/common/enums"; +import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { DialogService } from "@bitwarden/components"; + +import { BrowserApi } from "../../../../platform/browser/browser-api"; +import { PopOutComponent } from "../../../../platform/popup/components/pop-out.component"; +import { AboutDialogComponent } from "../about-dialog/about-dialog.component"; + +const RateUrls = { + [DeviceType.ChromeExtension]: + "https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews", + [DeviceType.FirefoxExtension]: + "https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/#reviews", + [DeviceType.OperaExtension]: + "https://addons.opera.com/en/extensions/details/bitwarden-free-password-manager/#feedback-container", + [DeviceType.EdgeExtension]: + "https://microsoftedge.microsoft.com/addons/detail/jbkfoedolllekgbhcbcoahefnbanhhlh", + [DeviceType.VivaldiExtension]: + "https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews", + [DeviceType.SafariExtension]: "https://apps.apple.com/app/bitwarden/id1352778147", +}; + +@Component({ + templateUrl: "about-page.component.html", + standalone: true, + imports: [CommonModule, JslibModule, RouterModule, PopOutComponent], +}) +export class AboutPageComponent { + constructor( + private dialogService: DialogService, + private environmentService: EnvironmentService, + private platformUtilsService: PlatformUtilsService, + ) {} + + about() { + this.dialogService.open(AboutDialogComponent); + } + + async launchHelp() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "continueToHelpCenter" }, + content: { key: "continueToHelpCenterDesc" }, + type: "info", + acceptButtonText: { key: "continue" }, + }); + if (confirmed) { + await BrowserApi.createNewTab("https://bitwarden.com/help/"); + } + } + + async openWebVault() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "continueToWebApp" }, + content: { key: "continueToWebAppDesc" }, + type: "info", + acceptButtonText: { key: "continue" }, + }); + if (confirmed) { + const env = await firstValueFrom(this.environmentService.environment$); + const url = env.getWebVaultUrl(); + await BrowserApi.createNewTab(url); + } + } + + async launchContactForm() { + await BrowserApi.createNewTab("https://bitwarden.com/contact/"); + } + + async launchForums() { + await BrowserApi.createNewTab("https://bitwarden.com/getinvolved/"); + } + + async rate() { + const deviceType = this.platformUtilsService.getDevice(); + await BrowserApi.createNewTab((RateUrls as any)[deviceType]); + } +} diff --git a/apps/browser/src/tools/popup/settings/about-page/more-from-bitwarden-page.component.html b/apps/browser/src/tools/popup/settings/about-page/more-from-bitwarden-page.component.html new file mode 100644 index 0000000000..bf9decca4e --- /dev/null +++ b/apps/browser/src/tools/popup/settings/about-page/more-from-bitwarden-page.component.html @@ -0,0 +1,75 @@ +
+
+ +
+

+ {{ "moreFromBitwarden" | i18n }} +

+
+ +
+
+
+
+
+
+ +
+ + + + + +
+
+
diff --git a/apps/browser/src/tools/popup/settings/about-page/more-from-bitwarden-page.component.ts b/apps/browser/src/tools/popup/settings/about-page/more-from-bitwarden-page.component.ts new file mode 100644 index 0000000000..a9e9e797bf --- /dev/null +++ b/apps/browser/src/tools/popup/settings/about-page/more-from-bitwarden-page.component.ts @@ -0,0 +1,91 @@ +import { CommonModule } from "@angular/common"; +import { Component } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { Observable, firstValueFrom } from "rxjs"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; +import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; +import { DialogService } from "@bitwarden/components"; + +import { BrowserApi } from "../../../../platform/browser/browser-api"; +import { PopOutComponent } from "../../../../platform/popup/components/pop-out.component"; + +@Component({ + templateUrl: "more-from-bitwarden-page.component.html", + standalone: true, + imports: [CommonModule, JslibModule, RouterModule, PopOutComponent], +}) +export class MoreFromBitwardenPageComponent { + canAccessPremium$: Observable; + + constructor( + private dialogService: DialogService, + private billingAccountProfileStateService: BillingAccountProfileStateService, + private environmentService: EnvironmentService, + ) { + this.canAccessPremium$ = billingAccountProfileStateService.hasPremiumFromAnySource$; + } + + async openFreeBitwardenFamiliesPage() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "continueToWebApp" }, + content: { key: "freeBitwardenFamiliesPageDesc" }, + type: "info", + acceptButtonText: { key: "continue" }, + }); + if (confirmed) { + const env = await firstValueFrom(this.environmentService.environment$); + const url = env.getWebVaultUrl(); + await BrowserApi.createNewTab(url + "/#/settings/sponsored-families"); + } + } + + async openBitwardenForBusinessPage() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "continueToBitwardenDotCom" }, + content: { key: "bitwardenForBusinessPageDesc" }, + type: "info", + acceptButtonText: { key: "continue" }, + }); + if (confirmed) { + await BrowserApi.createNewTab("https://bitwarden.com/products/business/"); + } + } + + async openAuthenticatorPage() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "continueToBitwardenDotCom" }, + content: { key: "continueToAuthenticatorPageDesc" }, + type: "info", + acceptButtonText: { key: "continue" }, + }); + if (confirmed) { + await BrowserApi.createNewTab("https://bitwarden.com/products/authenticator"); + } + } + + async openSecretsManagerPage() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "continueToBitwardenDotCom" }, + content: { key: "continueToSecretsManagerPageDesc" }, + type: "info", + acceptButtonText: { key: "continue" }, + }); + if (confirmed) { + await BrowserApi.createNewTab("https://bitwarden.com/products/secrets-manager"); + } + } + + async openPasswordlessDotDevPage() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "continueToBitwardenDotCom" }, + content: { key: "continueToPasswordlessDotDevPageDesc" }, + type: "info", + acceptButtonText: { key: "continue" }, + }); + if (confirmed) { + await BrowserApi.createNewTab("https://bitwarden.com/products/passwordless"); + } + } +} diff --git a/apps/browser/src/tools/popup/settings/settings.component.html b/apps/browser/src/tools/popup/settings/settings.component.html index 7506a07da5..7dba3d0a3d 100644 --- a/apps/browser/src/tools/popup/settings/settings.component.html +++ b/apps/browser/src/tools/popup/settings/settings.component.html @@ -1,15 +1,14 @@ -
- -
+

{{ "settings" | i18n }}

-
+
+ +
-

{{ "manage" | i18n }}

-
- -
-

{{ "account" | i18n }}

-
- -
-
-
-

{{ "tools" | i18n }}

-
- -
-
-
-

{{ "other" | i18n }}

-
- - -
-
diff --git a/apps/browser/src/tools/popup/settings/settings.component.ts b/apps/browser/src/tools/popup/settings/settings.component.ts index d0c5d63092..973efc7203 100644 --- a/apps/browser/src/tools/popup/settings/settings.component.ts +++ b/apps/browser/src/tools/popup/settings/settings.component.ts @@ -1,101 +1,9 @@ -import { Component, OnInit } from "@angular/core"; -import { Router } from "@angular/router"; -import { firstValueFrom, Subject } from "rxjs"; - -import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; -import { DeviceType } from "@bitwarden/common/enums"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { DialogService } from "@bitwarden/components"; - -import { BrowserApi } from "../../../platform/browser/browser-api"; -import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils"; - -import { AboutDialogComponent } from "./about-dialog/about-dialog.component"; - -const RateUrls = { - [DeviceType.ChromeExtension]: - "https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews", - [DeviceType.FirefoxExtension]: - "https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/#reviews", - [DeviceType.OperaExtension]: - "https://addons.opera.com/en/extensions/details/bitwarden-free-password-manager/#feedback-container", - [DeviceType.EdgeExtension]: - "https://microsoftedge.microsoft.com/addons/detail/jbkfoedolllekgbhcbcoahefnbanhhlh", - [DeviceType.VivaldiExtension]: - "https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews", - [DeviceType.SafariExtension]: "https://apps.apple.com/app/bitwarden/id1352778147", -}; +import { Component } from "@angular/core"; @Component({ selector: "tools-settings", templateUrl: "settings.component.html", }) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class SettingsComponent implements OnInit { - private destroy$ = new Subject(); - - constructor( - private platformUtilsService: PlatformUtilsService, - private i18nService: I18nService, - private vaultTimeoutService: VaultTimeoutService, - public messagingService: MessagingService, - private router: Router, - private environmentService: EnvironmentService, - private dialogService: DialogService, - ) {} - - async ngOnInit() {} - - async share() { - const confirmed = await this.dialogService.openSimpleDialog({ - title: { key: "learnOrg" }, - content: { key: "learnOrgConfirmation" }, - type: "info", - }); - if (confirmed) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.createNewTab("https://bitwarden.com/help/about-organizations/"); - } - } - - async webVault() { - const env = await firstValueFrom(this.environmentService.environment$); - const url = env.getWebVaultUrl(); - await BrowserApi.createNewTab(url); - } - - async import() { - await this.router.navigate(["/import"]); - if (await BrowserApi.isPopupOpen()) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserPopupUtils.openCurrentPagePopout(window); - } - } - - export() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/export"]); - } - - about() { - this.dialogService.open(AboutDialogComponent); - } - - rate() { - const deviceType = this.platformUtilsService.getDevice(); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.createNewTab((RateUrls as any)[deviceType]); - } - - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - } +export class SettingsComponent { + constructor() {} }