mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
[PM-14921]Customers managed by a Reseller need to see how many seats are in their subscription, while still obfuscating the cost of subscription. (#12726)
* Add the seats info for reseller managed org * Resolve the remaining seat bug * Resolve pr comments * code refactoring
This commit is contained in:
@@ -294,6 +294,10 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #setupSelfHost>
|
<ng-template #setupSelfHost>
|
||||||
|
<ng-container *ngIf="userOrg.hasReseller && resellerSeatsRemainingMessage">
|
||||||
|
<h2 bitTypography="h2" class="tw-mt-7">{{ "manageSubscription" | i18n }}</h2>
|
||||||
|
<p bitTypography="body1">{{ resellerSeatsRemainingMessage }}</p>
|
||||||
|
</ng-container>
|
||||||
<ng-container *ngIf="showSelfHost">
|
<ng-container *ngIf="showSelfHost">
|
||||||
<h2 bitTypography="h2" class="tw-mt-7">
|
<h2 bitTypography="h2" class="tw-mt-7">
|
||||||
{{ "selfHostingTitleProper" | i18n }}
|
{{ "selfHostingTitleProper" | i18n }}
|
||||||
|
|||||||
@@ -4,13 +4,17 @@ import { Component, OnDestroy, OnInit } from "@angular/core";
|
|||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
import { firstValueFrom, lastValueFrom, Observable, Subject } from "rxjs";
|
import { firstValueFrom, lastValueFrom, Observable, Subject } from "rxjs";
|
||||||
|
|
||||||
|
import { OrganizationUserApiService } from "@bitwarden/admin-console/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import {
|
import {
|
||||||
getOrganizationById,
|
getOrganizationById,
|
||||||
OrganizationService,
|
OrganizationService,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { OrganizationApiKeyType } from "@bitwarden/common/admin-console/enums";
|
import {
|
||||||
|
OrganizationApiKeyType,
|
||||||
|
OrganizationUserStatusType,
|
||||||
|
} from "@bitwarden/common/admin-console/enums";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||||
@@ -61,12 +65,15 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
|||||||
showSubscription = true;
|
showSubscription = true;
|
||||||
showSelfHost = false;
|
showSelfHost = false;
|
||||||
organizationIsManagedByConsolidatedBillingMSP = false;
|
organizationIsManagedByConsolidatedBillingMSP = false;
|
||||||
|
resellerSeatsRemainingMessage: string;
|
||||||
|
|
||||||
protected readonly subscriptionHiddenIcon = SubscriptionHiddenIcon;
|
protected readonly subscriptionHiddenIcon = SubscriptionHiddenIcon;
|
||||||
protected readonly teamsStarter = ProductTierType.TeamsStarter;
|
protected readonly teamsStarter = ProductTierType.TeamsStarter;
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
private seatsRemainingMessage: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
@@ -79,6 +86,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
|||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
private billingApiService: BillingApiServiceAbstraction,
|
private billingApiService: BillingApiServiceAbstraction,
|
||||||
|
private organizationUserApiService: OrganizationUserApiService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -104,6 +112,28 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.userOrg.hasReseller) {
|
||||||
|
const allUsers = await this.organizationUserApiService.getAllUsers(this.userOrg.id);
|
||||||
|
|
||||||
|
const userCount = allUsers.data.filter((user) =>
|
||||||
|
[
|
||||||
|
OrganizationUserStatusType.Invited,
|
||||||
|
OrganizationUserStatusType.Accepted,
|
||||||
|
OrganizationUserStatusType.Confirmed,
|
||||||
|
].includes(user.status),
|
||||||
|
).length;
|
||||||
|
|
||||||
|
const remainingSeats = this.userOrg.seats - userCount;
|
||||||
|
|
||||||
|
const seatsRemaining = this.i18nService.t(
|
||||||
|
"seatsRemaining",
|
||||||
|
remainingSeats.toString(),
|
||||||
|
this.userOrg.seats.toString(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.resellerSeatsRemainingMessage = seatsRemaining;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|||||||
@@ -10333,5 +10333,18 @@
|
|||||||
"example": "Acme c"
|
"example": "Acme c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"seatsRemaining": {
|
||||||
|
"message": "You have $REMAINING$ seats remaining out of $TOTAL$ seats assigned to this organization. Contact your provider to manage your subscription.",
|
||||||
|
"placeholders": {
|
||||||
|
"remaining": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "5"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "10"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user