[PM-33308] Use providedIn: "root" for web-based billing services (#19449)

* refactor(billing): move billing services to providedIn root and remove component-level providers

* refactor(billing): remove missed redundant billing service providers

* refactor(billing): move 4 additional billing services to providedIn root and remove empty modules
This commit is contained in:
Alex Morask 2026-03-11 10:38:43 -05:00 committed by GitHub
parent c8c66a8bf1
commit e5a6312fee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 13 additions and 88 deletions

View File

@ -27,7 +27,6 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { getById } from "@bitwarden/common/platform/misc";
import { BannerModule, SvgModule } from "@bitwarden/components";
import { OrganizationWarningsModule } from "@bitwarden/web-vault/app/billing/organizations/warnings/organization-warnings.module";
import { OrganizationWarningsService } from "@bitwarden/web-vault/app/billing/organizations/warnings/services";
import { NonIndividualSubscriber } from "@bitwarden/web-vault/app/billing/types";
import { TaxIdWarningComponent } from "@bitwarden/web-vault/app/billing/warnings/components";
@ -52,7 +51,6 @@ import { WebLayoutModule } from "../../../layouts/web-layout.module";
BannerModule,
TaxIdWarningComponent,
TaxIdWarningComponent,
OrganizationWarningsModule,
],
})
export class OrganizationLayoutComponent implements OnInit {

View File

@ -2,7 +2,6 @@ import { ScrollingModule } from "@angular/cdk/scrolling";
import { NgModule } from "@angular/core";
import { ScrollLayoutDirective } from "@bitwarden/components";
import { OrganizationWarningsModule } from "@bitwarden/web-vault/app/billing/organizations/warnings/organization-warnings.module";
import { HeaderModule } from "../../layouts/header/header.module";
@ -22,7 +21,6 @@ import { AccessSelectorModule } from "./shared/components/access-selector";
HeaderModule,
ScrollingModule,
ScrollLayoutDirective,
OrganizationWarningsModule,
],
declarations: [GroupsComponent, GroupAddEditComponent],
})

View File

