mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-21 11:35:34 +01:00
Refactor StaticStore Plans and consuming logic (#6136)
* staticstore factoring changes * Refactoring code changes * fix the free org issue * remove a depreciated endpoint * Resolve the issue of secrets manager sub * Fix the ui product sorting
This commit is contained in:
parent
d4e6793871
commit
5cacd79d8c
@ -14,20 +14,48 @@
|
||||
formControlName="plan"
|
||||
/>
|
||||
<ng-container *ngIf="selectablePlan.isAnnual">
|
||||
{{ "annual" | i18n }} -
|
||||
{{
|
||||
(selectablePlan.basePrice === 0 ? selectablePlan.seatPrice : selectablePlan.basePrice)
|
||||
| currency : "$"
|
||||
}}
|
||||
/{{ "yr" | i18n }}
|
||||
<ng-container *ngIf="selectablePlan.PasswordManager">
|
||||
{{ "annual" | i18n }} -
|
||||
{{
|
||||
(selectablePlan.PasswordManager.basePrice === 0
|
||||
? selectablePlan.PasswordManager.seatPrice
|
||||
: selectablePlan.PasswordManager.basePrice
|
||||
) | currency : "$"
|
||||
}}
|
||||
/{{ "yr" | i18n }}
|
||||
</ng-container>
|
||||
<ng-container *ngIf="selectablePlan.SecretsManager">
|
||||
{{ "annual" | i18n }} -
|
||||
{{
|
||||
(selectablePlan.SecretsManager.basePrice === 0
|
||||
? selectablePlan.SecretsManager.seatPrice
|
||||
: selectablePlan.SecretsManager.basePrice
|
||||
) | currency : "$"
|
||||
}}
|
||||
/{{ "yr" | i18n }}
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!selectablePlan.isAnnual">
|
||||
{{ "monthly" | i18n }} -
|
||||
{{
|
||||
(selectablePlan.basePrice === 0 ? selectablePlan.seatPrice : selectablePlan.basePrice)
|
||||
| currency : "$"
|
||||
}}
|
||||
/{{ "monthAbbr" | i18n }}
|
||||
<ng-container *ngIf="selectablePlan.PasswordManager">
|
||||
{{ "monthly" | i18n }} -
|
||||
{{
|
||||
(selectablePlan.PasswordManager.basePrice === 0
|
||||
? selectablePlan.PasswordManager.seatPrice
|
||||
: selectablePlan.PasswordManager.basePrice
|
||||
) | currency : "$"
|
||||
}}
|
||||
/{{ "monthAbbr" | i18n }}
|
||||
</ng-container>
|
||||
<ng-container *ngIf="selectablePlan.SecretsManager">
|
||||
{{ "monthly" | i18n }} -
|
||||
{{
|
||||
(selectablePlan.SecretsManager.basePrice === 0
|
||||
? selectablePlan.SecretsManager.seatPrice
|
||||
: selectablePlan.SecretsManager.basePrice
|
||||
) | currency : "$"
|
||||
}}
|
||||
/{{ "monthAbbr" | i18n }}
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -68,23 +68,38 @@
|
||||
</ng-container>
|
||||
<ng-template #fullFeatureList>
|
||||
<small *ngIf="selectableProduct.product == productTypes.Free"
|
||||
>• {{ "limitedUsers" | i18n : selectableProduct.maxUsers }}</small
|
||||
>• {{ "limitedUsers" | i18n : selectableProduct.PasswordManager.maxSeats }}</small
|
||||
>
|
||||
<small *ngIf="selectableProduct.product != productTypes.Free && selectableProduct.maxUsers"
|
||||
>• {{ "addShareLimitedUsers" | i18n : selectableProduct.maxUsers }}</small
|
||||
<small
|
||||
*ngIf="
|
||||
selectableProduct.product != productTypes.Free &&
|
||||
selectableProduct.PasswordManager.maxSeats
|
||||
"
|
||||
>• {{ "addShareLimitedUsers" | i18n : selectableProduct.PasswordManager.maxSeats }}</small
|
||||
>
|
||||
<small *ngIf="!selectableProduct.maxUsers">• {{ "addShareUnlimitedUsers" | i18n }}</small>
|
||||
<small *ngIf="selectableProduct.maxCollections"
|
||||
>• {{ "limitedCollections" | i18n : selectableProduct.maxCollections }}</small
|
||||
<small *ngIf="!selectableProduct.PasswordManager.maxSeats"
|
||||
>• {{ "addShareUnlimitedUsers" | i18n }}</small
|
||||
>
|
||||
<small *ngIf="selectableProduct.maxAdditionalSeats"
|
||||
>• {{ "addShareLimitedUsers" | i18n : selectableProduct.maxAdditionalSeats }}</small
|
||||
<small *ngIf="selectableProduct.PasswordManager.maxCollections"
|
||||
>•
|
||||
{{
|
||||
"limitedCollections" | i18n : selectableProduct.PasswordManager.maxCollections
|
||||
}}</small
|
||||
>
|
||||
<small *ngIf="!selectableProduct.maxCollections"
|
||||
<small *ngIf="selectableProduct.PasswordManager.maxAdditionalSeats"
|
||||
>•
|
||||
{{
|
||||
"addShareLimitedUsers" | i18n : selectableProduct.PasswordManager.maxAdditionalSeats
|
||||
}}</small
|
||||
>
|
||||
<small *ngIf="!selectableProduct.PasswordManager.maxCollections"
|
||||
>• {{ "createUnlimitedCollections" | i18n }}</small
|
||||
>
|
||||
<small *ngIf="selectableProduct.baseStorageGb"
|
||||
>• {{ "gbEncryptedFileStorage" | i18n : selectableProduct.baseStorageGb + "GB" }}</small
|
||||
<small *ngIf="selectableProduct.PasswordManager.baseStorageGb"
|
||||
>•
|
||||
{{
|
||||
"gbEncryptedFileStorage" | i18n : selectableProduct.PasswordManager.baseStorageGb + "GB"
|
||||
}}</small
|
||||
>
|
||||
<small *ngIf="selectableProduct.hasGroups">• {{ "controlAccessWithGroups" | i18n }}</small>
|
||||
<small *ngIf="selectableProduct.hasApi">• {{ "trackAuditLogs" | i18n }}</small>
|
||||
@ -102,25 +117,40 @@
|
||||
</small>
|
||||
</ng-template>
|
||||
<span *ngIf="selectableProduct.product != productTypes.Free">
|
||||
<ng-container *ngIf="selectableProduct.basePrice && !acceptingSponsorship">
|
||||
{{ selectableProduct.basePrice / 12 | currency : "$" }} /{{ "month" | i18n }},
|
||||
{{ "includesXUsers" | i18n : selectableProduct.baseSeats }}
|
||||
<ng-container *ngIf="selectableProduct.hasAdditionalSeatsOption">
|
||||
<ng-container *ngIf="selectableProduct.PasswordManager.basePrice && !acceptingSponsorship">
|
||||
{{ selectableProduct.PasswordManager.basePrice / 12 | currency : "$" }} /{{
|
||||
"month" | i18n
|
||||
}},
|
||||
{{ "includesXUsers" | i18n : selectableProduct.PasswordManager.baseSeats }}
|
||||
<ng-container *ngIf="selectableProduct.PasswordManager.hasAdditionalSeatsOption">
|
||||
{{ ("additionalUsers" | i18n).toLowerCase() }}
|
||||
{{ selectableProduct.seatPrice / 12 | currency : "$" }} /{{ "month" | i18n }}
|
||||
{{ selectableProduct.PasswordManager.seatPrice / 12 | currency : "$" }} /{{
|
||||
"month" | i18n
|
||||
}}
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</span>
|
||||
<span *ngIf="!selectableProduct.basePrice && selectableProduct.hasAdditionalSeatsOption">
|
||||
{{ "costPerUser" | i18n : (selectableProduct.seatPrice / 12 | currency : "$") }} /{{
|
||||
"month" | i18n
|
||||
<span
|
||||
*ngIf="
|
||||
!selectableProduct.PasswordManager.basePrice &&
|
||||
selectableProduct.PasswordManager.hasAdditionalSeatsOption
|
||||
"
|
||||
>
|
||||
{{
|
||||
"costPerUser" | i18n : (selectableProduct.PasswordManager.seatPrice / 12 | currency : "$")
|
||||
}}
|
||||
/{{ "month" | i18n }}
|
||||
</span>
|
||||
<span *ngIf="selectableProduct.product == productTypes.Free">{{ "freeForever" | i18n }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div *ngIf="formGroup.value.product !== productTypes.Free">
|
||||
<ng-container *ngIf="selectedPlan.hasAdditionalSeatsOption && !selectedPlan.baseSeats">
|
||||
<ng-container
|
||||
*ngIf="
|
||||
selectedPlan.PasswordManager.hasAdditionalSeatsOption &&
|
||||
!selectedPlan.PasswordManager.baseSeats
|
||||
"
|
||||
>
|
||||
<h2 class="mt-5">{{ "users" | i18n }}</h2>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
@ -139,7 +169,13 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
<h2 class="mt-5">{{ "addons" | i18n }}</h2>
|
||||
<div class="row" *ngIf="selectedPlan.hasAdditionalSeatsOption && selectedPlan.baseSeats">
|
||||
<div
|
||||
class="row"
|
||||
*ngIf="
|
||||
selectedPlan.PasswordManager.hasAdditionalSeatsOption &&
|
||||
selectedPlan.PasswordManager.baseSeats
|
||||
"
|
||||
>
|
||||
<div class="form-group col-6">
|
||||
<label for="additionalSeats">{{ "additionalUserSeats" | i18n }}</label>
|
||||
<input
|
||||
@ -152,7 +188,9 @@
|
||||
/>
|
||||
<small class="text-muted form-text">{{
|
||||
"userSeatsAdditionalDesc"
|
||||
| i18n : selectedPlan.baseSeats : (seatPriceMonthly(selectedPlan) | currency : "$")
|
||||
| i18n
|
||||
: selectedPlan.PasswordManager.baseSeats
|
||||
: (seatPriceMonthly(selectedPlan) | currency : "$")
|
||||
}}</small>
|
||||
</div>
|
||||
</div>
|
||||
@ -178,7 +216,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-6" *ngIf="selectedPlan.hasPremiumAccessOption">
|
||||
<div class="form-group col-6" *ngIf="selectedPlan.PasswordManager.hasPremiumAccessOption">
|
||||
<div class="form-check">
|
||||
<input
|
||||
id="premiumAccess"
|
||||
@ -209,62 +247,72 @@
|
||||
<label class="form-check-label" for="interval{{ selectablePlan.type }}">
|
||||
<ng-container *ngIf="selectablePlan.isAnnual">
|
||||
{{ "annually" | i18n }}
|
||||
<small *ngIf="selectablePlan.basePrice">
|
||||
{{ "basePrice" | i18n }}: {{ selectablePlan.basePrice / 12 | currency : "$" }} ×
|
||||
12
|
||||
<small *ngIf="selectablePlan.PasswordManager.basePrice">
|
||||
{{ "basePrice" | i18n }}:
|
||||
{{ selectablePlan.PasswordManager.basePrice / 12 | currency : "$" }} × 12
|
||||
{{ "monthAbbr" | i18n }}
|
||||
=
|
||||
<ng-container *ngIf="acceptingSponsorship; else notAcceptingSponsorship">
|
||||
<span style="text-decoration: line-through">{{
|
||||
selectablePlan.basePrice | currency : "$"
|
||||
selectablePlan.PasswordManager.basePrice | currency : "$"
|
||||
}}</span>
|
||||
{{ "freeWithSponsorship" | i18n }}
|
||||
</ng-container>
|
||||
<ng-template #notAcceptingSponsorship>
|
||||
{{ selectablePlan.basePrice | currency : "$" }}
|
||||
{{ selectablePlan.PasswordManager.basePrice | currency : "$" }}
|
||||
/{{ "year" | i18n }}
|
||||
</ng-template>
|
||||
</small>
|
||||
<small *ngIf="selectablePlan.hasAdditionalSeatsOption">
|
||||
<span *ngIf="selectablePlan.baseSeats">{{ "additionalUsers" | i18n }}:</span>
|
||||
<span *ngIf="!selectablePlan.baseSeats">{{ "users" | i18n }}:</span>
|
||||
<small *ngIf="selectablePlan.PasswordManager.hasAdditionalSeatsOption">
|
||||
<span *ngIf="selectablePlan.PasswordManager.baseSeats"
|
||||
>{{ "additionalUsers" | i18n }}:</span
|
||||
>
|
||||
<span *ngIf="!selectablePlan.PasswordManager.baseSeats">{{ "users" | i18n }}:</span>
|
||||
{{ formGroup.controls["additionalSeats"].value || 0 }} ×
|
||||
{{ selectablePlan.seatPrice / 12 | currency : "$" }} × 12
|
||||
{{ selectablePlan.PasswordManager.seatPrice / 12 | currency : "$" }} × 12
|
||||
{{ "monthAbbr" | i18n }} =
|
||||
{{ seatTotal(selectablePlan, formGroup.value.additionalSeats) | currency : "$" }} /{{
|
||||
"year" | i18n
|
||||
{{
|
||||
passwordManagerSeatTotal(selectablePlan, formGroup.value.additionalSeats)
|
||||
| currency : "$"
|
||||
}}
|
||||
/{{ "year" | i18n }}
|
||||
</small>
|
||||
<small *ngIf="selectablePlan.hasAdditionalStorageOption">
|
||||
<small *ngIf="selectablePlan.PasswordManager.hasAdditionalStorageOption">
|
||||
{{ "additionalStorageGb" | i18n }}:
|
||||
{{ formGroup.controls["additionalStorage"].value || 0 }} ×
|
||||
{{ selectablePlan.additionalStoragePricePerGb / 12 | currency : "$" }} × 12
|
||||
{{ "monthAbbr" | i18n }} =
|
||||
{{ selectablePlan.PasswordManager.additionalStoragePricePerGb / 12 | currency : "$" }}
|
||||
× 12 {{ "monthAbbr" | i18n }} =
|
||||
{{ additionalStorageTotal(selectablePlan) | currency : "$" }} /{{ "year" | i18n }}
|
||||
</small>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!selectablePlan.isAnnual">
|
||||
{{ "monthly" | i18n }}
|
||||
<small *ngIf="selectablePlan.basePrice">
|
||||
{{ "basePrice" | i18n }}: {{ selectablePlan.basePrice | currency : "$" }}
|
||||
<small *ngIf="selectablePlan.PasswordManager.basePrice">
|
||||
{{ "basePrice" | i18n }}:
|
||||
{{ selectablePlan.PasswordManager.basePrice | currency : "$" }}
|
||||
{{ "monthAbbr" | i18n }}
|
||||
=
|
||||
{{ selectablePlan.basePrice | currency : "$" }}
|
||||
{{ selectablePlan.PasswordManager.basePrice | currency : "$" }}
|
||||
/{{ "month" | i18n }}
|
||||
</small>
|
||||
<small *ngIf="selectablePlan.hasAdditionalSeatsOption">
|
||||
<span *ngIf="selectablePlan.baseSeats">{{ "additionalUsers" | i18n }}:</span>
|
||||
<span *ngIf="!selectablePlan.baseSeats">{{ "users" | i18n }}:</span>
|
||||
<small *ngIf="selectablePlan.PasswordManager.hasAdditionalSeatsOption">
|
||||
<span *ngIf="selectablePlan.PasswordManager.baseSeats"
|
||||
>{{ "additionalUsers" | i18n }}:</span
|
||||
>
|
||||
<span *ngIf="!selectablePlan.PasswordManager.baseSeats">{{ "users" | i18n }}:</span>
|
||||
{{ formGroup.controls["additionalSeats"].value || 0 }} ×
|
||||
{{ selectablePlan.seatPrice | currency : "$" }} {{ "monthAbbr" | i18n }} =
|
||||
{{ seatTotal(selectablePlan, formGroup.value.additionalSeats) | currency : "$" }} /{{
|
||||
"month" | i18n
|
||||
{{ selectablePlan.PasswordManager.seatPrice | currency : "$" }}
|
||||
{{ "monthAbbr" | i18n }} =
|
||||
{{
|
||||
passwordManagerSeatTotal(selectablePlan, formGroup.value.additionalSeats)
|
||||
| currency : "$"
|
||||
}}
|
||||
/{{ "month" | i18n }}
|
||||
</small>
|
||||
<small *ngIf="selectablePlan.hasAdditionalStorageOption">
|
||||
<small *ngIf="selectablePlan.PasswordManager.hasAdditionalStorageOption">
|
||||
{{ "additionalStorageGb" | i18n }}:
|
||||
{{ formGroup.controls["additionalStorage"].value || 0 }} ×
|
||||
{{ selectablePlan.additionalStoragePricePerGb | currency : "$" }}
|
||||
{{ selectablePlan.PasswordManager.additionalStoragePricePerGb | currency : "$" }}
|
||||
{{ "monthAbbr" | i18n }} =
|
||||
{{ additionalStorageTotal(selectablePlan) | currency : "$" }} /{{ "month" | i18n }}
|
||||
</small>
|
||||
|
@ -20,7 +20,7 @@ import { OrganizationCreateRequest } from "@bitwarden/common/admin-console/model
|
||||
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||
import { OrganizationUpgradeRequest } from "@bitwarden/common/admin-console/models/request/organization-upgrade.request";
|
||||
import { ProviderOrganizationCreateRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-organization-create.request";
|
||||
import { BitwardenProductType, PaymentMethodType, PlanType } from "@bitwarden/common/billing/enums";
|
||||
import { PaymentMethodType, PlanType } from "@bitwarden/common/billing/enums";
|
||||
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
@ -136,12 +136,8 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
async ngOnInit() {
|
||||
if (!this.selfHosted) {
|
||||
const plans = await this.apiService.getPlans();
|
||||
this.passwordManagerPlans = plans.data.filter(
|
||||
(plan) => plan.bitwardenProduct === BitwardenProductType.PasswordManager
|
||||
);
|
||||
this.secretsManagerPlans = plans.data.filter(
|
||||
(plan) => plan.bitwardenProduct === BitwardenProductType.SecretsManager
|
||||
);
|
||||
this.passwordManagerPlans = plans.data.filter((plan) => !!plan.PasswordManager);
|
||||
this.secretsManagerPlans = plans.data.filter((plan) => !!plan.SecretsManager);
|
||||
|
||||
if (this.product === ProductType.Enterprise || this.product === ProductType.Teams) {
|
||||
this.formGroup.controls.businessOwned.setValue(true);
|
||||
@ -221,7 +217,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
const familyPlan = this.passwordManagerPlans.find(
|
||||
(plan) => plan.type === PlanType.FamiliesAnnually
|
||||
);
|
||||
this.discount = familyPlan.basePrice;
|
||||
this.discount = familyPlan.PasswordManager.basePrice;
|
||||
validPlans = [familyPlan];
|
||||
}
|
||||
|
||||
@ -241,67 +237,78 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
|
||||
additionalStoragePriceMonthly(selectedPlan: PlanResponse) {
|
||||
if (!selectedPlan.isAnnual) {
|
||||
return selectedPlan.additionalStoragePricePerGb;
|
||||
return selectedPlan.PasswordManager.additionalStoragePricePerGb;
|
||||
}
|
||||
return selectedPlan.additionalStoragePricePerGb / 12;
|
||||
return selectedPlan.PasswordManager.additionalStoragePricePerGb / 12;
|
||||
}
|
||||
|
||||
seatPriceMonthly(selectedPlan: PlanResponse) {
|
||||
if (!selectedPlan.isAnnual) {
|
||||
return selectedPlan.seatPrice;
|
||||
return selectedPlan.PasswordManager.seatPrice;
|
||||
}
|
||||
return selectedPlan.seatPrice / 12;
|
||||
return selectedPlan.PasswordManager.seatPrice / 12;
|
||||
}
|
||||
|
||||
additionalStorageTotal(plan: PlanResponse): number {
|
||||
if (!plan.hasAdditionalStorageOption) {
|
||||
if (!plan.PasswordManager.hasAdditionalStorageOption) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (
|
||||
plan.additionalStoragePricePerGb *
|
||||
plan.PasswordManager.additionalStoragePricePerGb *
|
||||
Math.abs(this.formGroup.controls.additionalStorage.value || 0)
|
||||
);
|
||||
}
|
||||
|
||||
seatTotal(plan: PlanResponse, seats: number): number {
|
||||
if (!plan.hasAdditionalSeatsOption) {
|
||||
passwordManagerSeatTotal(plan: PlanResponse, seats: number): number {
|
||||
if (!plan.PasswordManager.hasAdditionalSeatsOption) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return plan.seatPrice * Math.abs(seats || 0);
|
||||
return plan.PasswordManager.seatPrice * Math.abs(seats || 0);
|
||||
}
|
||||
|
||||
secretsManagerSeatTotal(plan: PlanResponse, seats: number): number {
|
||||
if (!plan.SecretsManager.hasAdditionalSeatsOption) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return plan.SecretsManager.seatPrice * Math.abs(seats || 0);
|
||||
}
|
||||
|
||||
additionalServiceAccountTotal(plan: PlanResponse): number {
|
||||
if (!plan.hasAdditionalServiceAccountOption) {
|
||||
if (!plan.SecretsManager.hasAdditionalServiceAccountOption) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (
|
||||
plan.additionalPricePerServiceAccount *
|
||||
plan.SecretsManager.additionalPricePerServiceAccount *
|
||||
Math.abs(this.secretsManagerForm.value.additionalServiceAccounts || 0)
|
||||
);
|
||||
}
|
||||
|
||||
get passwordManagerSubtotal() {
|
||||
let subTotal = this.selectedPlan.basePrice;
|
||||
let subTotal = this.selectedPlan.PasswordManager.basePrice;
|
||||
if (
|
||||
this.selectedPlan.hasAdditionalSeatsOption &&
|
||||
this.selectedPlan.PasswordManager.hasAdditionalSeatsOption &&
|
||||
this.formGroup.controls.additionalSeats.value
|
||||
) {
|
||||
subTotal += this.seatTotal(this.selectedPlan, this.formGroup.value.additionalSeats);
|
||||
subTotal += this.passwordManagerSeatTotal(
|
||||
this.selectedPlan,
|
||||
this.formGroup.value.additionalSeats
|
||||
);
|
||||
}
|
||||
if (
|
||||
this.selectedPlan.hasAdditionalStorageOption &&
|
||||
this.selectedPlan.PasswordManager.hasAdditionalStorageOption &&
|
||||
this.formGroup.controls.additionalStorage.value
|
||||
) {
|
||||
subTotal += this.additionalStorageTotal(this.selectedPlan);
|
||||
}
|
||||
if (
|
||||
this.selectedPlan.hasPremiumAccessOption &&
|
||||
this.selectedPlan.PasswordManager.hasPremiumAccessOption &&
|
||||
this.formGroup.controls.premiumAccessAddon.value
|
||||
) {
|
||||
subTotal += this.selectedPlan.premiumAccessOptionPrice;
|
||||
subTotal += this.selectedPlan.PasswordManager.premiumAccessOptionPrice;
|
||||
}
|
||||
return subTotal - this.discount;
|
||||
}
|
||||
@ -315,8 +322,8 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
return (
|
||||
plan.basePrice +
|
||||
this.seatTotal(plan, formValues.userSeats) +
|
||||
plan.SecretsManager.basePrice +
|
||||
this.secretsManagerSeatTotal(plan, formValues.userSeats) +
|
||||
this.additionalServiceAccountTotal(plan)
|
||||
);
|
||||
}
|
||||
@ -356,18 +363,18 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
|
||||
changedProduct() {
|
||||
this.formGroup.controls.plan.setValue(this.selectablePlans[0].type);
|
||||
if (!this.selectedPlan.hasPremiumAccessOption) {
|
||||
if (!this.selectedPlan.PasswordManager.hasPremiumAccessOption) {
|
||||
this.formGroup.controls.premiumAccessAddon.setValue(false);
|
||||
}
|
||||
if (!this.selectedPlan.hasAdditionalStorageOption) {
|
||||
if (!this.selectedPlan.PasswordManager.hasAdditionalStorageOption) {
|
||||
this.formGroup.controls.additionalStorage.setValue(0);
|
||||
}
|
||||
if (!this.selectedPlan.hasAdditionalSeatsOption) {
|
||||
if (!this.selectedPlan.PasswordManager.hasAdditionalSeatsOption) {
|
||||
this.formGroup.controls.additionalSeats.setValue(0);
|
||||
} else if (
|
||||
!this.formGroup.controls.additionalSeats.value &&
|
||||
!this.selectedPlan.baseSeats &&
|
||||
this.selectedPlan.hasAdditionalSeatsOption
|
||||
!this.selectedPlan.PasswordManager.baseSeats &&
|
||||
this.selectedPlan.PasswordManager.hasAdditionalSeatsOption
|
||||
) {
|
||||
this.formGroup.controls.additionalSeats.setValue(1);
|
||||
}
|
||||
@ -478,7 +485,8 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
request.additionalSeats = this.formGroup.controls.additionalSeats.value;
|
||||
request.additionalStorageGb = this.formGroup.controls.additionalStorage.value;
|
||||
request.premiumAccessAddon =
|
||||
this.selectedPlan.hasPremiumAccessOption && this.formGroup.controls.premiumAccessAddon.value;
|
||||
this.selectedPlan.PasswordManager.hasPremiumAccessOption &&
|
||||
this.formGroup.controls.premiumAccessAddon.value;
|
||||
request.planType = this.selectedPlan.type;
|
||||
request.billingAddressCountry = this.taxComponent.taxInfo.country;
|
||||
request.billingAddressPostalCode = this.taxComponent.taxInfo.postalCode;
|
||||
@ -527,7 +535,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
request.additionalSeats = this.formGroup.controls.additionalSeats.value;
|
||||
request.additionalStorageGb = this.formGroup.controls.additionalStorage.value;
|
||||
request.premiumAccessAddon =
|
||||
this.selectedPlan.hasPremiumAccessOption &&
|
||||
this.selectedPlan.PasswordManager.hasPremiumAccessOption &&
|
||||
this.formGroup.controls.premiumAccessAddon.value;
|
||||
request.planType = this.selectedPlan.type;
|
||||
request.billingAddressPostalCode = this.taxComponent.taxInfo.postalCode;
|
||||
@ -588,7 +596,10 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
|
||||
private billingSubLabelText(): string {
|
||||
const selectedPlan = this.selectedPlan;
|
||||
const price = selectedPlan.basePrice === 0 ? selectedPlan.seatPrice : selectedPlan.basePrice;
|
||||
const price =
|
||||
selectedPlan.PasswordManager.basePrice === 0
|
||||
? selectedPlan.PasswordManager.seatPrice
|
||||
: selectedPlan.PasswordManager.basePrice;
|
||||
let text = "";
|
||||
|
||||
if (selectedPlan.isAnnual) {
|
||||
@ -611,11 +622,11 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.selectedSecretsManagerPlan.hasAdditionalSeatsOption) {
|
||||
if (this.selectedSecretsManagerPlan.SecretsManager.hasAdditionalSeatsOption) {
|
||||
request.additionalSmSeats = formValues.userSeats;
|
||||
}
|
||||
|
||||
if (this.selectedSecretsManagerPlan.hasAdditionalServiceAccountOption) {
|
||||
if (this.selectedSecretsManagerPlan.SecretsManager.hasAdditionalServiceAccountOption) {
|
||||
request.additionalServiceAccounts = formValues.additionalServiceAccounts;
|
||||
}
|
||||
}
|
||||
|
@ -71,9 +71,7 @@
|
||||
<ng-container *ngIf="subscription">
|
||||
<tr bitRow *ngFor="let i of lineItems">
|
||||
<td bitCell [ngClass]="{ 'tw-pl-20': i.addonSubscriptionItem }">
|
||||
<span *ngIf="!i.addonSubscriptionItem"
|
||||
>{{ productName(i.bitwardenProduct) }} -</span
|
||||
>
|
||||
<span *ngIf="!i.addonSubscriptionItem">{{ i.productName }} -</span>
|
||||
{{ i.name }} {{ i.quantity > 1 ? "×" + i.quantity : "" }} @
|
||||
{{ i.amount | currency : "$" }}
|
||||
</td>
|
||||
@ -150,7 +148,7 @@
|
||||
<ng-container *ngIf="showSecretsManagerSubscribe">
|
||||
<div class="tw-mt-7">
|
||||
<sm-subscribe-standalone
|
||||
[plan]="sub.secretsManagerPlan"
|
||||
[plan]="sub.plan"
|
||||
[organization]="userOrg"
|
||||
(onSubscribe)="subscriptionAdjusted()"
|
||||
></sm-subscribe-standalone>
|
||||
|
@ -8,7 +8,7 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationApiKeyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { BitwardenProductType, PlanType } from "@bitwarden/common/billing/enums";
|
||||
import { PlanType } from "@bitwarden/common/billing/enums";
|
||||
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
|
||||
import { BillingSubscriptionItemResponse } from "@bitwarden/common/billing/models/response/subscription.response";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@ -74,17 +74,6 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
productName(product: BitwardenProductType) {
|
||||
switch (product) {
|
||||
case BitwardenProductType.PasswordManager:
|
||||
return this.i18nService.t("passwordManager");
|
||||
case BitwardenProductType.SecretsManager:
|
||||
return this.i18nService.t("secretsManager");
|
||||
default:
|
||||
return this.i18nService.t("passwordManager");
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
@ -98,7 +87,20 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
this.userOrg = this.organizationService.get(this.organizationId);
|
||||
if (this.userOrg.canViewSubscription) {
|
||||
this.sub = await this.organizationApiService.getSubscription(this.organizationId);
|
||||
this.lineItems = this.sub?.subscription?.items?.sort(sortSubscriptionItems) ?? [];
|
||||
this.lineItems = this.sub?.subscription?.items;
|
||||
if (this.lineItems && this.lineItems.length) {
|
||||
this.lineItems = this.lineItems
|
||||
.map((item) => {
|
||||
const itemTotalAmount = item.amount * item.quantity;
|
||||
const seatPriceTotal = this.sub.plan?.SecretsManager?.seatPrice * item.quantity;
|
||||
item.productName =
|
||||
itemTotalAmount === seatPriceTotal || item.name.includes("Service Accounts")
|
||||
? "SecretsManager"
|
||||
: "PasswordManager";
|
||||
return item;
|
||||
})
|
||||
.sort(sortSubscriptionItems);
|
||||
}
|
||||
}
|
||||
|
||||
const apiKeyResponse = await this.organizationApiService.getApiKeyInformation(
|
||||
@ -111,6 +113,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
this.showSecretsManagerSubscribe =
|
||||
this.userOrg.canEditSubscription &&
|
||||
!this.userOrg.hasProvider &&
|
||||
this.sub?.plan?.SecretsManager &&
|
||||
!this.userOrg.useSecretsManager &&
|
||||
!this.subscription?.cancelled &&
|
||||
!this.subscriptionMarkedForCancel;
|
||||
@ -119,7 +122,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
this.userOrg.canEditSubscription &&
|
||||
this.userOrg.useSecretsManager &&
|
||||
this.subscription != null &&
|
||||
this.sub.secretsManagerPlan?.hasAdditionalSeatsOption &&
|
||||
this.sub.plan?.SecretsManager?.hasAdditionalSeatsOption &&
|
||||
!this.sub.secretsManagerBeta &&
|
||||
!this.subscription.cancelled &&
|
||||
!this.subscriptionMarkedForCancel;
|
||||
@ -165,11 +168,11 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
}
|
||||
|
||||
get storageGbPrice() {
|
||||
return this.sub.plan.additionalStoragePricePerGb;
|
||||
return this.sub.plan.PasswordManager.additionalStoragePricePerGb;
|
||||
}
|
||||
|
||||
get seatPrice() {
|
||||
return this.sub.plan.seatPrice;
|
||||
return this.sub.plan.PasswordManager.seatPrice;
|
||||
}
|
||||
|
||||
get seats() {
|
||||
@ -180,13 +183,13 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
return {
|
||||
seatCount: this.sub.smSeats,
|
||||
maxAutoscaleSeats: this.sub.maxAutoscaleSmSeats,
|
||||
seatPrice: this.sub.secretsManagerPlan.seatPrice,
|
||||
seatPrice: this.sub.plan.SecretsManager.seatPrice,
|
||||
maxAutoscaleServiceAccounts: this.sub.maxAutoscaleSmServiceAccounts,
|
||||
additionalServiceAccounts:
|
||||
this.sub.smServiceAccounts - this.sub.secretsManagerPlan.baseServiceAccount,
|
||||
interval: this.sub.secretsManagerPlan.isAnnual ? "year" : "month",
|
||||
additionalServiceAccountPrice: this.sub.secretsManagerPlan.additionalPricePerServiceAccount,
|
||||
baseServiceAccountCount: this.sub.secretsManagerPlan.baseServiceAccount,
|
||||
this.sub.smServiceAccounts - this.sub.plan.SecretsManager.baseServiceAccount,
|
||||
interval: this.sub.plan.isAnnual ? "year" : "month",
|
||||
additionalServiceAccountPrice: this.sub.plan.SecretsManager.additionalPricePerServiceAccount,
|
||||
baseServiceAccountCount: this.sub.plan.SecretsManager.baseServiceAccount,
|
||||
};
|
||||
}
|
||||
|
||||
@ -195,7 +198,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
}
|
||||
|
||||
get canAdjustSeats() {
|
||||
return this.sub.plan.hasAdditionalSeatsOption;
|
||||
return this.sub.plan.PasswordManager.hasAdditionalSeatsOption;
|
||||
}
|
||||
|
||||
get isAdmin() {
|
||||
@ -391,7 +394,7 @@ function sortSubscriptionItems(
|
||||
a: BillingSubscriptionItemResponse,
|
||||
b: BillingSubscriptionItemResponse
|
||||
) {
|
||||
if (a.bitwardenProduct == b.bitwardenProduct) {
|
||||
if (a.productName == b.productName) {
|
||||
if (a.addonSubscriptionItem == b.addonSubscriptionItem) {
|
||||
return 0;
|
||||
}
|
||||
@ -401,5 +404,5 @@ function sortSubscriptionItems(
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return a.bitwardenProduct - b.bitwardenProduct;
|
||||
return a.productName.localeCompare(b.productName);
|
||||
}
|
||||
|
@ -33,10 +33,10 @@ export class SecretsManagerSubscribeStandaloneComponent {
|
||||
|
||||
submit = async () => {
|
||||
const request = new SecretsManagerSubscribeRequest();
|
||||
request.additionalSmSeats = this.plan.hasAdditionalSeatsOption
|
||||
request.additionalSmSeats = this.plan.SecretsManager.hasAdditionalSeatsOption
|
||||
? this.formGroup.value.userSeats
|
||||
: 0;
|
||||
request.additionalServiceAccounts = this.plan.hasAdditionalServiceAccountOption
|
||||
request.additionalServiceAccounts = this.plan.SecretsManager.hasAdditionalServiceAccountOption
|
||||
? this.formGroup.value.additionalServiceAccounts
|
||||
: 0;
|
||||
|
||||
|
@ -45,14 +45,14 @@
|
||||
</bit-form-control>
|
||||
|
||||
<ng-container *ngIf="formGroup.value.enabled">
|
||||
<div *ngIf="selectedPlan.hasAdditionalSeatsOption" class="tw-w-1/2">
|
||||
<div *ngIf="selectedPlan.SecretsManager.hasAdditionalSeatsOption" class="tw-w-1/2">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "userSeats" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="userSeats" type="number" />
|
||||
<bit-hint>{{ "userSeatsHowManyDesc" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
</div>
|
||||
<div *ngIf="selectedPlan.hasAdditionalServiceAccountOption" class="tw-w-1/2">
|
||||
<div *ngIf="selectedPlan.SecretsManager.hasAdditionalServiceAccountOption" class="tw-w-1/2">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "additionalServiceAccounts" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="additionalServiceAccounts" type="number" />
|
||||
|
@ -79,26 +79,26 @@ export class SecretsManagerSubscribeComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
get serviceAccountsIncluded() {
|
||||
return this.selectedPlan.baseServiceAccount;
|
||||
return this.selectedPlan.SecretsManager.baseServiceAccount;
|
||||
}
|
||||
|
||||
get monthlyCostPerServiceAccount() {
|
||||
return this.selectedPlan.isAnnual
|
||||
? this.selectedPlan.additionalPricePerServiceAccount / 12
|
||||
: this.selectedPlan.additionalPricePerServiceAccount;
|
||||
? this.selectedPlan.SecretsManager.additionalPricePerServiceAccount / 12
|
||||
: this.selectedPlan.SecretsManager.additionalPricePerServiceAccount;
|
||||
}
|
||||
|
||||
get maxUsers() {
|
||||
return this.selectedPlan.maxUsers;
|
||||
return this.selectedPlan.SecretsManager.maxSeats;
|
||||
}
|
||||
|
||||
get maxProjects() {
|
||||
return this.selectedPlan.maxProjects;
|
||||
return this.selectedPlan.SecretsManager.maxProjects;
|
||||
}
|
||||
|
||||
get monthlyCostPerUser() {
|
||||
return this.selectedPlan.isAnnual
|
||||
? this.selectedPlan.seatPrice / 12
|
||||
: this.selectedPlan.seatPrice;
|
||||
? this.selectedPlan.SecretsManager.seatPrice / 12
|
||||
: this.selectedPlan.SecretsManager.seatPrice;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ export class OrganizationResponse extends BaseResponse {
|
||||
businessTaxNumber: string;
|
||||
billingEmail: string;
|
||||
plan: PlanResponse;
|
||||
secretsManagerPlan: PlanResponse;
|
||||
planType: PlanType;
|
||||
seats: number;
|
||||
maxAutoscaleSeats: number;
|
||||
@ -49,10 +48,6 @@ export class OrganizationResponse extends BaseResponse {
|
||||
const plan = this.getResponseProperty("Plan");
|
||||
this.plan = plan == null ? null : new PlanResponse(plan);
|
||||
|
||||
const secretsManagerPlan = this.getResponseProperty("SecretsManagerPlan");
|
||||
this.secretsManagerPlan =
|
||||
secretsManagerPlan == null ? null : new PlanResponse(secretsManagerPlan);
|
||||
|
||||
this.planType = this.getResponseProperty("PlanType");
|
||||
this.seats = this.getResponseProperty("Seats");
|
||||
this.maxAutoscaleSeats = this.getResponseProperty("MaxAutoscaleSeats");
|
||||
|
@ -1,28 +1,16 @@
|
||||
import { ProductType } from "../../../enums";
|
||||
import { BaseResponse } from "../../../models/response/base.response";
|
||||
import { BitwardenProductType, PlanType } from "../../enums";
|
||||
import { PlanType } from "../../enums";
|
||||
|
||||
export class PlanResponse extends BaseResponse {
|
||||
type: PlanType;
|
||||
product: ProductType;
|
||||
bitwardenProduct: BitwardenProductType;
|
||||
name: string;
|
||||
isAnnual: boolean;
|
||||
nameLocalizationKey: string;
|
||||
descriptionLocalizationKey: string;
|
||||
canBeUsedByBusiness: boolean;
|
||||
baseSeats: number;
|
||||
baseStorageGb: number;
|
||||
maxCollections: number;
|
||||
maxUsers: number;
|
||||
|
||||
hasAdditionalSeatsOption: boolean;
|
||||
maxAdditionalSeats: number;
|
||||
hasAdditionalStorageOption: boolean;
|
||||
maxAdditionalStorage: number;
|
||||
hasPremiumAccessOption: boolean;
|
||||
trialPeriodDays: number;
|
||||
|
||||
hasSelfHost: boolean;
|
||||
hasPolicies: boolean;
|
||||
hasGroups: boolean;
|
||||
@ -34,29 +22,12 @@ export class PlanResponse extends BaseResponse {
|
||||
hasSso: boolean;
|
||||
hasResetPassword: boolean;
|
||||
usersGetPremium: boolean;
|
||||
|
||||
upgradeSortOrder: number;
|
||||
displaySortOrder: number;
|
||||
legacyYear: number;
|
||||
disabled: boolean;
|
||||
|
||||
stripePlanId: string;
|
||||
stripeSeatPlanId: string;
|
||||
stripeStoragePlanId: string;
|
||||
stripePremiumAccessPlanId: string;
|
||||
basePrice: number;
|
||||
seatPrice: number;
|
||||
additionalStoragePricePerGb: number;
|
||||
premiumAccessOptionPrice: number;
|
||||
|
||||
// SM only
|
||||
additionalPricePerServiceAccount: number;
|
||||
baseServiceAccount: number;
|
||||
maxServiceAccount: number;
|
||||
hasAdditionalServiceAccountOption: boolean;
|
||||
maxProjects: number;
|
||||
maxAdditionalServiceAccounts: number;
|
||||
stripeServiceAccountPlanId: string;
|
||||
PasswordManager: PasswordManagerPlanFeaturesResponse;
|
||||
SecretsManager: SecretsManagerPlanFeaturesResponse;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@ -67,15 +38,6 @@ export class PlanResponse extends BaseResponse {
|
||||
this.nameLocalizationKey = this.getResponseProperty("NameLocalizationKey");
|
||||
this.descriptionLocalizationKey = this.getResponseProperty("DescriptionLocalizationKey");
|
||||
this.canBeUsedByBusiness = this.getResponseProperty("CanBeUsedByBusiness");
|
||||
this.baseSeats = this.getResponseProperty("BaseSeats");
|
||||
this.baseStorageGb = this.getResponseProperty("BaseStorageGb");
|
||||
this.maxCollections = this.getResponseProperty("MaxCollections");
|
||||
this.maxUsers = this.getResponseProperty("MaxUsers");
|
||||
this.hasAdditionalSeatsOption = this.getResponseProperty("HasAdditionalSeatsOption");
|
||||
this.maxAdditionalSeats = this.getResponseProperty("MaxAdditionalSeats");
|
||||
this.hasAdditionalStorageOption = this.getResponseProperty("HasAdditionalStorageOption");
|
||||
this.maxAdditionalStorage = this.getResponseProperty("MaxAdditionalStorage");
|
||||
this.hasPremiumAccessOption = this.getResponseProperty("HasPremiumAccessOption");
|
||||
this.trialPeriodDays = this.getResponseProperty("TrialPeriodDays");
|
||||
this.hasSelfHost = this.getResponseProperty("HasSelfHost");
|
||||
this.hasPolicies = this.getResponseProperty("HasPolicies");
|
||||
@ -92,16 +54,46 @@ export class PlanResponse extends BaseResponse {
|
||||
this.displaySortOrder = this.getResponseProperty("SortOrder");
|
||||
this.legacyYear = this.getResponseProperty("LegacyYear");
|
||||
this.disabled = this.getResponseProperty("Disabled");
|
||||
this.stripePlanId = this.getResponseProperty("StripePlanId");
|
||||
const passwordManager = this.getResponseProperty("PasswordManager");
|
||||
const secretsManager = this.getResponseProperty("SecretsManager");
|
||||
this.PasswordManager =
|
||||
passwordManager == null ? null : new PasswordManagerPlanFeaturesResponse(passwordManager);
|
||||
this.SecretsManager =
|
||||
secretsManager == null ? null : new SecretsManagerPlanFeaturesResponse(secretsManager);
|
||||
}
|
||||
}
|
||||
|
||||
export class SecretsManagerPlanFeaturesResponse extends BaseResponse {
|
||||
// Seats
|
||||
stripeSeatPlanId: string;
|
||||
baseSeats: number;
|
||||
basePrice: number;
|
||||
seatPrice: number;
|
||||
hasAdditionalSeatsOption: boolean;
|
||||
maxAdditionalSeats: number;
|
||||
maxSeats: number;
|
||||
|
||||
// Service accounts
|
||||
stripeServiceAccountPlanId: string;
|
||||
additionalPricePerServiceAccount: number;
|
||||
baseServiceAccount: number;
|
||||
maxServiceAccount: number;
|
||||
hasAdditionalServiceAccountOption: boolean;
|
||||
maxAdditionalServiceAccounts: number;
|
||||
|
||||
// Features
|
||||
maxProjects: number;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.stripeSeatPlanId = this.getResponseProperty("StripeSeatPlanId");
|
||||
this.stripeStoragePlanId = this.getResponseProperty("StripeStoragePlanId");
|
||||
this.stripePremiumAccessPlanId = this.getResponseProperty("StripePremiumAccessPlanId");
|
||||
this.baseSeats = this.getResponseProperty("BaseSeats");
|
||||
this.basePrice = this.getResponseProperty("BasePrice");
|
||||
this.seatPrice = this.getResponseProperty("SeatPrice");
|
||||
this.additionalStoragePricePerGb = this.getResponseProperty("AdditionalStoragePricePerGb");
|
||||
this.premiumAccessOptionPrice = this.getResponseProperty("PremiumAccessOptionPrice");
|
||||
|
||||
this.bitwardenProduct = this.getResponseProperty("BitwardenProduct");
|
||||
this.hasAdditionalSeatsOption = this.getResponseProperty("HasAdditionalSeatsOption");
|
||||
this.maxAdditionalSeats = this.getResponseProperty("MaxAdditionalSeats");
|
||||
this.maxSeats = this.getResponseProperty("MaxSeats");
|
||||
this.stripeServiceAccountPlanId = this.getResponseProperty("StripeServiceAccountPlanId");
|
||||
this.additionalPricePerServiceAccount = this.getResponseProperty(
|
||||
"AdditionalPricePerServiceAccount"
|
||||
);
|
||||
@ -110,8 +102,53 @@ export class PlanResponse extends BaseResponse {
|
||||
this.hasAdditionalServiceAccountOption = this.getResponseProperty(
|
||||
"HasAdditionalServiceAccountOption"
|
||||
);
|
||||
this.maxProjects = this.getResponseProperty("MaxProjects");
|
||||
this.maxAdditionalServiceAccounts = this.getResponseProperty("MaxAdditionalServiceAccounts");
|
||||
this.stripeServiceAccountPlanId = this.getResponseProperty("StripeServiceAccountPlanId");
|
||||
this.maxProjects = this.getResponseProperty("MaxProjects");
|
||||
}
|
||||
}
|
||||
|
||||
export class PasswordManagerPlanFeaturesResponse extends BaseResponse {
|
||||
// Seats
|
||||
stripePlanId: string;
|
||||
stripeSeatPlanId: string;
|
||||
stripePremiumAccessPlanId: string;
|
||||
basePrice: number;
|
||||
seatPrice: number;
|
||||
premiumAccessOptionPrice: number;
|
||||
baseSeats: number;
|
||||
maxAdditionalSeats: number;
|
||||
maxSeats: number;
|
||||
hasPremiumAccessOption: boolean;
|
||||
|
||||
// Storage
|
||||
additionalStoragePricePerGb: number;
|
||||
stripeStoragePlanId: string;
|
||||
baseStorageGb: number;
|
||||
hasAdditionalStorageOption: boolean;
|
||||
maxAdditionalStorage: number;
|
||||
hasAdditionalSeatsOption: boolean;
|
||||
|
||||
// Feature
|
||||
maxCollections: number;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.stripePlanId = this.getResponseProperty("StripePlanId");
|
||||
this.stripeSeatPlanId = this.getResponseProperty("StripeSeatPlanId");
|
||||
this.stripeStoragePlanId = this.getResponseProperty("StripeStoragePlanId");
|
||||
this.stripePremiumAccessPlanId = this.getResponseProperty("StripePremiumAccessPlanId");
|
||||
this.basePrice = this.getResponseProperty("BasePrice");
|
||||
this.seatPrice = this.getResponseProperty("SeatPrice");
|
||||
this.baseSeats = this.getResponseProperty("BaseSeats");
|
||||
this.maxAdditionalSeats = this.getResponseProperty("MaxAdditionalSeats");
|
||||
this.premiumAccessOptionPrice = this.getResponseProperty("PremiumAccessOptionPrice");
|
||||
this.maxSeats = this.getResponseProperty("MaxSeats");
|
||||
this.additionalStoragePricePerGb = this.getResponseProperty("AdditionalStoragePricePerGb");
|
||||
this.hasAdditionalSeatsOption = this.getResponseProperty("HasAdditionalSeatsOption");
|
||||
this.baseStorageGb = this.getResponseProperty("BaseStorageGb");
|
||||
this.maxCollections = this.getResponseProperty("MaxCollections");
|
||||
this.hasAdditionalStorageOption = this.getResponseProperty("HasAdditionalStorageOption");
|
||||
this.maxAdditionalStorage = this.getResponseProperty("MaxAdditionalStorage");
|
||||
this.hasPremiumAccessOption = this.getResponseProperty("HasPremiumAccessOption");
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { BaseResponse } from "../../../models/response/base.response";
|
||||
import { BitwardenProductType } from "../../enums";
|
||||
|
||||
export class SubscriptionResponse extends BaseResponse {
|
||||
storageName: string;
|
||||
@ -67,7 +66,7 @@ export class BillingSubscriptionItemResponse extends BaseResponse {
|
||||
interval: string;
|
||||
sponsoredSubscriptionItem: boolean;
|
||||
addonSubscriptionItem: boolean;
|
||||
bitwardenProduct: BitwardenProductType;
|
||||
productName: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@ -77,7 +76,6 @@ export class BillingSubscriptionItemResponse extends BaseResponse {
|
||||
this.interval = this.getResponseProperty("Interval");
|
||||
this.sponsoredSubscriptionItem = this.getResponseProperty("SponsoredSubscriptionItem");
|
||||
this.addonSubscriptionItem = this.getResponseProperty("AddonSubscriptionItem");
|
||||
this.bitwardenProduct = this.getResponseProperty("BitwardenProduct");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -894,7 +894,7 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
// Plan APIs
|
||||
|
||||
async getPlans(): Promise<ListResponse<PlanResponse>> {
|
||||
const r = await this.send("GET", "/plans/all", null, false, true);
|
||||
const r = await this.send("GET", "/plans", null, false, true);
|
||||
return new ListResponse(r, PlanResponse);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user