1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 06:13:38 +00:00

[PM-24985][PM-24986][PM-25211][PM-24987] - [Vault] Migrate components to use Premium badge component (#16227)

* migrate all components to use PremiumBadgeComponent

* move badge component to vault

* move premium badge to vault

* move premium badge to billing

* fix import

* use premium badge in tools new send dropdown

* remove badge module import

* remove module
This commit is contained in:
Jordan Aasen
2025-09-09 13:39:24 -07:00
committed by GitHub
parent 4907820383
commit 30af3d7035
17 changed files with 41 additions and 56 deletions

View File

@@ -1,12 +1,12 @@
import { NgModule } from "@angular/core"; import { NgModule } from "@angular/core";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { ItemModule } from "@bitwarden/components"; import { ItemModule } from "@bitwarden/components";
import { DangerZoneComponent } from "../../../auth/settings/account/danger-zone.component"; import { DangerZoneComponent } from "../../../auth/settings/account/danger-zone.component";
import { HeaderModule } from "../../../layouts/header/header.module"; import { HeaderModule } from "../../../layouts/header/header.module";
import { SharedModule } from "../../../shared"; import { SharedModule } from "../../../shared";
import { AccountFingerprintComponent } from "../../../shared/components/account-fingerprint/account-fingerprint.component"; import { AccountFingerprintComponent } from "../../../shared/components/account-fingerprint/account-fingerprint.component";
import { PremiumBadgeComponent } from "../../../vault/components/premium-badge.component";
import { PoliciesModule } from "../../organizations/policies"; import { PoliciesModule } from "../../organizations/policies";
import { AccountComponent } from "./account.component"; import { AccountComponent } from "./account.component";

View File

@@ -3,6 +3,7 @@
import { Component, Inject, OnInit } from "@angular/core"; import { Component, Inject, OnInit } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms"; import { FormBuilder, Validators } from "@angular/forms";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -15,7 +16,6 @@ import {
} from "@bitwarden/components"; } from "@bitwarden/components";
import { SharedModule } from "../../../shared/shared.module"; import { SharedModule } from "../../../shared/shared.module";
import { PremiumBadgeComponent } from "../../../vault/components/premium-badge.component";
import { EmergencyAccessService } from "../../emergency-access"; import { EmergencyAccessService } from "../../emergency-access";
import { EmergencyAccessType } from "../../emergency-access/enums/emergency-access-type"; import { EmergencyAccessType } from "../../emergency-access/enums/emergency-access-type";

View File

@@ -3,6 +3,7 @@
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { lastValueFrom, Observable, firstValueFrom, switchMap } from "rxjs"; import { lastValueFrom, Observable, firstValueFrom, switchMap } from "rxjs";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
@@ -20,7 +21,6 @@ import { DialogService, ToastService } from "@bitwarden/components";
import { HeaderModule } from "../../../layouts/header/header.module"; import { HeaderModule } from "../../../layouts/header/header.module";
import { SharedModule } from "../../../shared/shared.module"; import { SharedModule } from "../../../shared/shared.module";
import { PremiumBadgeComponent } from "../../../vault/components/premium-badge.component";
import { EmergencyAccessService } from "../../emergency-access"; import { EmergencyAccessService } from "../../emergency-access";
import { EmergencyAccessStatusType } from "../../emergency-access/enums/emergency-access-status-type"; import { EmergencyAccessStatusType } from "../../emergency-access/enums/emergency-access-status-type";
import { EmergencyAccessType } from "../../emergency-access/enums/emergency-access-type"; import { EmergencyAccessType } from "../../emergency-access/enums/emergency-access-type";

View File

@@ -12,6 +12,7 @@ import {
switchMap, switchMap,
} from "rxjs"; } from "rxjs";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
@@ -35,7 +36,6 @@ import { DialogRef, DialogService, ItemModule } from "@bitwarden/components";
import { HeaderModule } from "../../../layouts/header/header.module"; import { HeaderModule } from "../../../layouts/header/header.module";
import { SharedModule } from "../../../shared/shared.module"; import { SharedModule } from "../../../shared/shared.module";
import { PremiumBadgeComponent } from "../../../vault/components/premium-badge.component";
import { TwoFactorRecoveryComponent } from "./two-factor-recovery.component"; import { TwoFactorRecoveryComponent } from "./two-factor-recovery.component";
import { TwoFactorSetupAuthenticatorComponent } from "./two-factor-setup-authenticator.component"; import { TwoFactorSetupAuthenticatorComponent } from "./two-factor-setup-authenticator.component";

