mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-23713] premium badge interaction (#16911)
* feature flag * new upgrade dialog component and moved pricing service into libs first draft * moved pricing service to libs/common removed toast service from the pricing service and implemented error handling in calling components # Conflicts: # apps/web/src/app/billing/individual/upgrade/upgrade-payment/upgrade-payment.component.ts * moved new premium upgrade dialog component to libs/angular * badge opens new dialog in browser extension * adds new dialog to desktop and fixes tests * updates send dropdown to use premium prompt service * styling and copy updates * implement in web and desktop * unit tests * converting premium reports to use premium badge, and some cleanup * fixes issue after merge * linter errors * pr feedback * handle async promise correctly * full sync after the premium upgrade is complete * fixing test * add padding to bottom of card in new dialog * add support for self hosting * fixing tests * fix test * Update has-premium.guard.ts * pr feedback * fix build and pr feedback * fix build * prettier * fixing stories and making badge line height consistent * pr feedback * updated upgrade dialog to no longer use pricing card * fixing incorrect markup and removing unused bits * formatting * pr feedback removing unused message keys and adding back in code that was erroneously removed * change detection * close dialog when error * claude pr feedback
This commit is contained in:
@@ -19,14 +19,23 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
|
||||
import { CalloutModule, DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
import { DesktopPremiumUpgradePromptService } from "../../../services/desktop-premium-upgrade-prompt.service";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-send-add-edit",
|
||||
templateUrl: "add-edit.component.html",
|
||||
imports: [CommonModule, JslibModule, ReactiveFormsModule, CalloutModule],
|
||||
providers: [
|
||||
{
|
||||
provide: PremiumUpgradePromptService,
|
||||
useClass: DesktopPremiumUpgradePromptService,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddEditComponent extends BaseAddEditComponent {
|
||||
constructor(
|
||||
@@ -45,6 +54,7 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
accountService: AccountService,
|
||||
toastService: ToastService,
|
||||
premiumUpgradePromptService: PremiumUpgradePromptService,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@@ -62,6 +72,7 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
billingAccountProfileStateService,
|
||||
accountService,
|
||||
toastService,
|
||||
premiumUpgradePromptService,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4193,5 +4193,29 @@
|
||||
},
|
||||
"cardNumberLabel": {
|
||||
"message": "Card number"
|
||||
},
|
||||
"upgradeNow": {
|
||||
"message": "Upgrade now"
|
||||
},
|
||||
"builtInAuthenticator": {
|
||||
"message": "Built-in authenticator"
|
||||
},
|
||||
"secureFileStorage": {
|
||||
"message": "Secure file storage"
|
||||
},
|
||||
"emergencyAccess": {
|
||||
"message": "Emergency access"
|
||||
},
|
||||
"breachMonitoring": {
|
||||
"message": "Breach monitoring"
|
||||
},
|
||||
"andMoreFeatures": {
|
||||
"message": "And more!"
|
||||
},
|
||||
"planDescPremium": {
|
||||
"message": "Complete online security"
|
||||
},
|
||||
"upgradeToPremium": {
|
||||
"message": "Upgrade to Premium"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,31 @@
|
||||
import { TestBed } from "@angular/core/testing";
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { PremiumUpgradeDialogComponent } from "@bitwarden/angular/billing/components";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { DesktopPremiumUpgradePromptService } from "./desktop-premium-upgrade-prompt.service";
|
||||
|
||||
describe("DesktopPremiumUpgradePromptService", () => {
|
||||
let service: DesktopPremiumUpgradePromptService;
|
||||
let messager: MockProxy<MessagingService>;
|
||||
let configService: MockProxy<ConfigService>;
|
||||
let dialogService: MockProxy<DialogService>;
|
||||
|
||||
beforeEach(async () => {
|
||||
messager = mock<MessagingService>();
|
||||
configService = mock<ConfigService>();
|
||||
dialogService = mock<DialogService>();
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
providers: [
|
||||
DesktopPremiumUpgradePromptService,
|
||||
{ provide: MessagingService, useValue: messager },
|
||||
{ provide: ConfigService, useValue: configService },
|
||||
{ provide: DialogService, useValue: dialogService },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
@@ -22,9 +33,38 @@ describe("DesktopPremiumUpgradePromptService", () => {
|
||||
});
|
||||
|
||||
describe("promptForPremium", () => {
|
||||
it("navigates to the premium update screen", async () => {
|
||||
let openSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
openSpy = jest.spyOn(PremiumUpgradeDialogComponent, "open").mockImplementation();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
openSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("opens the new premium upgrade dialog when feature flag is enabled", async () => {
|
||||
configService.getFeatureFlag.mockResolvedValue(true);
|
||||
|
||||
await service.promptForPremium();
|
||||
|
||||
expect(configService.getFeatureFlag).toHaveBeenCalledWith(
|
||||
FeatureFlag.PM23713_PremiumBadgeOpensNewPremiumUpgradeDialog,
|
||||
);
|
||||
expect(openSpy).toHaveBeenCalledWith(dialogService);
|
||||
expect(messager.send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sends openPremium message when feature flag is disabled", async () => {
|
||||
configService.getFeatureFlag.mockResolvedValue(false);
|
||||
|
||||
await service.promptForPremium();
|
||||
|
||||
expect(configService.getFeatureFlag).toHaveBeenCalledWith(
|
||||
FeatureFlag.PM23713_PremiumBadgeOpensNewPremiumUpgradeDialog,
|
||||
);
|
||||
expect(messager.send).toHaveBeenCalledWith("openPremium");
|
||||
expect(openSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
import { inject } from "@angular/core";
|
||||
|
||||
import { PremiumUpgradeDialogComponent } from "@bitwarden/angular/billing/components";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
/**
|
||||
* This class handles the premium upgrade process for the desktop.
|
||||
*/
|
||||
export class DesktopPremiumUpgradePromptService implements PremiumUpgradePromptService {
|
||||
private messagingService = inject(MessagingService);
|
||||
private configService = inject(ConfigService);
|
||||
private dialogService = inject(DialogService);
|
||||
|
||||
async promptForPremium() {
|
||||
this.messagingService.send("openPremium");
|
||||
const showNewDialog = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.PM23713_PremiumBadgeOpensNewPremiumUpgradeDialog,
|
||||
);
|
||||
|
||||
if (showNewDialog) {
|
||||
PremiumUpgradeDialogComponent.open(this.dialogService);
|
||||
} else {
|
||||
this.messagingService.send("openPremium");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ config.content = [
|
||||
"../../libs/key-management-ui/src/**/*.{html,ts}",
|
||||
"../../libs/angular/src/**/*.{html,ts}",
|
||||
"../../libs/vault/src/**/*.{html,ts,mdx}",
|
||||
"../../libs/pricing/src/**/*.{html,ts}",
|
||||
];
|
||||
|
||||
module.exports = config;
|
||||
|
||||
Reference in New Issue
Block a user