mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
[AC-1758] Show banner when organization requires a payment method (#7088)
* Add billing banner states to account settings * Add billing banner service * Add add-payment-method-banners.component * Use add-payment-method-banners.component in layouts * Clear banner on payment method addition * Ran prettier after CI update * Finalize banners styling/translations * Will's (non-Tailwind) feedback * Review feedback * Review feedback * Review feedback * Replace StateService with StateProvider in BillingBannerService * Remove StateService methods
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
<ng-container *ngFor="let banner of banners$ | async">
|
||||
<bit-banner
|
||||
*ngIf="banner.visible"
|
||||
bannerType="warning"
|
||||
(onClose)="closeBanner(banner.organizationId)"
|
||||
>
|
||||
{{ "maintainYourSubscription" | i18n: banner.organizationName }}
|
||||
<a
|
||||
bitLink
|
||||
linkType="contrast"
|
||||
[routerLink]="['/organizations', banner.organizationId, 'billing', 'payment-method']"
|
||||
>{{ "addAPaymentMethod" | i18n }}</a
|
||||
>.
|
||||
</bit-banner>
|
||||
</ng-container>
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { combineLatest, Observable, switchMap } from "rxjs";
|
||||
|
||||
import { OrganizationApiServiceAbstraction as OrganizationApiService } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import {
|
||||
OrganizationService,
|
||||
canAccessAdmin,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { BillingBannerServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-banner.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { BannerModule } from "@bitwarden/components";
|
||||
|
||||
import { SharedModule } from "../../shared/shared.module";
|
||||
|
||||
type PaymentMethodBannerData = {
|
||||
organizationId: string;
|
||||
organizationName: string;
|
||||
visible: boolean;
|
||||
};
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "app-payment-method-banners",
|
||||
templateUrl: "payment-method-banners.component.html",
|
||||
imports: [BannerModule, SharedModule],
|
||||
})
|
||||
export class PaymentMethodBannersComponent {
|
||||
constructor(
|
||||
private billingBannerService: BillingBannerServiceAbstraction,
|
||||
private i18nService: I18nService,
|
||||
private organizationService: OrganizationService,
|
||||
private organizationApiService: OrganizationApiService,
|
||||
) {}
|
||||
|
||||
private organizations$ = this.organizationService.memberOrganizations$.pipe(
|
||||
canAccessAdmin(this.i18nService),
|
||||
);
|
||||
|
||||
protected banners$: Observable<PaymentMethodBannerData[]> = combineLatest([
|
||||
this.organizations$,
|
||||
this.billingBannerService.paymentMethodBannerStates$,
|
||||
]).pipe(
|
||||
switchMap(async ([organizations, paymentMethodBannerStates]) => {
|
||||
return await Promise.all(
|
||||
organizations.map(async (organization) => {
|
||||
const matchingBanner = paymentMethodBannerStates.find(
|
||||
(banner) => banner.organizationId === organization.id,
|
||||
);
|
||||
if (matchingBanner !== null && matchingBanner !== undefined) {
|
||||
return {
|
||||
organizationId: organization.id,
|
||||
organizationName: organization.name,
|
||||
visible: matchingBanner.visible,
|
||||
};
|
||||
}
|
||||
const response = await this.organizationApiService.risksSubscriptionFailure(
|
||||
organization.id,
|
||||
);
|
||||
await this.billingBannerService.setPaymentMethodBannerState(
|
||||
organization.id,
|
||||
response.risksSubscriptionFailure,
|
||||
);
|
||||
return {
|
||||
organizationId: organization.id,
|
||||
organizationName: organization.name,
|
||||
visible: response.risksSubscriptionFailure,
|
||||
};
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
protected async closeBanner(organizationId: string): Promise<void> {
|
||||
await this.billingBannerService.setPaymentMethodBannerState(organizationId, false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user