View File

@@ -2,11 +2,11 @@ import { importProvidersFrom } from "@angular/core";
import { RouterTestingModule } from "@angular/router/testing"; import { RouterTestingModule } from "@angular/router/testing";
import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { BadgeModule, IconModule } from "@bitwarden/components"; import { BadgeModule, IconModule } from "@bitwarden/components";
import { PreloadedEnglishI18nModule } from "../../../../core/tests"; import { PreloadedEnglishI18nModule } from "../../../../core/tests";
import { PremiumBadgeComponent } from "../../../../vault/components/premium-badge.component";
import { ReportVariant } from "../models/report-variant"; import { ReportVariant } from "../models/report-variant";
import { ReportCardComponent } from "./report-card.component"; import { ReportCardComponent } from "./report-card.component";

View File

@@ -2,11 +2,11 @@ import { importProvidersFrom } from "@angular/core";
import { RouterTestingModule } from "@angular/router/testing"; import { RouterTestingModule } from "@angular/router/testing";
import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { BadgeModule, IconModule } from "@bitwarden/components"; import { BadgeModule, IconModule } from "@bitwarden/components";
import { PreloadedEnglishI18nModule } from "../../../../core/tests"; import { PreloadedEnglishI18nModule } from "../../../../core/tests";
import { PremiumBadgeComponent } from "../../../../vault/components/premium-badge.component";
import { reports } from "../../reports"; import { reports } from "../../reports";
import { ReportVariant } from "../models/report-variant"; import { ReportVariant } from "../models/report-variant";
import { ReportCardComponent } from "../report-card/report-card.component"; import { ReportCardComponent } from "../report-card/report-card.component";

View File

@@ -9,15 +9,9 @@
</a> </a>
<a bitMenuItem (click)="createSend(sendType.File)"> <a bitMenuItem (click)="createSend(sendType.File)">
<i class="bwi bwi-file" slot="start" aria-hidden="true"></i> <i class="bwi bwi-file" slot="start" aria-hidden="true"></i>
<div class="tw-flex tw-items-center tw-gap-2">
{{ "sendTypeFile" | i18n }} {{ "sendTypeFile" | i18n }}
<button <app-premium-badge></app-premium-badge>
type="button" </div>
slot="end"
*ngIf="!(canAccessPremium$ | async)"
bitBadge
variant="success"
>
{{ "premium" | i18n }}
</button>
</a> </a>
</bit-menu> </bit-menu>

View File

