1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 17:23:37 +00:00

[PM-25463] Work towards complete usage of Payments domain (#16532)

* Use payment domain

* Fixing lint and test issue

* Fix organization plans tax issue

* PM-26297: Use existing billing address for tax calculation if it exists

* PM-26344: Check existing payment method on submit
This commit is contained in:
Alex Morask
2025-10-01 10:26:47 -05:00
committed by GitHub
parent 147b511d64
commit d9d8050998
117 changed files with 1505 additions and 5212 deletions

View File

@@ -39,12 +39,7 @@
*ngIf="canAccessBilling$ | async"
>
<bit-nav-item [text]="'subscription' | i18n" route="billing/subscription"></bit-nav-item>
@if (managePaymentDetailsOutsideCheckout$ | async) {
<bit-nav-item
[text]="'paymentDetails' | i18n"
route="billing/payment-details"
></bit-nav-item>
}
<bit-nav-item [text]="'paymentDetails' | i18n" route="billing/payment-details"></bit-nav-item>
<bit-nav-item [text]="'billingHistory' | i18n" route="billing/history"></bit-nav-item>
</bit-nav-group>
<bit-nav-item

View File

@@ -47,7 +47,6 @@ export class ProvidersLayoutComponent implements OnInit, OnDestroy {
protected canAccessBilling$: Observable<boolean>;
protected clientsTranslationKey$: Observable<string>;
protected managePaymentDetailsOutsideCheckout$: Observable<boolean>;
protected providerPortalTakeover$: Observable<boolean>;
protected subscriber$: Observable<NonIndividualSubscriber>;
@@ -100,10 +99,6 @@ export class ProvidersLayoutComponent implements OnInit, OnDestroy {
),
);
this.managePaymentDetailsOutsideCheckout$ = this.configService.getFeatureFlag$(
FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout,
);
this.provider$
.pipe(
switchMap((provider) =>

View File

@@ -7,14 +7,18 @@ import { JslibModule } from "@bitwarden/angular/jslib.module";
import { CardComponent, ScrollLayoutDirective, SearchModule } from "@bitwarden/components";
import { DangerZoneComponent } from "@bitwarden/web-vault/app/auth/settings/account/danger-zone.component";
import { OrganizationPlansComponent } from "@bitwarden/web-vault/app/billing";
import { PaymentComponent } from "@bitwarden/web-vault/app/billing/shared/payment/payment.component";
import { VerifyBankAccountComponent } from "@bitwarden/web-vault/app/billing/shared/verify-bank-account/verify-bank-account.component";
import {
EnterBillingAddressComponent,
EnterPaymentMethodComponent,
} from "@bitwarden/web-vault/app/billing/payment/components";
import { OssModule } from "@bitwarden/web-vault/app/oss.module";
import {
CreateClientDialogComponent,
InvoicesComponent,
ManageClientNameDialogComponent,
ManageClientSubscriptionDialogComponent,
NoInvoicesComponent,
ProviderBillingHistoryComponent,
ProviderSubscriptionComponent,
ProviderSubscriptionStatusComponent,
@@ -52,11 +56,11 @@ import { VerifyRecoverDeleteProviderComponent } from "./verify-recover-delete-pr
ProvidersLayoutComponent,
DangerZoneComponent,
ScrollingModule,
VerifyBankAccountComponent,
CardComponent,
ScrollLayoutDirective,
PaymentComponent,
ProviderWarningsModule,
EnterPaymentMethodComponent,
EnterBillingAddressComponent,
],
declarations: [
AcceptProviderComponent,
@@ -72,8 +76,10 @@ import { VerifyRecoverDeleteProviderComponent } from "./verify-recover-delete-pr
AddEditMemberDialogComponent,
AddExistingOrganizationDialogComponent,
CreateClientDialogComponent,
InvoicesComponent,
ManageClientNameDialogComponent,
ManageClientSubscriptionDialogComponent,
NoInvoicesComponent,
ProviderBillingHistoryComponent,
ProviderSubscriptionComponent,
ProviderSubscriptionStatusComponent,

View File

@@ -29,13 +29,11 @@
</div>
</div>
<h2 class="tw-mt-5">{{ "paymentMethod" | i18n }}</h2>
<app-payment
[showAccountCredit]="false"
[bankAccountWarningOverride]="
'verifyProviderBankAccountWithStatementDescriptorWarning' | i18n
"
/>
<app-manage-tax-information />
<app-enter-payment-method [group]="formGroup.controls.paymentMethod"></app-enter-payment-method>
<app-enter-billing-address
[group]="formGroup.controls.billingAddress"
[scenario]="{ type: 'checkout', supportsTaxId: true }"
></app-enter-billing-address>
<button class="tw-mt-8" bitButton bitFormButton buttonType="primary" type="submit">
{{ "submit" | i18n }}
</button>

View File

@@ -1,25 +1,24 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
import { firstValueFrom, Subject, switchMap } from "rxjs";
import { first, takeUntil } from "rxjs/operators";
import { ManageTaxInformationComponent } from "@bitwarden/angular/billing/components";
import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction";
import { ProviderSetupRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-setup.request";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
import { ProviderKey } from "@bitwarden/common/types/key";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { ToastService } from "@bitwarden/components";
import { KeyService } from "@bitwarden/key-management";
import { PaymentComponent } from "@bitwarden/web-vault/app/billing/shared/payment/payment.component";
import {
EnterBillingAddressComponent,
EnterPaymentMethodComponent,
getBillingAddressFromForm,
} from "@bitwarden/web-vault/app/billing/payment/components";
@Component({
selector: "provider-setup",
@@ -27,16 +26,17 @@ import { PaymentComponent } from "@bitwarden/web-vault/app/billing/shared/paymen
standalone: false,
})
export class SetupComponent implements OnInit, OnDestroy {
@ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
@ViewChild(ManageTaxInformationComponent) taxInformationComponent: ManageTaxInformationComponent;
@ViewChild(EnterPaymentMethodComponent) enterPaymentMethodComponent!: EnterPaymentMethodComponent;
loading = true;
providerId: string;
token: string;
providerId!: string;
token!: string;
protected formGroup = this.formBuilder.group({
name: ["", Validators.required],
billingEmail: ["", [Validators.required, Validators.email]],
paymentMethod: EnterPaymentMethodComponent.getFormGroup(),
billingAddress: EnterBillingAddressComponent.getFormGroup(),
});
private destroy$ = new Subject<void>();
@@ -69,7 +69,7 @@ export class SetupComponent implements OnInit, OnDestroy {
if (error) {
this.toastService.showToast({
variant: "error",
title: null,
title: "",
message: this.i18nService.t("emergencyInviteAcceptFailed"),
timeout: 10000,
});
@@ -95,6 +95,7 @@ export class SetupComponent implements OnInit, OnDestroy {
replaceUrl: true,
});
}
this.loading = false;
} catch (error) {
this.validationService.showError(error);
@@ -115,10 +116,7 @@ export class SetupComponent implements OnInit, OnDestroy {
try {
this.formGroup.markAllAsTouched();
const paymentValid = this.paymentComponent.validate();
const taxInformationValid = this.taxInformationComponent.validate();
if (!paymentValid || !taxInformationValid || !this.formGroup.valid) {
if (this.formGroup.invalid) {
return;
}
const activeUserId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
@@ -126,29 +124,24 @@ export class SetupComponent implements OnInit, OnDestroy {
const key = providerKey[0].encryptedString;
const request = new ProviderSetupRequest();
request.name = this.formGroup.value.name;
request.billingEmail = this.formGroup.value.billingEmail;
request.name = this.formGroup.value.name!;
request.billingEmail = this.formGroup.value.billingEmail!;
request.token = this.token;
request.key = key;
request.key = key!;
request.taxInfo = new ExpandedTaxInfoUpdateRequest();
const taxInformation = this.taxInformationComponent.getTaxInformation();
const paymentMethod = await this.enterPaymentMethodComponent.tokenize();
if (!paymentMethod) {
return;
}
request.taxInfo.country = taxInformation.country;
request.taxInfo.postalCode = taxInformation.postalCode;
request.taxInfo.taxId = taxInformation.taxId;
request.taxInfo.line1 = taxInformation.line1;
request.taxInfo.line2 = taxInformation.line2;
request.taxInfo.city = taxInformation.city;
request.taxInfo.state = taxInformation.state;
request.paymentSource = await this.paymentComponent.tokenize();
request.paymentMethod = paymentMethod;
request.billingAddress = getBillingAddressFromForm(this.formGroup.controls.billingAddress);
const provider = await this.providerApiService.postProviderSetup(this.providerId, request);
this.toastService.showToast({
variant: "success",
title: null,
title: "",
message: this.i18nService.t("providerSetup"),
});
@@ -156,20 +149,10 @@ export class SetupComponent implements OnInit, OnDestroy {
await this.router.navigate(["/providers", provider.id]);
} catch (e) {
if (
this.paymentComponent.selected === PaymentMethodType.PayPal &&
typeof e === "string" &&
e === "No payment method is available."
) {
this.toastService.showToast({
variant: "error",
title: null,
message: this.i18nService.t("clickPayWithPayPal"),
});
} else {
if (e !== null && typeof e === "object" && "message" in e && typeof e.message === "string") {
e.message = this.i18nService.translate(e.message) || e.message;
this.validationService.showError(e);
}
this.validationService.showError(e);
}
};
}

View File

@@ -0,0 +1,60 @@
<ng-container *ngIf="loading">
<i
class="bwi bwi-spinner bwi-spin tw-text-muted"
title="{{ 'loading' | i18n }}"
aria-hidden="true"
></i>
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
</ng-container>
<bit-table *ngIf="!loading">
<ng-container header>
<tr>
<th bitCell>{{ "date" | i18n }}</th>
<th bitCell>{{ "invoice" | i18n }}</th>
<th bitCell>{{ "total" | i18n }}</th>
<th bitCell>{{ "status" | i18n }}</th>
<th bitCell>{{ "clientDetails" | i18n }}</th>
</tr>
</ng-container>
<ng-template body>
<tr bitRow *ngFor="let invoice of invoices">
<td bitCell>{{ invoice.date | date: "mediumDate" }}</td>
<td bitCell>
<a
href="{{ invoice.url }}"
target="_blank"
rel="noreferrer"
title="{{ 'viewInvoice' | i18n }}"
>
{{ invoice.number }}
</a>
</td>
<td bitCell>{{ invoice.total | currency: "$" }}</td>
<td bitCell *ngIf="expandInvoiceStatus(invoice) as expandedInvoiceStatus">
<span *ngIf="expandedInvoiceStatus === 'open'">
{{ "open" | i18n | titlecase }}
</span>
<span *ngIf="expandedInvoiceStatus === 'unpaid'">
<i class="bwi bwi-error tw-text-muted" aria-hidden="true"></i>
{{ "unpaid" | i18n | titlecase }}
</span>
<span *ngIf="expandedInvoiceStatus === 'paid'">
<i class="bwi bwi-check tw-text-success" aria-hidden="true"></i>
{{ "paid" | i18n | titlecase }}
</span>
<span *ngIf="expandedInvoiceStatus === 'uncollectible'">
<i class="bwi bwi-error tw-text-muted" aria-hidden="true"></i>
{{ "uncollectible" | i18n | titlecase }}
</span>
</td>
<td bitCell>
<button type="button" bitLink (click)="runExport(invoice.id)">
<span class="tw-font-normal">{{ "downloadCSV" | i18n }}</span>
</button>
</td>
</tr>
</ng-template>
</bit-table>
<div *ngIf="!invoices || invoices.length === 0" class="tw-mt-10">
<app-no-invoices></app-no-invoices>
</div>

View File

@@ -0,0 +1,67 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Component, Input, OnInit } from "@angular/core";
import {
InvoiceResponse,
InvoicesResponse,
} from "@bitwarden/common/billing/models/response/invoices.response";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
@Component({
selector: "app-invoices",
templateUrl: "./invoices.component.html",
standalone: false,
})
export class InvoicesComponent implements OnInit {
@Input() startWith?: InvoicesResponse;
@Input() getInvoices?: () => Promise<InvoicesResponse>;
@Input() getClientInvoiceReport?: (invoiceId: string) => Promise<string>;
@Input() getClientInvoiceReportName?: (invoiceResponse: InvoiceResponse) => string;
protected invoices: InvoiceResponse[] = [];
protected loading = true;
constructor(private fileDownloadService: FileDownloadService) {}
runExport = async (invoiceId: string): Promise<void> => {
const blobData = await this.getClientInvoiceReport(invoiceId);
let fileName = "report.csv";
if (this.getClientInvoiceReportName) {
const invoice = this.invoices.find((invoice) => invoice.id === invoiceId);
fileName = this.getClientInvoiceReportName(invoice);
}
this.fileDownloadService.download({
fileName,
blobData,
blobOptions: {
type: "text/csv",
},
});
};
async ngOnInit(): Promise<void> {
if (this.startWith) {
this.invoices = this.startWith.invoices;
} else if (this.getInvoices) {
const response = await this.getInvoices();
this.invoices = response.invoices;
}
this.loading = false;
}
expandInvoiceStatus = (
invoice: InvoiceResponse,
): "open" | "unpaid" | "paid" | "uncollectible" => {
switch (invoice.status) {
case "open": {
const dueDate = new Date(invoice.dueDate);
return dueDate < new Date() ? "unpaid" : invoice.status;
}
case "paid":
case "uncollectible": {
return invoice.status;
}
}
};
}

View File

@@ -0,0 +1,14 @@
import { Component } from "@angular/core";
import { CreditCardIcon } from "@bitwarden/assets/svg";
@Component({
selector: "app-no-invoices",
template: `<bit-no-items [icon]="icon">
<div slot="title">{{ "noInvoicesToList" | i18n }}</div>
</bit-no-items>`,
standalone: false,
})
export class NoInvoicesComponent {
icon = CreditCardIcon;
}

View File

@@ -1,3 +1,5 @@
export * from "./billing-history/invoices.component";
export * from "./billing-history/no-invoices.component";
export * from "./billing-history/provider-billing-history.component";
export * from "./clients";
export * from "./guards/has-consolidated-billing.guard";

View File

@@ -1,13 +1,10 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { ActivatedRoute } from "@angular/router";
import {
BehaviorSubject,
combineLatest,
EMPTY,
filter,
firstValueFrom,
from,
map,
merge,
Observable,
of,
@@ -19,7 +16,6 @@ import {
tap,
withLatestFrom,
} from "rxjs";
import { catchError } from "rxjs/operators";
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
@@ -49,13 +45,6 @@ import { SharedModule } from "@bitwarden/web-vault/app/shared";
import { ProviderWarningsService } from "../warnings/services";
class RedirectError {
constructor(
public path: string[],
public relativeTo: ActivatedRoute,
) {}
}
type View = {
activeUserId: UserId;
provider: BitwardenSubscriber;
@@ -92,18 +81,6 @@ export class ProviderPaymentDetailsComponent implements OnInit, OnDestroy {
);
private load$: Observable<View> = this.provider$.pipe(
switchMap((provider) =>
this.configService
.getFeatureFlag$(FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout)
.pipe(
map((managePaymentDetailsOutsideCheckout) => {
if (!managePaymentDetailsOutsideCheckout) {
throw new RedirectError(["../subscription"], this.activatedRoute);
}
return provider;
}),
),
),
mapProviderToSubscriber,
switchMap(async (provider) => {
const getTaxIdWarning = firstValueFrom(
@@ -131,14 +108,6 @@ export class ProviderPaymentDetailsComponent implements OnInit, OnDestroy {
};
}),
shareReplay({ bufferSize: 1, refCount: false }),
catchError((error: unknown) => {
if (error instanceof RedirectError) {
return from(this.router.navigate(error.path, { relativeTo: error.relativeTo })).pipe(
switchMap(() => EMPTY),
);
}
throw error;
}),
);
view$: Observable<View> = merge(
@@ -158,7 +127,6 @@ export class ProviderPaymentDetailsComponent implements OnInit, OnDestroy {
private messageListener: MessageListener,
private providerService: ProviderService,
private providerWarningsService: ProviderWarningsService,
private router: Router,
private subscriberBillingClient: SubscriberBillingClient,
) {}

View File

@@ -62,51 +62,5 @@
</bit-table>
</div>
</ng-container>
@if (!managePaymentDetailsOutsideCheckout) {
<!-- Account Credit -->
<bit-section>
<h2 bitTypography="h2">
{{ "accountCredit" | i18n }}
</h2>
<p class="tw-text-lg tw-font-bold">{{ subscription.accountCredit | currency: "$" }}</p>
<p bitTypography="body1">{{ "creditAppliedDesc" | i18n }}</p>
</bit-section>
<!-- Payment Method -->
<bit-section>
<h2 bitTypography="h2">{{ "paymentMethod" | i18n }}</h2>
<p *ngIf="!subscription.paymentSource" bitTypography="body1">
{{ "noPaymentMethod" | i18n }}
</p>
<ng-container *ngIf="subscription.paymentSource">
<app-verify-bank-account
*ngIf="subscription.paymentSource.needsVerification"
[onSubmit]="verifyBankAccount"
(submitted)="load()"
>
</app-verify-bank-account>
<p>
<i class="bwi bwi-fw" [ngClass]="paymentSourceClasses"></i>
{{ subscription.paymentSource.description }}
<span *ngIf="subscription.paymentSource.needsVerification"
>- {{ "unverified" | i18n }}</span
>
</p>
</ng-container>
<button type="button" bitButton buttonType="secondary" [bitAction]="updatePaymentMethod">
{{ updatePaymentSourceButtonText }}
</button>
</bit-section>
<!-- Tax Information -->
<bit-section>
<h2 bitTypography="h2" class="tw-mt-16">{{ "taxInformation" | i18n }}</h2>
<p>{{ "taxInformationDesc" | i18n }}</p>
<app-manage-tax-information
*ngIf="subscription.taxInformation"
[startWith]="TaxInformation.from(subscription.taxInformation)"
[onSubmit]="updateTaxInformation"
(taxInformationUpdated)="load()"
/>
</bit-section>
}
</ng-container>
</bit-container>

View File

@@ -2,26 +2,14 @@
// @ts-strict-ignore
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { concatMap, lastValueFrom, Subject, takeUntil } from "rxjs";
import { concatMap, Subject, takeUntil } from "rxjs";
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
import { TaxInformation } from "@bitwarden/common/billing/models/domain";
import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request";
import { VerifyBankAccountRequest } from "@bitwarden/common/billing/models/request/verify-bank-account.request";
import {
ProviderPlanResponse,
ProviderSubscriptionResponse,
} from "@bitwarden/common/billing/models/response/provider-subscription-response";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { DialogService, ToastService } from "@bitwarden/components";
import { BillingNotificationService } from "@bitwarden/web-vault/app/billing/services/billing-notification.service";
import {
AdjustPaymentDialogComponent,
AdjustPaymentDialogResultType,
} from "@bitwarden/web-vault/app/billing/shared/adjust-payment-dialog/adjust-payment-dialog.component";
@Component({
selector: "app-provider-subscription",
@@ -36,18 +24,11 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
protected loading: boolean;
private destroy$ = new Subject<void>();
protected totalCost: number;
protected managePaymentDetailsOutsideCheckout: boolean;
protected readonly TaxInformation = TaxInformation;
constructor(
private billingApiService: BillingApiServiceAbstraction,
private i18nService: I18nService,
private route: ActivatedRoute,
private billingNotificationService: BillingNotificationService,
private dialogService: DialogService,
private toastService: ToastService,
private configService: ConfigService,
) {}
async ngOnInit() {
@@ -55,9 +36,6 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
.pipe(
concatMap(async (params) => {
this.providerId = params.providerId;
this.managePaymentDetailsOutsideCheckout = await this.configService.getFeatureFlag(
FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout,
);
await this.load();
this.firstLoaded = true;
}),
@@ -83,40 +61,6 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
}
}
protected updatePaymentMethod = async (): Promise<void> => {
const dialogRef = AdjustPaymentDialogComponent.open(this.dialogService, {
data: {
initialPaymentMethod: this.subscription.paymentSource?.type,
providerId: this.providerId,
},
});
const result = await lastValueFrom(dialogRef.closed);
if (result === AdjustPaymentDialogResultType.Submitted) {
await this.load();
}
};
protected updateTaxInformation = async (taxInformation: TaxInformation) => {
try {
const request = ExpandedTaxInfoUpdateRequest.From(taxInformation);
await this.billingApiService.updateProviderTaxInformation(this.providerId, request);
this.billingNotificationService.showSuccess(this.i18nService.t("updatedTaxInformation"));
} catch (error) {
this.billingNotificationService.handleError(error);
}
};
protected verifyBankAccount = async (request: VerifyBankAccountRequest): Promise<void> => {
await this.billingApiService.verifyProviderBankAccount(this.providerId, request);
this.toastService.showToast({
variant: "success",
title: null,
message: this.i18nService.t("verifiedBankAccount"),
});
};
protected getFormattedCost(
cost: number,
seatMinimum: number,
@@ -161,7 +105,7 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
}
protected getBillingCadenceLabel(providerPlanResponse: ProviderPlanResponse): string {
if (providerPlanResponse == null || providerPlanResponse == undefined) {
if (providerPlanResponse == null) {
return "month";
}
@@ -174,27 +118,4 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
return "month";
}
}
protected get paymentSourceClasses() {
if (this.subscription.paymentSource == null) {
return [];
}
switch (this.subscription.paymentSource.type) {
case PaymentMethodType.Card:
return ["bwi-credit-card"];
case PaymentMethodType.BankAccount:
case PaymentMethodType.Check:
return ["bwi-billing"];
case PaymentMethodType.PayPal:
return ["bwi-paypal text-primary"];
default:
return [];
}
}
protected get updatePaymentSourceButtonText(): string {
const key =
this.subscription.paymentSource == null ? "addPaymentMethod" : "changePaymentMethod";
return this.i18nService.t(key);
}
}

View File

@@ -23,8 +23,6 @@ import {
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.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";
@@ -117,7 +115,6 @@ export class OverviewComponent implements OnInit, OnDestroy {
private smOnboardingTasksService: SMOnboardingTasksService,
private logService: LogService,
private router: Router,
private configService: ConfigService,
) {}
ngOnInit() {
@@ -218,13 +215,12 @@ export class OverviewComponent implements OnInit, OnDestroy {
}
async navigateToPaymentMethod() {
const managePaymentDetailsOutsideCheckout = await this.configService.getFeatureFlag(
FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout,
await this.router.navigate(
["organizations", `${this.organizationId}`, "billing", "payment-details"],
{
state: { launchPaymentModalAutomatically: true },
},
);
const route = managePaymentDetailsOutsideCheckout ? "payment-details" : "payment-method";
await this.router.navigate(["organizations", `${this.organizationId}`, "billing", route], {
state: { launchPaymentModalAutomatically: true },
});
}
ngOnDestroy(): void {