1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-26793] Fetch premium plan from pricing service (#16858)

* Fetch premium plan from pricing service

* Resolve Claude feedback
This commit is contained in:
Alex Morask
2025-10-23 09:13:26 -05:00
committed by GitHub
parent 7f86f2d0ac
commit 7321e3132b
9 changed files with 591 additions and 224 deletions

View File

@@ -1,3 +1,5 @@
import { PremiumPlanResponse } from "@bitwarden/common/billing/models/response/premium-plan.response";
import { OrganizationCreateRequest } from "../../admin-console/models/request/organization-create.request";
import { SubscriptionCancellationRequest } from "../../billing/models/request/subscription-cancellation.request";
import { OrganizationBillingMetadataResponse } from "../../billing/models/response/organization-billing-metadata.response";
@@ -25,6 +27,8 @@ export abstract class BillingApiServiceAbstraction {
abstract getPlans(): Promise<ListResponse<PlanResponse>>;
abstract getPremiumPlan(): Promise<PremiumPlanResponse>;
abstract getProviderClientInvoiceReport(providerId: string, invoiceId: string): Promise<string>;
abstract getProviderInvoices(providerId: string): Promise<InvoicesResponse>;

View File

@@ -0,0 +1,47 @@
import { BaseResponse } from "@bitwarden/common/models/response/base.response";
export class PremiumPlanResponse extends BaseResponse {
seat: {
stripePriceId: string;
price: number;
};
storage: {
stripePriceId: string;
price: number;
};
constructor(response: any) {
super(response);
const seat = this.getResponseProperty("Seat");
if (!seat || typeof seat !== "object") {
throw new Error("PremiumPlanResponse: Missing or invalid 'Seat' property");
}
this.seat = new PurchasableResponse(seat);
const storage = this.getResponseProperty("Storage");
if (!storage || typeof storage !== "object") {
throw new Error("PremiumPlanResponse: Missing or invalid 'Storage' property");
}
this.storage = new PurchasableResponse(storage);
}
}
class PurchasableResponse extends BaseResponse {
stripePriceId: string;
price: number;
constructor(response: any) {
super(response);
this.stripePriceId = this.getResponseProperty("StripePriceId");
if (!this.stripePriceId || typeof this.stripePriceId !== "string") {
throw new Error("PurchasableResponse: Missing or invalid 'StripePriceId' property");
}
this.price = this.getResponseProperty("Price");
if (typeof this.price !== "number" || isNaN(this.price)) {
throw new Error("PurchasableResponse: Missing or invalid 'Price' property");
}
}
}

View File

@@ -1,6 +1,8 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { PremiumPlanResponse } from "@bitwarden/common/billing/models/response/premium-plan.response";
import { ApiService } from "../../abstractions/api.service";
import { OrganizationCreateRequest } from "../../admin-console/models/request/organization-create.request";
import { ListResponse } from "../../models/response/list.response";
@@ -61,10 +63,15 @@ export class BillingApiService implements BillingApiServiceAbstraction {
}
async getPlans(): Promise<ListResponse<PlanResponse>> {
const r = await this.apiService.send("GET", "/plans", null, false, true);
const r = await this.apiService.send("GET", "/plans", null, true, true);
return new ListResponse(r, PlanResponse);
}
async getPremiumPlan(): Promise<PremiumPlanResponse> {
const response = await this.apiService.send("GET", "/plans/premium", null, true, true);
return new PremiumPlanResponse(response);
}
async getProviderClientInvoiceReport(providerId: string, invoiceId: string): Promise<string> {
const response = await this.apiService.send(
"GET",

View File

@@ -30,6 +30,7 @@ export enum FeatureFlag {
PM25379_UseNewOrganizationMetadataStructure = "pm-25379-use-new-organization-metadata-structure",
PM24996_ImplementUpgradeFromFreeDialog = "pm-24996-implement-upgrade-from-free-dialog",
PM24033PremiumUpgradeNewDesign = "pm-24033-updat-premium-subscription-page",
PM26793_FetchPremiumPriceFromPricingService = "pm-26793-fetch-premium-price-from-pricing-service",
/* Key Management */
PrivateKeyRegeneration = "pm-12241-private-key-regeneration",
@@ -115,6 +116,7 @@ export const DefaultFeatureFlagValue = {
[FeatureFlag.PM25379_UseNewOrganizationMetadataStructure]: FALSE,
[FeatureFlag.PM24996_ImplementUpgradeFromFreeDialog]: FALSE,
[FeatureFlag.PM24033PremiumUpgradeNewDesign]: FALSE,
[FeatureFlag.PM26793_FetchPremiumPriceFromPricingService]: FALSE,
/* Key Management */
[FeatureFlag.PrivateKeyRegeneration]: FALSE,