@@ -1,19 +1,19 @@
import { CommonModule } from "@angular/common"; import { CommonModule } from "@angular/common";
import { Component, Input } from "@angular/core"; import { Component, Input } from "@angular/core";
import { Router } from "@angular/router";
import { firstValueFrom, Observable, of, switchMap } from "rxjs"; import { firstValueFrom, Observable, of, switchMap } from "rxjs";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
import { BadgeModule, ButtonModule, DialogService, MenuModule } from "@bitwarden/components"; import { ButtonModule, DialogService, MenuModule } from "@bitwarden/components";
import { DefaultSendFormConfigService, SendAddEditDialogComponent } from "@bitwarden/send-ui"; import { DefaultSendFormConfigService, SendAddEditDialogComponent } from "@bitwarden/send-ui";
@Component({ @Component({
selector: "tools-new-send-dropdown", selector: "tools-new-send-dropdown",
templateUrl: "new-send-dropdown.component.html", templateUrl: "new-send-dropdown.component.html",
imports: [JslibModule, CommonModule, ButtonModule, MenuModule, BadgeModule], imports: [JslibModule, CommonModule, ButtonModule, MenuModule, PremiumBadgeComponent],
providers: [DefaultSendFormConfigService], providers: [DefaultSendFormConfigService],
}) })
/** /**
@@ -30,7 +30,6 @@ export class NewSendDropdownComponent {
protected canAccessPremium$: Observable<boolean>; protected canAccessPremium$: Observable<boolean>;
constructor( constructor(
private router: Router,
private billingAccountProfileStateService: BillingAccountProfileStateService, private billingAccountProfileStateService: BillingAccountProfileStateService,
private accountService: AccountService, private accountService: AccountService,
private dialogService: DialogService, private dialogService: DialogService,
@@ -47,16 +46,16 @@ export class NewSendDropdownComponent {
/** /**
* Opens the SendAddEditComponent for a new Send with the provided type. * Opens the SendAddEditComponent for a new Send with the provided type.
* If has user does not have premium access and the type is File, the user will be redirected to the premium settings page. * If has user does not have premium access and the type is File do nothing the PremiumBadgeComponent will handle the flow.
* @param type The type of Send to create. * @param type The type of Send to create.
*/ */
async createSend(type: SendType) { async createSend(type: SendType) {
if (!(await firstValueFrom(this.canAccessPremium$)) && type === SendType.File) { if (!(await firstValueFrom(this.canAccessPremium$)) && type === SendType.File) {
return await this.router.navigate(["settings/subscription/premium"]); return;
} }
const formConfig = await this.addEditFormConfigService.buildConfig("add", undefined, type); const formConfig = await this.addEditFormConfigService.buildConfig("add", undefined, type);
await SendAddEditDialogComponent.open(this.dialogService, { formConfig }); SendAddEditDialogComponent.open(this.dialogService, { formConfig });
} }
} }

View File

@@ -25,17 +25,10 @@
type="button" type="button"
(click)="openAttachmentsDialog()" (click)="openAttachmentsDialog()"
> >
<p class="tw-m-0"> <div class="tw-flex tw-items-center tw-gap-2">
{{ "attachments" | i18n }} {{ "attachments" | i18n }}
<span <app-premium-badge></app-premium-badge>
*ngIf="!(canAccessAttachments$ | async)" </div>
bitBadge
variant="success"
class="tw-ml-2"
>
{{ "premium" | i18n }}
</span>
</p>
<i slot="end" class="bwi bwi-angle-right" aria-hidden="true"></i> <i slot="end" class="bwi bwi-angle-right" aria-hidden="true"></i>
</button> </button>
</bit-item> </bit-item>

View File