@ -25,7 +25,7 @@ export type UpgradePremiumToOrganizationRequest = {
billingAddress: Pick<BillingAddress, "country" | "postalCode" | "taxId">;
};
@Injectable()
@Injectable({ providedIn: "root" })
export class AccountBillingClient {
private endpoint = "/account/billing/vnext";

View File

@ -4,7 +4,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { OrganizationWarningsResponse } from "@bitwarden/web-vault/app/billing/organizations/warnings/types";
@Injectable()
@Injectable({ providedIn: "root" })
export class OrganizationBillingClient {
constructor(private apiService: ApiService) {}

View File

@ -69,7 +69,7 @@ export interface TaxAmounts {
total: number;
}
@Injectable()
@Injectable({ providedIn: "root" })
export class PreviewInvoiceClient {
constructor(private apiService: ApiService) {}

View File

@ -22,7 +22,7 @@ type Result<T> =
message: string;
};
@Injectable()
@Injectable({ providedIn: "root" })
export class SubscriberBillingClient {
constructor(private apiService: ApiService) {}

View File

@ -30,7 +30,6 @@ type View = {
HeaderModule,
SharedModule,
],
providers: [SubscriberBillingClient],
})
export class AccountPaymentDetailsComponent {
private viewState$ = new BehaviorSubject<View | null>(null);

View File

@ -65,7 +65,6 @@ const RouteParamValues = {
I18nPipe,
PricingCardComponent,
],
providers: [AccountBillingClient],
})
export class CloudHostedPremiumComponent {
protected hasPremiumFromAnyOrganization$: Observable<boolean>;

View File

@ -8,7 +8,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { UserId } from "@bitwarden/user-core";
import { AccountBillingClient } from "@bitwarden/web-vault/app/billing/clients";
@Injectable()
@Injectable({ providedIn: "root" })
export class PremiumSubscriptionRoutingService {
constructor(
private accountService: AccountService,

View File

@ -17,7 +17,6 @@ import { AccountBillingClient } from "../clients/account-billing.client";
@Component({
templateUrl: "subscription.component.html",
standalone: false,
providers: [AccountBillingClient],
})
export class SubscriptionComponent implements OnInit {
showSubscriptionPageLink$: Observable<boolean>;

View File

@ -41,7 +41,6 @@ type AdjustAccountSubscriptionStorageDialogResult = "closed" | "submitted";
@Component({
templateUrl: "./adjust-account-subscription-storage-dialog.component.html",
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [AccountBillingClient],
imports: [
AsyncActionsModule,
ButtonModule,

View File

@ -60,7 +60,6 @@ import {
SubscriptionCardComponent,
TypographyModule,
],
providers: [AccountBillingClient],
})
export class CloudHostedAccountSubscriptionComponent {
private readonly accountService = inject(AccountService);

View File

@ -28,14 +28,12 @@ import {
DialogService,
} from "@bitwarden/components";
import { AccountBillingClient, PreviewInvoiceClient } from "../../../clients";
import { BillingServicesModule } from "../../../services";
import {
PremiumOrgUpgradePaymentComponent,
PremiumOrgUpgradePaymentResult,
} from "../premium-org-upgrade-payment/premium-org-upgrade-payment.component";
import { PremiumOrgUpgradePlanSelectionComponent } from "../premium-org-upgrade-plan-selection/premium-org-upgrade-plan-selection.component";
import { UpgradePaymentService } from "../upgrade-payment/services/upgrade-payment.service";
export const PremiumOrgUpgradeDialogStatus = {
Closed: "closed",
@ -84,7 +82,6 @@ export type PremiumOrgUpgradeDialogParams = {
PremiumOrgUpgradePlanSelectionComponent,
PremiumOrgUpgradePaymentComponent,
],
providers: [UpgradePaymentService, AccountBillingClient, PreviewInvoiceClient],
templateUrl: "./premium-org-upgrade-dialog.component.html",
})
export class PremiumOrgUpgradeDialogComponent implements OnInit {

View File

@ -83,7 +83,6 @@ export type PremiumOrgUpgradePaymentResult = {
EnterBillingAddressComponent,
DisplayPaymentMethodInlineComponent,
],
providers: [PremiumOrgUpgradeService],
templateUrl: "./premium-org-upgrade-payment.component.html",
})
export class PremiumOrgUpgradePaymentComponent implements OnInit, AfterViewInit {

View File

@ -46,7 +46,7 @@ export interface InvoicePreview {
newPlanProratedAmount?: number;
}
@Injectable()
@Injectable({ providedIn: "root" })
export class PremiumOrgUpgradeService {
constructor(
private accountBillingClient: AccountBillingClient,

View File

@ -15,10 +15,8 @@ import {
DialogService,
} from "@bitwarden/components";
import { AccountBillingClient, PreviewInvoiceClient } from "../../../clients";
import { BillingServicesModule } from "../../../services";
import { UpgradeAccountComponent } from "../upgrade-account/upgrade-account.component";
import { UpgradePaymentService } from "../upgrade-payment/services/upgrade-payment.service";
import {
UpgradePaymentComponent,
UpgradePaymentResult,
@ -74,7 +72,6 @@ export type UnifiedUpgradeDialogParams = {
UpgradePaymentComponent,
BillingServicesModule,
],
providers: [UpgradePaymentService, AccountBillingClient, PreviewInvoiceClient],
templateUrl: "./unified-upgrade-dialog.component.html",
})
export class UnifiedUpgradeDialogComponent implements OnInit {

View File

@ -53,7 +53,7 @@ export type PaymentFormValues = {
/**
* Service for handling payment submission and sales tax calculation for upgrade payment component
*/
@Injectable()
@Injectable({ providedIn: "root" })
export class UpgradePaymentService {
constructor(
private organizationBillingService: OrganizationBillingServiceAbstraction,

View File

@ -97,7 +97,6 @@ export type UpgradePaymentParams = {
EnterBillingAddressComponent,
BillingServicesModule,
],
providers: [UpgradePaymentService],
templateUrl: "./upgrade-payment.component.html",
})
export class UpgradePaymentComponent implements OnInit, AfterViewInit {

View File

@ -117,7 +117,6 @@ interface OnSuccessArgs {
EnterBillingAddressComponent,
CardComponent,
],
providers: [SubscriberBillingClient, PreviewInvoiceClient],
})
export class ChangePlanDialogComponent implements OnInit, OnDestroy {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals

View File

@ -51,7 +51,6 @@ import { IconComponent, ToastService } from "@bitwarden/components";
import { KeyService } from "@bitwarden/key-management";
import { Cart, CartSummaryComponent, DiscountTypes } from "@bitwarden/pricing";
import {
AccountBillingClient,
OrganizationSubscriptionPlan,
OrganizationSubscriptionPurchase,
PreviewInvoiceClient,
@ -96,12 +95,6 @@ const Allowed2020PlansForLegacyProviders = [
IconComponent,
CartSummaryComponent,
],
providers: [
AccountBillingClient,
SubscriberBillingClient,
PreviewInvoiceClient,
PremiumOrgUpgradeService,
],
})
export class OrganizationPlansComponent implements OnInit, OnDestroy {
// ViewChildren

View File

@ -1,12 +0,0 @@
import { NgModule } from "@angular/core";
import {
OrganizationBillingClient,
SubscriberBillingClient,
} from "@bitwarden/web-vault/app/billing/clients";
import { OrganizationWarningsService } from "@bitwarden/web-vault/app/billing/organizations/warnings/services";
@NgModule({
providers: [OrganizationBillingClient, OrganizationWarningsService, SubscriberBillingClient],
})
export class OrganizationWarningsModule {}

View File

@ -42,7 +42,7 @@ const format = (date: Date) =>
year: "numeric",
});
@Injectable()
@Injectable({ providedIn: "root" })
export class OrganizationWarningsService {
private cache$ = new Map<OrganizationId, Observable<OrganizationWarningsResponse>>();

View File

@ -127,7 +127,6 @@ const positiveNumberValidator =
`,
standalone: true,
imports: [SharedModule],
providers: [SubscriberBillingClient],
})
export class AddAccountCreditDialogComponent {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals

View File

@ -53,7 +53,6 @@ type DialogParams = {
`,
standalone: true,
imports: [EnterPaymentMethodComponent, SharedModule],
providers: [SubscriberBillingClient],
})
export class ChangePaymentMethodDialogComponent extends SubmitPaymentMethodDialogComponent {
protected override subscriber: BitwardenSubscriber;

View File

@ -1,4 +1,3 @@
import { CurrencyPipe } from "@angular/common";
import { Component, Input } from "@angular/core";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -16,7 +15,7 @@ import { AddAccountCreditDialogComponent } from "./add-account-credit-dialog.com
selector: "app-display-account-credit",
template: `
<bit-section>
<h2 bitTypography="h2">{{ "accountCredit" | i18n }}: {{ formattedCredit }}</h2>
<h2 bitTypography="h2">{{ "accountCredit" | i18n }}: {{ credit ?? 0 | currency: "$" }}</h2>
<p>{{ "availableCreditAppliedToInvoice" | i18n }}</p>
<button type="button" bitButton buttonType="secondary" [bitAction]="addAccountCredit">
{{ "addCredit" | i18n }}
@ -25,7 +24,6 @@ import { AddAccountCreditDialogComponent } from "./add-account-credit-dialog.com
`,
standalone: true,
imports: [SharedModule],
providers: [SubscriberBillingClient, CurrencyPipe],
})
export class DisplayAccountCreditComponent {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
@ -37,7 +35,6 @@ export class DisplayAccountCreditComponent {
constructor(
private billingClient: SubscriberBillingClient,
private currencyPipe: CurrencyPipe,
private dialogService: DialogService,
private i18nService: I18nService,
private toastService: ToastService,
@ -61,9 +58,4 @@ export class DisplayAccountCreditComponent {
},
});
};
get formattedCredit(): string | null {
const credit = this.credit ?? 0;
return this.currencyPipe.transform(credit, "$");
}
}

View File

@ -118,7 +118,6 @@ import { EnterPaymentMethodComponent } from "./enter-payment-method.component";
`,
standalone: true,
imports: [SharedModule, EnterPaymentMethodComponent, IconComponent],
providers: [SubscriberBillingClient],
})
export class DisplayPaymentMethodInlineComponent {
readonly subscriber = input.required<BitwardenSubscriber>();

View File

@ -79,7 +79,6 @@ type DialogResult =
`,
standalone: true,
imports: [EnterBillingAddressComponent, SharedModule],
providers: [SubscriberBillingClient],
})
export class EditBillingAddressDialogComponent {
protected formGroup = EnterBillingAddressComponent.getFormGroup();

View File

@ -55,7 +55,6 @@ type DialogParams = {
`,
standalone: true,
imports: [EnterPaymentMethodComponent, SharedModule],
providers: [SubscriberBillingClient],
})
export class RequirePaymentMethodDialogComponent extends SubmitPaymentMethodDialogComponent {
protected override subscriber: BitwardenSubscriber;

View File

@ -34,7 +34,6 @@ import { MaskedPaymentMethod } from "../types";
`,
standalone: true,
imports: [SharedModule],
providers: [SubscriberBillingClient],
})
export class VerifyBankAccountComponent {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals

View File

@ -76,7 +76,6 @@ interface OnSuccessArgs {
selector: "app-trial-payment-dialog",
templateUrl: "./trial-payment-dialog.component.html",
standalone: false,
providers: [SubscriberBillingClient, PreviewInvoiceClient],
})
export class TrialPaymentDialogComponent implements OnInit, OnDestroy {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals

View File

@ -15,7 +15,6 @@ import {
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { ToastService } from "@bitwarden/components";
import { PreviewInvoiceClient } from "@bitwarden/web-vault/app/billing/clients";
import {
BillingAddressControls,
EnterBillingAddressComponent,
@ -41,7 +40,6 @@ export interface OrganizationCreatedEvent {
selector: "app-trial-billing-step",
templateUrl: "./trial-billing-step.component.html",
imports: [EnterPaymentMethodComponent, EnterBillingAddressComponent, SharedModule],
providers: [PreviewInvoiceClient, TrialBillingStepService],
})
export class TrialBillingStepComponent implements OnInit, OnDestroy {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals

View File

@ -57,7 +57,7 @@ export interface Trial {
length: number;
}
@Injectable()
@Injectable({ providedIn: "root" })
export class TrialBillingStepService {
constructor(
private accountService: AccountService,

View File

@ -11,14 +11,12 @@ import type { Organization } from "@bitwarden/common/admin-console/models/domain
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
import { DialogService, IconModule, NavigationModule } from "@bitwarden/components";
import { OrganizationWarningsModule } from "@bitwarden/web-vault/app/billing/organizations/warnings/organization-warnings.module";
// 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: "org-switcher",
templateUrl: "org-switcher.component.html",
imports: [CommonModule, JslibModule, NavigationModule, OrganizationWarningsModule, IconModule],
imports: [CommonModule, JslibModule, NavigationModule, IconModule],
})
export class OrgSwitcherComponent {
protected organizations$: Observable<Organization[]> = this.accountService.activeAccount$.pipe(

View File

@ -16,7 +16,6 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { SyncService } from "@bitwarden/common/platform/sync";
import { SvgModule } from "@bitwarden/components";
import { AccountBillingClient } from "@bitwarden/web-vault/app/billing/clients";
import { PremiumSubscriptionRoutingService } from "@bitwarden/web-vault/app/billing/individual/services/premium-subscription-routing.service";
import { BillingFreeFamiliesNavItemComponent } from "../billing/shared/billing-free-families-nav-item.component";
@ -36,7 +35,6 @@ import { WebLayoutModule } from "./web-layout.module";
SvgModule,
BillingFreeFamiliesNavItemComponent,
],
providers: [AccountBillingClient, PremiumSubscriptionRoutingService],
})
export class UserLayoutComponent implements OnInit {
protected readonly logo = PasswordManagerLogo;

View File

@ -2,7 +2,6 @@ import { NgModule } from "@angular/core";
import { SearchModule } from "@bitwarden/components";
import { VaultFilterServiceAbstraction, VaultFilterService } from "@bitwarden/vault";
import { OrganizationWarningsModule } from "@bitwarden/web-vault/app/billing/organizations/warnings/organization-warnings.module";
import { VaultFilterSharedModule } from "../../individual-vault/vault-filter/shared/vault-filter-shared.module";
@ -10,7 +9,7 @@ import { OrganizationOptionsComponent } from "./components/organization-options.
import { VaultFilterComponent } from "./components/vault-filter.component";
@NgModule({
imports: [VaultFilterSharedModule, SearchModule, OrganizationWarningsModule],
imports: [VaultFilterSharedModule, SearchModule],
declarations: [VaultFilterComponent, OrganizationOptionsComponent],
exports: [VaultFilterComponent],
providers: [

View File

@ -101,7 +101,6 @@ import {
DefaultVaultItemsTransferService,
VaultItem,
} from "@bitwarden/vault";
import { OrganizationWarningsModule } from "@bitwarden/web-vault/app/billing/organizations/warnings/organization-warnings.module";
import { OrganizationWarningsService } from "@bitwarden/web-vault/app/billing/organizations/warnings/services";
import {
@ -159,7 +158,6 @@ type EmptyStateMap = Record<EmptyStateType, EmptyStateItem>;
VaultFilterModule,
VaultItemsModule,
SharedModule,
OrganizationWarningsModule,
],
providers: [
RoutedVaultFilterService,

View File

@ -21,7 +21,6 @@ import { ProviderBillingHistoryComponent } from "../../billing/providers/billing
import { SetupBusinessUnitComponent } from "../../billing/providers/setup/setup-business-unit.component";
import { ProviderSubscriptionStatusComponent } from "../../billing/providers/subscription/provider-subscription-status.component";
import { ProviderSubscriptionComponent } from "../../billing/providers/subscription/provider-subscription.component";
import { ProviderWarningsModule } from "../../billing/providers/warnings/provider-warnings.module";
import { EventsComponent } from "../../dirt/provider-events/events.component";
import { AddExistingOrganizationDialogComponent } from "./clients/add-existing-organization-dialog.component";
@ -57,7 +56,6 @@ import { VerifyRecoverDeleteProviderComponent } from "./verify-recover-delete-pr
ScrollingModule,
CardComponent,
ScrollLayoutDirective,
ProviderWarningsModule,
EnterPaymentMethodComponent,
EnterBillingAddressComponent,
],

View File

@ -1,10 +0,0 @@
import { NgModule } from "@angular/core";
import { SubscriberBillingClient } from "@bitwarden/web-vault/app/billing/clients";
import { ProviderWarningsService } from "./services";
@NgModule({
providers: [ProviderWarningsService, SubscriberBillingClient],
})
export class ProviderWarningsModule {}

View File

@ -24,7 +24,7 @@ import { TaxIdWarningType } from "@bitwarden/web-vault/app/billing/warnings/type
import { ProviderWarningsResponse } from "../types/provider-warnings";
@Injectable()
@Injectable({ providedIn: "root" })
export class ProviderWarningsService {
private cache$ = new Map<ProviderId, Observable<ProviderWarningsResponse>>();

View File

@ -2,7 +2,6 @@ import { NgModule } from "@angular/core";
import { BannerModule } from "@bitwarden/components";
import { OrganizationFreeTrialWarningComponent } from "@bitwarden/web-vault/app/billing/organizations/warnings/components";
import { OrganizationWarningsModule } from "@bitwarden/web-vault/app/billing/organizations/warnings/organization-warnings.module";
import { OnboardingModule } from "@bitwarden/web-vault/app/shared/components/onboarding/onboarding.module";
import { SecretsManagerSharedModule } from "../shared/sm-shared.module";
@ -18,7 +17,6 @@ import { SectionComponent } from "./section.component";
OnboardingModule,
BannerModule,
OrganizationFreeTrialWarningComponent,
OrganizationWarningsModule,
],
declarations: [OverviewComponent, SectionComponent],
providers: [],