1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-01-22 21:21:35 +01:00

[PM-16662] Fix annual pricing for billable providers (#12657)

This commit is contained in:
Jonas Hendrickx 2025-01-22 12:22:53 +01:00 committed by GitHub
parent 8784602858
commit 09748389e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 38 additions and 24 deletions

View File

@ -25,7 +25,7 @@
<tr bitRow *ngFor="let i of activePlans">
<td bitCell class="tw-pl-0 tw-py-3">
{{ getFormattedPlanName(i.planName) }} {{ "orgSeats" | i18n }} ({{
i.cadence.toLowerCase()
getFormattedPlanNameCadence(i.cadence) | i18n
}}) {{ "&times;" }}{{ getFormattedSeatCount(i.seatMinimum, i.purchasedSeats) }}
&#64;
{{
@ -38,12 +38,11 @@
}}
</td>
<td bitCell class="tw-text-right tw-py-3">
{{ ((100 - subscription.discountPercentage) / 100) * i.cost | currency: "$" }} /{{
"month" | i18n
}}
{{ ((100 - subscription.discountPercentage) / 100) * i.cost | currency: "$" }} /
{{ getBillingCadenceLabel(i) | i18n }}
<div *ngIf="subscription.discountPercentage">
<bit-hint class="tw-text-sm tw-line-through">
{{ i.cost | currency: "$" }} /{{ "month" | i18n }}
{{ i.cost | currency: "$" }} / {{ getBillingCadenceLabel(i) | i18n }}
</bit-hint>
</div>
</td>
@ -52,8 +51,9 @@
<tr bitRow>
<td bitCell class="tw-pl-0 tw-py-3"></td>
<td bitCell class="tw-text-right">
<span class="tw-font-bold">Total:</span> {{ totalCost | currency: "$" }} /{{
"month" | i18n
<span class="tw-font-bold">Total:</span> {{ totalCost | currency: "$" }} /
{{
getBillingCadenceLabel(activePlans.length > 0 ? activePlans[0] : null) | i18n
}}
</td>
</tr>

View File

@ -19,14 +19,13 @@ import { ToastService } from "@bitwarden/components";
templateUrl: "./provider-subscription.component.html",
})
export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
providerId: string;
subscription: ProviderSubscriptionResponse;
private providerId: string;
protected subscription: ProviderSubscriptionResponse;
firstLoaded = false;
loading: boolean;
protected firstLoaded = false;
protected loading: boolean;
private destroy$ = new Subject<void>();
totalCost: number;
currentDate = new Date();
protected totalCost: number;
protected readonly TaxInformation = TaxInformation;
@ -50,11 +49,7 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
.subscribe();
}
get isExpired() {
return this.subscription.status !== "active";
}
async load() {
protected async load() {
if (this.loading) {
return;
}
@ -65,7 +60,7 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
this.loading = false;
}
updateTaxInformation = async (taxInformation: TaxInformation) => {
protected updateTaxInformation = async (taxInformation: TaxInformation) => {
const request = ExpandedTaxInfoUpdateRequest.From(taxInformation);
await this.billingApiService.updateProviderTaxInformation(this.providerId, request);
this.toastService.showToast({
@ -75,7 +70,7 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
});
};
getFormattedCost(
protected getFormattedCost(
cost: number,
seatMinimum: number,
purchasedSeats: number,
@ -85,17 +80,21 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
return costPerSeat - (costPerSeat * discountPercentage) / 100;
}
getFormattedPlanName(planName: string): string {
protected getFormattedPlanName(planName: string): string {
const spaceIndex = planName.indexOf(" ");
return planName.substring(0, spaceIndex);
}
getFormattedSeatCount(seatMinimum: number, purchasedSeats: number): string {
protected getFormattedSeatCount(seatMinimum: number, purchasedSeats: number): string {
const totalSeats = seatMinimum + purchasedSeats;
return totalSeats > 1 ? totalSeats.toString() : "";
}
sumCost(plans: ProviderPlanResponse[]): number {
protected getFormattedPlanNameCadence(cadence: string) {
return cadence === "Annual" ? "annually" : "monthly";
}
private sumCost(plans: ProviderPlanResponse[]): number {
return plans.reduce((acc, plan) => acc + plan.cost, 0);
}
@ -104,7 +103,7 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
this.destroy$.complete();
}
get activePlans(): ProviderPlanResponse[] {
protected get activePlans(): ProviderPlanResponse[] {
return this.subscription.plans.filter((plan) => {
if (plan.purchasedSeats === 0) {
return plan.seatMinimum > 0;
@ -113,4 +112,19 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy {
}
});
}
protected getBillingCadenceLabel(providerPlanResponse: ProviderPlanResponse): string {
if (providerPlanResponse == null || providerPlanResponse == undefined) {
return "month";
}
switch (providerPlanResponse.cadence) {
case "Monthly":
return "month";
case "Annual":
return "year";
default:
return "month";
}
}
}