@@ -7,6 +7,7 @@ import { firstValueFrom, Subject, switchMap } from "rxjs";
import { map } from "rxjs/operators"; import { map } from "rxjs/operators";
import { CollectionView } from "@bitwarden/admin-console/common"; import { CollectionView } from "@bitwarden/admin-console/common";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { VaultViewPasswordHistoryService } from "@bitwarden/angular/services/view-password-history.service"; import { VaultViewPasswordHistoryService } from "@bitwarden/angular/services/view-password-history.service";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
@@ -131,6 +132,7 @@ export type VaultItemDialogResult = UnionOfValues<typeof VaultItemDialogResult>;
CipherFormModule, CipherFormModule,
AsyncActionsModule, AsyncActionsModule,
ItemModule, ItemModule,
PremiumBadgeComponent,
], ],
providers: [ providers: [
{ provide: PremiumUpgradePromptService, useClass: WebVaultPremiumUpgradePromptService }, { provide: PremiumUpgradePromptService, useClass: WebVaultPremiumUpgradePromptService },

View File

@@ -0,0 +1 @@
export * from "./premium-badge.component";

View File

@@ -6,12 +6,13 @@ import { BadgeModule } from "@bitwarden/components";
@Component({ @Component({
selector: "app-premium-badge", selector: "app-premium-badge",
standalone: true,
template: ` template: `
<button type="button" *appNotPremium bitBadge variant="success" (click)="premiumRequired()"> <button type="button" *appNotPremium bitBadge variant="success" (click)="premiumRequired()">
{{ "premium" | i18n }} {{ "premium" | i18n }}
</button> </button>
`, `,
imports: [JslibModule, BadgeModule], imports: [BadgeModule, JslibModule],
}) })
export class PremiumBadgeComponent { export class PremiumBadgeComponent {
constructor(private messagingService: MessagingService) {} constructor(private messagingService: MessagingService) {}

View File

@@ -17,7 +17,7 @@ class MockMessagingService implements MessageSender {
} }
export default { export default {
title: "Web/Premium Badge", title: "Billing/Premium Badge",
component: PremiumBadgeComponent, component: PremiumBadgeComponent,
decorators: [ decorators: [
moduleMetadata({ moduleMetadata({

View File

@@ -16,10 +16,10 @@
[routerLink]="buildRouterLink(sendType.File)" [routerLink]="buildRouterLink(sendType.File)"
[queryParams]="buildQueryParams(sendType.File)" [queryParams]="buildQueryParams(sendType.File)"
> >
<div class="tw-flex tw-items-center tw-gap-2">
<i class="bwi bwi-file" slot="start" aria-hidden="true"></i> <i class="bwi bwi-file" slot="start" aria-hidden="true"></i>
{{ "sendTypeFile" | i18n }} {{ "sendTypeFile" | i18n }}
<button type="button" slot="end" *ngIf="hasNoPremium" bitBadge variant="success"> <app-premium-badge></app-premium-badge>
{{ "premium" | i18n }} </div>
</button>
</a> </a>
</bit-menu> </bit-menu>

View File

@@ -1,18 +1,19 @@
import { CommonModule } from "@angular/common"; import { CommonModule } from "@angular/common";
import { Component, Input, OnInit } from "@angular/core"; import { Component, Input, OnInit } from "@angular/core";
import { Router, RouterLink } from "@angular/router"; import { RouterLink } from "@angular/router";
import { firstValueFrom } from "rxjs"; import { firstValueFrom } from "rxjs";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
import { BadgeModule, ButtonModule, ButtonType, MenuModule } from "@bitwarden/components"; import { ButtonModule, ButtonType, MenuModule } from "@bitwarden/components";
@Component({ @Component({
selector: "tools-new-send-dropdown", selector: "tools-new-send-dropdown",
templateUrl: "new-send-dropdown.component.html", templateUrl: "new-send-dropdown.component.html",
imports: [JslibModule, CommonModule, ButtonModule, RouterLink, MenuModule, BadgeModule], imports: [JslibModule, CommonModule, ButtonModule, RouterLink, MenuModule, PremiumBadgeComponent],
}) })
export class NewSendDropdownComponent implements OnInit { export class NewSendDropdownComponent implements OnInit {
@Input() hideIcon: boolean = false; @Input() hideIcon: boolean = false;
@@ -23,7 +24,6 @@ export class NewSendDropdownComponent implements OnInit {
hasNoPremium = false; hasNoPremium = false;
constructor( constructor(
private router: Router,
private billingAccountProfileStateService: BillingAccountProfileStateService, private billingAccountProfileStateService: BillingAccountProfileStateService,
private accountService: AccountService, private accountService: AccountService,
) {} ) {}

View File

@@ -121,18 +121,11 @@
/> />
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="cipher.login.totp"> <bit-form-field *ngIf="cipher.login.totp">
<bit-label [appTextDrag]="totpCodeCopyObj?.totpCode" <bit-label [appTextDrag]="totpCodeCopyObj?.totpCode">
>{{ "verificationCodeTotp" | i18n }} <div class="tw-flex tw-items-center tw-gap-3">
<span {{ "verificationCodeTotp" | i18n }}
*ngIf="!(isPremium$ | async)" <app-premium-badge></app-premium-badge>
bitBadge </div>
variant="success"
class="tw-ml-2 tw-cursor-pointer"
(click)="getPremium(cipher.organizationId)"
slot="end"
>
{{ "premium" | i18n }}
</span>
</bit-label> </bit-label>
<input <input
id="totp" id="totp"

View File

@@ -14,6 +14,7 @@ import {
} from "@angular/core"; } from "@angular/core";
import { Observable, switchMap } from "rxjs"; import { Observable, switchMap } from "rxjs";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
@@ -56,6 +57,7 @@ type TotpCodeValues = {
BitTotpCountdownComponent, BitTotpCountdownComponent,
ReadOnlyCipherCardComponent, ReadOnlyCipherCardComponent,
LinkModule, LinkModule,
PremiumBadgeComponent,
], ],
}) })
export class LoginCredentialsViewComponent implements OnChanges { export class LoginCredentialsViewComponent implements OnChanges {