[PM-8228] - Create new Premium Component (#10514)
* add new premium component * finish new premium component * revert change to config service * hide copy changes behind feature flag * revert keys back to original * remove stateService and translation key * add missing translation key * add missing key
This commit is contained in:
parent
199ac3de45
commit
a72ec8ab89
|
@ -1082,6 +1082,9 @@
|
|||
"ppremiumSignUpStorage": {
|
||||
"message": "1 GB encrypted storage for file attachments."
|
||||
},
|
||||
"premiumSignUpEmergency": {
|
||||
"message": "Emergency access"
|
||||
},
|
||||
"premiumSignUpTwoStepOptions": {
|
||||
"message": "Proprietary two-step login options such as YubiKey and Duo."
|
||||
},
|
||||
|
@ -1103,6 +1106,9 @@
|
|||
"premiumPurchaseAlert": {
|
||||
"message": "You can purchase Premium membership on the bitwarden.com web vault. Do you want to visit the website now?"
|
||||
},
|
||||
"premiumPurchaseAlertV2": {
|
||||
"message": "You can purchase Premium from your account settings on the Bitwarden web app."
|
||||
},
|
||||
"premiumCurrentMember": {
|
||||
"message": "You are a Premium member!"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<popup-page>
|
||||
<popup-header slot="header" pageTitle="{{ 'premiumMembership' | i18n }}" showBackButton>
|
||||
<ng-container slot="end">
|
||||
<app-pop-out></app-pop-out>
|
||||
</ng-container>
|
||||
</popup-header>
|
||||
|
||||
<div class="tw-flex tw-flex-col tw-p-2">
|
||||
<h2 class="tw-font-bold">{{ "premiumFeatures" | i18n }}</h2>
|
||||
<bit-section>
|
||||
<bit-card>
|
||||
<div class="tw-flex tw-flex-col tw-p-3">
|
||||
<ul class="tw-list-disc tw-pl-5 tw-space-y-2 tw-break-words">
|
||||
<li>
|
||||
{{ "ppremiumSignUpStorage" | i18n }}
|
||||
</li>
|
||||
<li>
|
||||
{{ "ppremiumSignUpTwoStepOptions" | i18n }}
|
||||
</li>
|
||||
<li>
|
||||
{{ "premiumSignUpEmergency" | i18n }}
|
||||
</li>
|
||||
<li>
|
||||
{{ "ppremiumSignUpReports" | i18n }}
|
||||
</li>
|
||||
<li>
|
||||
{{ "ppremiumSignUpTotp" | i18n }}
|
||||
</li>
|
||||
<li>
|
||||
{{ "ppremiumSignUpSupport" | i18n }}
|
||||
</li>
|
||||
<li>
|
||||
{{ "ppremiumSignUpFuture" | i18n }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p class="tw-mt-5 tw-mb-0">{{ priceString }}</p>
|
||||
</bit-card>
|
||||
</bit-section>
|
||||
<button bitButton type="submit" buttonType="primary" (click)="purchase()" class="tw-mb-3">
|
||||
<b>{{ "premiumPurchase" | i18n }}</b>
|
||||
<i class="bwi bwi-external-link" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button
|
||||
#refreshBtn
|
||||
type="button"
|
||||
(click)="refresh()"
|
||||
[disabled]="$any(refreshBtn).loading"
|
||||
[appApiAction]="refreshPromise"
|
||||
bitButton
|
||||
>
|
||||
<span [hidden]="$any(refreshBtn).loading">{{ "premiumRefresh" | i18n }}</span>
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin bwi-lg bwi-fw"
|
||||
[hidden]="!$any(refreshBtn).loading"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
</div>
|
||||
</popup-page>
|
|
@ -0,0 +1,86 @@
|
|||
import { CommonModule, CurrencyPipe, Location } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
import { RouterModule } from "@angular/router";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import {
|
||||
ButtonModule,
|
||||
CardComponent,
|
||||
DialogService,
|
||||
ItemModule,
|
||||
SectionComponent,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component";
|
||||
import { PopOutComponent } from "../../../platform/popup/components/pop-out.component";
|
||||
import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component";
|
||||
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-premium",
|
||||
templateUrl: "premium-v2.component.html",
|
||||
standalone: true,
|
||||
imports: [
|
||||
ButtonModule,
|
||||
CardComponent,
|
||||
CommonModule,
|
||||
CurrentAccountComponent,
|
||||
ItemModule,
|
||||
JslibModule,
|
||||
PopupPageComponent,
|
||||
PopupHeaderComponent,
|
||||
PopOutComponent,
|
||||
RouterModule,
|
||||
SectionComponent,
|
||||
],
|
||||
})
|
||||
export class PremiumV2Component extends BasePremiumComponent {
|
||||
priceString: string;
|
||||
|
||||
constructor(
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
apiService: ApiService,
|
||||
configService: ConfigService,
|
||||
logService: LogService,
|
||||
private location: Location,
|
||||
private currencyPipe: CurrencyPipe,
|
||||
dialogService: DialogService,
|
||||
environmentService: EnvironmentService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
platformUtilsService,
|
||||
apiService,
|
||||
configService,
|
||||
logService,
|
||||
dialogService,
|
||||
environmentService,
|
||||
billingAccountProfileStateService,
|
||||
);
|
||||
|
||||
// Support old price string. Can be removed in future once all translations are properly updated.
|
||||
const thePrice = this.currencyPipe.transform(this.price, "$");
|
||||
// Safari extension crashes due to $1 appearing in the price string ($10.00). Escape the $ to fix.
|
||||
const formattedPrice = this.platformUtilsService.isSafari()
|
||||
? thePrice.replace("$", "$$$")
|
||||
: thePrice;
|
||||
this.priceString = i18nService.t("premiumPrice", formattedPrice);
|
||||
if (this.priceString.indexOf("%price%") > -1) {
|
||||
this.priceString = this.priceString.replace("%price%", thePrice);
|
||||
}
|
||||
}
|
||||
|
||||
goBack() {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
|
@ -4,11 +4,11 @@ import { Component } from "@angular/core";
|
|||
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
|
@ -22,7 +22,7 @@ export class PremiumComponent extends BasePremiumComponent {
|
|||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
apiService: ApiService,
|
||||
stateService: StateService,
|
||||
configService: ConfigService,
|
||||
logService: LogService,
|
||||
private location: Location,
|
||||
private currencyPipe: CurrencyPipe,
|
||||
|
@ -34,8 +34,8 @@ export class PremiumComponent extends BasePremiumComponent {
|
|||
i18nService,
|
||||
platformUtilsService,
|
||||
apiService,
|
||||
configService,
|
||||
logService,
|
||||
stateService,
|
||||
dialogService,
|
||||
environmentService,
|
||||
billingAccountProfileStateService,
|
||||
|
|
|
@ -46,6 +46,7 @@ import { ExcludedDomainsV1Component } from "../autofill/popup/settings/excluded-
|
|||
import { ExcludedDomainsComponent } from "../autofill/popup/settings/excluded-domains.component";
|
||||
import { NotificationsSettingsV1Component } from "../autofill/popup/settings/notifications-v1.component";
|
||||
import { NotificationsSettingsComponent } from "../autofill/popup/settings/notifications.component";
|
||||
import { PremiumV2Component } from "../billing/popup/settings/premium-v2.component";
|
||||
import { PremiumComponent } from "../billing/popup/settings/premium.component";
|
||||
import BrowserPopupUtils from "../platform/popup/browser-popup-utils";
|
||||
import { popupRouterCacheGuard } from "../platform/popup/view-cache/popup-router-cache.service";
|
||||
|
@ -337,12 +338,12 @@ const routes: Routes = [
|
|||
canActivate: [authGuard],
|
||||
data: { state: "excluded-domains" },
|
||||
}),
|
||||
{
|
||||
...extensionRefreshSwap(PremiumComponent, PremiumV2Component, {
|
||||
path: "premium",
|
||||
component: PremiumComponent,
|
||||
canActivate: [authGuard],
|
||||
data: { state: "premium" },
|
||||
},
|
||||
}),
|
||||
...extensionRefreshSwap(AppearanceComponent, AppearanceV2Component, {
|
||||
path: "appearance",
|
||||
canActivate: [authGuard],
|
||||
|
|
|
@ -1174,6 +1174,9 @@
|
|||
"premiumPurchaseAlert": {
|
||||
"message": "You can purchase premium membership on the bitwarden.com web vault. Do you want to visit the website now?"
|
||||
},
|
||||
"premiumPurchaseAlertV2": {
|
||||
"message": "You can purchase Premium from your account settings on the Bitwarden web app."
|
||||
},
|
||||
"premiumCurrentMember": {
|
||||
"message": "You are a premium member!"
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Component } from "@angular/core";
|
|||
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
|
@ -19,6 +20,7 @@ export class PremiumComponent extends BasePremiumComponent {
|
|||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
apiService: ApiService,
|
||||
configService: ConfigService,
|
||||
logService: LogService,
|
||||
stateService: StateService,
|
||||
dialogService: DialogService,
|
||||
|
@ -29,6 +31,7 @@ export class PremiumComponent extends BasePremiumComponent {
|
|||
i18nService,
|
||||
platformUtilsService,
|
||||
apiService,
|
||||
configService,
|
||||
logService,
|
||||
stateService,
|
||||
dialogService,
|
||||
|
|
|
@ -3,12 +3,13 @@ import { firstValueFrom, Observable } from "rxjs";
|
|||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { DialogService, SimpleDialogOptions } from "@bitwarden/components";
|
||||
|
||||
@Directive()
|
||||
export class PremiumComponent implements OnInit {
|
||||
|
@ -16,13 +17,14 @@ export class PremiumComponent implements OnInit {
|
|||
price = 10;
|
||||
refreshPromise: Promise<any>;
|
||||
cloudWebVaultUrl: string;
|
||||
extensionRefreshFlagEnabled: boolean;
|
||||
|
||||
constructor(
|
||||
protected i18nService: I18nService,
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
protected apiService: ApiService,
|
||||
protected configService: ConfigService,
|
||||
private logService: LogService,
|
||||
protected stateService: StateService,
|
||||
protected dialogService: DialogService,
|
||||
private environmentService: EnvironmentService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
|
@ -32,6 +34,9 @@ export class PremiumComponent implements OnInit {
|
|||
|
||||
async ngOnInit() {
|
||||
this.cloudWebVaultUrl = await firstValueFrom(this.environmentService.cloudWebVaultUrl$);
|
||||
this.extensionRefreshFlagEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.ExtensionRefresh,
|
||||
);
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
|
@ -45,11 +50,20 @@ export class PremiumComponent implements OnInit {
|
|||
}
|
||||
|
||||
async purchase() {
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "premiumPurchase" },
|
||||
content: { key: "premiumPurchaseAlert" },
|
||||
const dialogOpts: SimpleDialogOptions = {
|
||||
title: { key: "continueToBitwardenDotCom" },
|
||||
content: {
|
||||
key: this.extensionRefreshFlagEnabled ? "premiumPurchaseAlertV2" : "premiumPurchaseAlert",
|
||||
},
|
||||
type: "info",
|
||||
});
|
||||
};
|
||||
|
||||
if (this.extensionRefreshFlagEnabled) {
|
||||
dialogOpts.acceptButtonText = { key: "continue" };
|
||||
dialogOpts.cancelButtonText = { key: "close" };
|
||||
}
|
||||
|
||||
const confirmed = await this.dialogService.openSimpleDialog(dialogOpts);
|
||||
|
||||
if (confirmed) {
|
||||
this.platformUtilsService.launchUri(
|
||||
|
|
Loading…
Reference in New Issue