Skip to content

Commit 8c6c961

Browse files
authored
feat(sdk): group features by title (#529)
* chore: update frontier client * chore: group features by title * chore: show interval based on plan interval
1 parent 2a9686e commit 8c6c961

File tree

5 files changed

+42
-28
lines changed

5 files changed

+42
-28
lines changed

sdks/js/packages/core/client/V1Beta1.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,16 +1759,17 @@ export class V1Beta1<SecurityDataType = unknown> extends HttpClient<SecurityData
17591759
orgId: string,
17601760
billingId: string,
17611761
id: string,
1762-
query?: {
1762+
body: {
17631763
immediate?: boolean;
17641764
},
17651765
params: RequestParams = {}
17661766
) =>
17671767
this.request<V1Beta1CancelSubscriptionResponse, RpcStatus>({
17681768
path: `/v1beta1/organizations/${orgId}/billing/${billingId}/subscriptions/${id}/cancel`,
17691769
method: 'POST',
1770-
query: query,
1770+
body: body,
17711771
secure: true,
1772+
type: ContentType.Json,
17721773
format: 'json',
17731774
...params
17741775
});
@@ -2360,10 +2361,11 @@ export class V1Beta1<SecurityDataType = unknown> extends HttpClient<SecurityData
23602361
* @request POST:/v1beta1/organizations/{org_id}/invitations/{id}/accept
23612362
* @secure
23622363
*/
2363-
frontierServiceAcceptOrganizationInvitation = (orgId: string, id: string, params: RequestParams = {}) =>
2364+
frontierServiceAcceptOrganizationInvitation = (orgId: string, id: string, body: object, params: RequestParams = {}) =>
23642365
this.request<V1Beta1AcceptOrganizationInvitationResponse, RpcStatus>({
23652366
path: `/v1beta1/organizations/${orgId}/invitations/${id}/accept`,
23662367
method: 'POST',
2368+
body: body,
23672369
secure: true,
23682370
format: 'json',
23692371
...params
@@ -2377,10 +2379,11 @@ export class V1Beta1<SecurityDataType = unknown> extends HttpClient<SecurityData
23772379
* @request POST:/v1beta1/organizations/{org_id}/join
23782380
* @secure
23792381
*/
2380-
frontierServiceJoinOrganization = (orgId: string, params: RequestParams = {}) =>
2382+
frontierServiceJoinOrganization = (orgId: string, body: object, params: RequestParams = {}) =>
23812383
this.request<V1Beta1JoinOrganizationResponse, RpcStatus>({
23822384
path: `/v1beta1/organizations/${orgId}/join`,
23832385
method: 'POST',
2386+
body: body,
23842387
secure: true,
23852388
format: 'json',
23862389
...params

sdks/js/packages/core/client/data-contracts.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,8 @@ export interface V1Beta1CheckoutSetupBody {
307307

308308
export interface V1Beta1CheckoutSubscriptionBody {
309309
plan?: string;
310-
/** @format int32 */
311-
trail_days?: number;
310+
skip_trial?: boolean;
311+
cancel_after_trial?: boolean;
312312
}
313313

314314
export interface V1Beta1CreateBillingAccountResponse {
@@ -554,8 +554,11 @@ export type V1Beta1EnableUserResponse = object;
554554

555555
export interface V1Beta1Feature {
556556
id?: string;
557+
/** machine friendly name */
557558
name?: string;
558559
product_ids?: string[];
560+
/** human friendly name */
561+
title?: string;
559562
metadata?: object;
560563
/** @format date-time */
561564
created_at?: string;

sdks/js/packages/core/react/components/organization/plans/helpers/index.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,23 @@ export function groupPlansPricingByInterval(plans: V1Beta1Plan[]) {
4141
return acc;
4242
}, {} as IntervalPricing) || ({} as IntervalPricing);
4343

44-
plan?.products?.forEach(product => {
45-
product.features?.forEach(feature => {
46-
plansMap[slug].features[feature?.id || ''] = feature;
47-
});
48-
}, {} as IntervalPricing) || ({} as IntervalPricing);
49-
5044
const planMetadata = (plan?.metadata as Record<string, string>) || {};
5145
plansMap[slug].intervals[planInterval] = {
5246
planId: plan?.id || '',
5347
planName: plan?.name || '',
5448
interval: planInterval,
5549
weightage: planMetadata?.weightage ? Number(planMetadata?.weightage) : 0,
50+
features: {},
5651
...productPrices
5752
};
5853

54+
plan?.products?.forEach(product => {
55+
product.features?.forEach(feature => {
56+
plansMap[slug].intervals[planInterval].features[feature?.title || ''] =
57+
feature;
58+
});
59+
}, {} as IntervalPricing) || ({} as IntervalPricing);
60+
5961
plansMap[slug].weightage = Object.values(plansMap[slug].intervals).reduce(
6062
(acc, data) => acc + data.weightage,
6163
0

sdks/js/packages/core/react/components/organization/plans/index.tsx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ const PlanPricingColumn = ({
9292
allowAction
9393
}: {
9494
plan: PlanIntervalPricing;
95-
features: V1Beta1Feature[];
95+
features: string[];
9696
currentPlan?: IntervalPricingWithPlan;
9797
allowAction: boolean;
9898
}) => {
@@ -258,13 +258,16 @@ const PlanPricingColumn = ({
258258
</Flex>
259259
</Flex>
260260
{features.map(feature => {
261-
const featureId = feature?.id || '';
262-
const planFeature = _.get(plan?.features, featureId, { metadata: {} });
261+
const planFeature = _.get(
262+
plan?.intervals[selectedInterval].features,
263+
feature,
264+
{ metadata: {} }
265+
);
263266
const value = (planFeature?.metadata as Record<string, any>)?.value;
264267
const isAvailable = value?.toLowerCase() === 'true';
265268
return (
266269
<Flex
267-
key={featureId + '-' + plan?.slug}
270+
key={feature + '-' + plan?.slug}
268271
align={'center'}
269272
justify={'start'}
270273
className={plansStyles.featureCell}
@@ -314,15 +317,18 @@ const PlansList = ({
314317
});
315318

316319
const totalFeatures = features.length;
317-
const sortedFeatures = features
318-
.sort((f1, f2) => ((f1?.name || '') > (f2?.name || '') ? -1 : 1))
319-
.sort((f1, f2) => {
320-
const f1Weight =
321-
(f1.metadata as Record<string, any>)?.weightage || totalFeatures;
322-
const f2Weight =
323-
(f2.metadata as Record<string, any>)?.weightage || totalFeatures;
324-
return f1Weight - f2Weight;
325-
});
320+
321+
const featureTitleMap = features.reduce((acc, f) => {
322+
const weightage =
323+
(f.metadata as Record<string, any>)?.weightage || totalFeatures;
324+
acc[f.title || ''] = weightage;
325+
return acc;
326+
}, {} as Record<string, number>);
327+
328+
const sortedFeatures = Object.entries(featureTitleMap)
329+
.sort((f1, f2) => f1[1] - f2[1])
330+
.map(f => f[0])
331+
.filter(f => Boolean(f));
326332

327333
return (
328334
<Flex>
@@ -342,13 +348,13 @@ const PlansList = ({
342348
{sortedFeatures.map(feature => {
343349
return (
344350
<Flex
345-
key={feature?.id}
351+
key={feature}
346352
align={'center'}
347353
justify={'start'}
348354
className={plansStyles.featureCell}
349355
>
350356
<Text size={3} className={plansStyles.featureLabel}>
351-
{feature?.name}
357+
{feature}
352358
</Text>
353359
</Flex>
354360
);

sdks/js/packages/core/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export interface IntervalPricingWithPlan extends IntervalPricing {
8383
planName: string;
8484
interval: IntervalKeys;
8585
weightage: number;
86+
features: Record<string, V1Beta1Feature>;
8687
}
8788

8889
export interface PlanIntervalPricing {
@@ -91,5 +92,4 @@ export interface PlanIntervalPricing {
9192
description: string;
9293
intervals: Record<IntervalKeys, IntervalPricingWithPlan>;
9394
weightage: number;
94-
features: Record<string, V1Beta1Feature>;
9595
}

0 commit comments

Comments
 (0)