diff --git a/apps/browser/src/vault/popup/components/fido2/fido2-use-browser-link.component.ts b/apps/browser/src/vault/popup/components/fido2/fido2-use-browser-link.component.ts index 7af90125db..d062a7b0a0 100644 --- a/apps/browser/src/vault/popup/components/fido2/fido2-use-browser-link.component.ts +++ b/apps/browser/src/vault/popup/components/fido2/fido2-use-browser-link.component.ts @@ -38,7 +38,7 @@ import { ], }) export class Fido2UseBrowserLinkComponent { - showOverlay: boolean = false; + showOverlay = false; isOpen = false; overlayPosition: ConnectedPosition[] = [ { diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html index c34c07150d..44647d0d3b 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html @@ -1,4 +1,5 @@ +
@@ -36,6 +37,5 @@
- diff --git a/apps/web/src/app/billing/shared/adjust-payment.component.ts b/apps/web/src/app/billing/shared/adjust-payment.component.ts index 765a38a350..595566b11d 100644 --- a/apps/web/src/app/billing/shared/adjust-payment.component.ts +++ b/apps/web/src/app/billing/shared/adjust-payment.component.ts @@ -2,6 +2,7 @@ import { Component, EventEmitter, Input, Output, ViewChild } from "@angular/core import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { BillingBannerServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-banner.service.abstraction"; import { PaymentMethodType } from "@bitwarden/common/billing/enums"; import { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -33,6 +34,7 @@ export class AdjustPaymentComponent { private platformUtilsService: PlatformUtilsService, private logService: LogService, private organizationApiService: OrganizationApiServiceAbstraction, + private billingBannerService: BillingBannerServiceAbstraction, ) {} async submit() { @@ -56,6 +58,9 @@ export class AdjustPaymentComponent { } }); await this.formPromise; + if (this.organizationId) { + await this.billingBannerService.setPaymentMethodBannerState(this.organizationId, false); + } this.platformUtilsService.showToast( "success", null, diff --git a/apps/web/src/app/components/payment-method-banners/payment-method-banners.component.html b/apps/web/src/app/components/payment-method-banners/payment-method-banners.component.html new file mode 100644 index 0000000000..1820525ee8 --- /dev/null +++ b/apps/web/src/app/components/payment-method-banners/payment-method-banners.component.html @@ -0,0 +1,15 @@ + + + {{ "maintainYourSubscription" | i18n: banner.organizationName }} + {{ "addAPaymentMethod" | i18n }}. + + diff --git a/apps/web/src/app/components/payment-method-banners/payment-method-banners.component.ts b/apps/web/src/app/components/payment-method-banners/payment-method-banners.component.ts new file mode 100644 index 0000000000..69f3d6c2e7 --- /dev/null +++ b/apps/web/src/app/components/payment-method-banners/payment-method-banners.component.ts @@ -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 = 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 { + await this.billingBannerService.setPaymentMethodBannerState(organizationId, false); + } +} diff --git a/apps/web/src/app/layouts/user-layout.component.html b/apps/web/src/app/layouts/user-layout.component.html index 28dca81162..af71e4d37a 100644 --- a/apps/web/src/app/layouts/user-layout.component.html +++ b/apps/web/src/app/layouts/user-layout.component.html @@ -1,3 +1,4 @@ + diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts index 262b52d8e4..bb83b0972b 100644 --- a/apps/web/src/app/shared/loose-components.module.ts +++ b/apps/web/src/app/shared/loose-components.module.ts @@ -60,6 +60,7 @@ import { UpdateTempPasswordComponent } from "../auth/update-temp-password.compon import { VerifyEmailTokenComponent } from "../auth/verify-email-token.component"; import { VerifyRecoverDeleteComponent } from "../auth/verify-recover-delete.component"; import { DynamicAvatarComponent } from "../components/dynamic-avatar.component"; +import { PaymentMethodBannersComponent } from "../components/payment-method-banners/payment-method-banners.component"; import { SelectableAvatarComponent } from "../components/selectable-avatar.component"; import { FooterComponent } from "../layouts/footer.component"; import { FrontendLayoutComponent } from "../layouts/frontend-layout.component"; @@ -109,6 +110,7 @@ import { SharedModule } from "./shared.module"; PipesModule, PasswordCalloutComponent, DangerZoneComponent, + PaymentMethodBannersComponent, ], declarations: [ AcceptFamilySponsorshipComponent, diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 11c76c6b24..d11b8482b9 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -7392,12 +7392,6 @@ "skipToContent": { "message": "Skip to content" }, - "customBillingStart": { - "message": "Custom billing is not reflected. Visit the " - }, - "customBillingEnd": { - "message": " page for latest invoicing." - }, "managePermissionRequired": { "message": "At least one member or group must have can manage permission." }, @@ -7453,5 +7447,19 @@ "commonImportFormats": { "message": "Common formats", "description": "Label indicating the most common import formats" + }, + "maintainYourSubscription": { + "message": "To maintain your subscription for $ORG$, ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To maintain your subscription for $ORG$, add a payment method.'", + "placeholders": { + "org": { + "content": "$1", + "example": "Example Inc." + } + } + }, + "addAPaymentMethod": { + "message": "add a payment method", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To maintain your subscription for $ORG$, add a payment method.'" } } diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html index 8204b0b6f4..f629ed13f5 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html @@ -1,4 +1,5 @@ +
diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts index 7995e14825..293e31db20 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts @@ -5,6 +5,7 @@ import { FormsModule } from "@angular/forms"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { SearchModule } from "@bitwarden/components"; import { OrganizationPlansComponent } from "@bitwarden/web-vault/app/billing"; +import { PaymentMethodBannersComponent } from "@bitwarden/web-vault/app/components/payment-method-banners/payment-method-banners.component"; import { OssModule } from "@bitwarden/web-vault/app/oss.module"; import { AddOrganizationComponent } from "./clients/add-organization.component"; @@ -34,6 +35,7 @@ import { SetupComponent } from "./setup/setup.component"; JslibModule, ProvidersRoutingModule, OrganizationPlansComponent, + PaymentMethodBannersComponent, SearchModule, ], declarations: [ diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.html index cd0e792d1d..f48a23d10f 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.html @@ -1,4 +1,5 @@ +