diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 8b8c2656531..73396c39c16 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -8564,5 +8564,8 @@ "example": "Organization name" } } + }, + "purchasedSeatsRemoved": { + "message": "purchased seats removed" } } diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.html b/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.html index 662cd8a69fa..66ac422441a 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.html @@ -58,13 +58,16 @@ 0" + class="tw-text-muted tw-grid tw-grid-flow-col tw-gap-1 tw-grid-cols-1" + [ngClass]="{ + 'tw-grid-rows-1': additionalSeatsPurchased <= 0, + 'tw-grid-rows-2': additionalSeatsPurchased > 0 + }" > {{ unassignedSeats }} {{ "unassignedSeatsDescription" | i18n | lowercase }} - 0" >{{ additionalSeatsPurchased }} {{ "purchaseSeatDescription" | i18n | lowercase }} diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts index 987b7cc6982..c0ee21d2ab3 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/create-client-dialog.component.ts @@ -162,18 +162,16 @@ export class CreateClientDialogComponent implements OnInit { this.dialogRef.close(this.ResultType.Submitted); }; - protected get openSeats(): number { + protected get unassignedSeats(): number { const selectedProviderPlan = this.getSelectedProviderPlan(); if (selectedProviderPlan === null) { return 0; } - return selectedProviderPlan.seatMinimum - selectedProviderPlan.assignedSeats; - } + const openSeats = selectedProviderPlan.seatMinimum - selectedProviderPlan.assignedSeats; - protected get unassignedSeats(): number { - const unassignedSeats = this.openSeats - this.formGroup.value.seats; + const unassignedSeats = openSeats - this.formGroup.value.seats; return unassignedSeats > 0 ? unassignedSeats : 0; } @@ -185,11 +183,16 @@ export class CreateClientDialogComponent implements OnInit { return 0; } - const selectedSeats = this.formGroup.value.seats ?? 0; + if (selectedProviderPlan.purchasedSeats > 0) { + return this.formGroup.value.seats; + } - const purchased = selectedSeats - this.openSeats; + const additionalSeatsPurchased = + this.formGroup.value.seats + + selectedProviderPlan.assignedSeats - + selectedProviderPlan.seatMinimum; - return purchased > 0 ? purchased : 0; + return additionalSeatsPurchased > 0 ? additionalSeatsPurchased : 0; } private getSelectedProviderPlan(): ProviderPlanResponse { diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.html b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.html index 0d2d22eadd9..2c911b2cb15 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.html @@ -16,21 +16,27 @@ formControlName="assignedSeats" [min]="dialogParams.organization.occupiedSeats" /> - 0 || isServiceUserWithPurchasedSeats"> + {{ unassignedSeats }} {{ "unassignedSeatsDescription" | i18n | lowercase }} - {{ additionalSeatsPurchased }} {{ "purchaseSeatDescription" | i18n | lowercase }} + {{ purchasedSeatsRemoved }} {{ "purchasedSeatsRemoved" | i18n | lowercase }} + diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.ts index e97e4ea9596..f92223d1b54 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/manage-client-subscription-dialog.component.ts @@ -36,7 +36,10 @@ export const openManageClientSubscriptionDialog = ( export class ManageClientSubscriptionDialogComponent implements OnInit { protected loading = true; protected providerPlan: ProviderPlanResponse; + protected assignedSeats: number; protected openSeats: number; + protected purchasedSeats: number; + protected seatMinimum: number; protected readonly ResultType = ManageClientSubscriptionDialogResultType; protected formGroup = new FormGroup({ @@ -63,7 +66,10 @@ export class ManageClientSubscriptionDialogComponent implements OnInit { (plan) => plan.planName === this.dialogParams.organization.plan, ); + this.assignedSeats = this.providerPlan.assignedSeats; this.openSeats = this.providerPlan.seatMinimum - this.providerPlan.assignedSeats; + this.purchasedSeats = this.providerPlan.purchasedSeats; + this.seatMinimum = this.providerPlan.seatMinimum; this.formGroup.controls.assignedSeats.addValidators( this.isServiceUserWithPurchasedSeats @@ -165,9 +171,22 @@ export class ManageClientSubscriptionDialogComponent implements OnInit { const seatDifference = this.formGroup.value.assignedSeats - this.dialogParams.organization.seats; - const purchasedSeats = seatDifference - this.openSeats; + if (this.purchasedSeats > 0) { + return seatDifference; + } - return purchasedSeats > 0 ? purchasedSeats : 0; + return seatDifference - this.openSeats; + } + + get purchasedSeatsRemoved(): number { + const seatDifference = + this.dialogParams.organization.seats - this.formGroup.value.assignedSeats; + + if (this.purchasedSeats >= seatDifference) { + return seatDifference; + } + + return this.purchasedSeats; } get isProviderAdmin(): boolean { @@ -177,4 +196,12 @@ export class ManageClientSubscriptionDialogComponent implements OnInit { get isServiceUserWithPurchasedSeats(): boolean { return !this.isProviderAdmin && this.providerPlan && this.providerPlan.purchasedSeats > 0; } + + get purchasingSeats(): boolean { + return this.additionalSeatsPurchased > 0; + } + + get sellingSeats(): boolean { + return this.purchasedSeats > 0 && this.additionalSeatsPurchased < 0; + } }