+ {/** Public reserved plan buttons */}
{logtoSkus.map(({ id: skuId }) => {
- const isCurrentSku = currentSkuId === skuId;
- const isDowngrade = isDowngradePlan(currentSkuId, skuId);
-
- // Let user contact us when they are currently on Enterprise plan. Do not allow users to self-serve downgrade.
- return isEnterprisePlan ? (
-
- ) : (
-
- {
- void handleSubscribe(skuId, isDowngrade);
- }}
- />
-
+ return (
+
);
})}
+ {/** Enterprise plan button */}
{
@@ -35,25 +35,28 @@ export const formatLogtoSkusResponses = (logtoSkus: LogtoSkuResponse[] | undefin
return [];
}
- return logtoSkus
- .map((logtoSku) => addSupportQuota(logtoSku))
- .slice()
- .sort(
- ({ id: previousId }, { id: nextId }) =>
- featuredPlanIdOrder.indexOf(previousId) - featuredPlanIdOrder.indexOf(nextId)
- );
+ return logtoSkus.map((logtoSku) => addSupportQuota(logtoSku));
};
const getSubscriptionPlanOrderById = (id: string) => {
- const index = featuredPlanIdOrder.indexOf(id);
+ const index = planIdOrder[id];
// Note: if the plan id is not in the featuredPlanIdOrder, it will be treated as the highest priority
- return index === -1 ? Number.POSITIVE_INFINITY : index;
+ // E.g. enterprise plan.
+ return index ?? Number.POSITIVE_INFINITY;
};
export const isDowngradePlan = (fromPlanId: string, toPlanId: string) =>
getSubscriptionPlanOrderById(fromPlanId) > getSubscriptionPlanOrderById(toPlanId);
+/**
+ * Check if the two plan ids are equivalent,
+ * one is grandfathered and the other is public visible featured plan.
+ */
+export const isEquivalentPlan = (fromPlanId: string, toPlanId: string) =>
+ fromPlanId !== toPlanId &&
+ getSubscriptionPlanOrderById(fromPlanId) === getSubscriptionPlanOrderById(toPlanId);
+
type FormatPeriodOptions = {
periodStart: Date;
periodEnd: Date;
@@ -98,8 +101,18 @@ export const parseExceededSkuQuotaLimitError = async (
return [true, Object.keys(exceededQuota) as Array];
};
+/**
+ * Filter the featured plans (public visible) from the Logto SKUs API response.
+ * and sorted by the order of {@link planIdOrder}.
+ */
export const pickupFeaturedLogtoSkus = (logtoSkus: LogtoSkuResponse[]): LogtoSkuResponse[] =>
- logtoSkus.filter(({ id }) => featuredPlanIds.includes(id));
+ logtoSkus
+ .filter(({ id }) => featuredPlanIds.includes(id))
+ .slice()
+ .sort(
+ ({ id: previousId }, { id: nextId }) =>
+ getSubscriptionPlanOrderById(previousId) - getSubscriptionPlanOrderById(nextId)
+ );
export const isPaidPlan = (planId: string, isEnterprisePlan: boolean) =>
isProPlan(planId) || isEnterprisePlan;
diff --git a/packages/core/src/libraries/quota.ts b/packages/core/src/libraries/quota.ts
index fc440ca54..d09f8c3ef 100644
--- a/packages/core/src/libraries/quota.ts
+++ b/packages/core/src/libraries/quota.ts
@@ -14,6 +14,7 @@ import { type CloudConnectionLibrary } from './cloud-connection.js';
export type QuotaLibrary = ReturnType;
+const paidReservedPlans = new Set([ReservedPlanId.Pro, ReservedPlanId.Pro202411]);
/**
* @remarks
* Should report usage changes to the Cloud only when the following conditions are met:
@@ -25,7 +26,7 @@ const shouldReportSubscriptionUpdates = (
isEnterprisePlan: boolean,
key: keyof SubscriptionQuota
) =>
- (planId === ReservedPlanId.Pro || isEnterprisePlan) && isReportSubscriptionUpdatesUsageKey(key);
+ (paidReservedPlans.has(planId) || isEnterprisePlan) && isReportSubscriptionUpdatesUsageKey(key);
export const createQuotaLibrary = (cloudConnection: CloudConnectionLibrary) => {
const guardTenantUsageByKey = async (key: keyof SubscriptionUsage) => {
diff --git a/packages/phrases/src/locales/ar/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/ar/translation/admin-console/subscription/quota-table.ts
index 2f166746e..185db5b23 100644
--- a/packages/phrases/src/locales/ar/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/ar/translation/admin-console/subscription/quota-table.ts
@@ -101,6 +101,7 @@ const quota_table = {
included: '{{value, number}} مضمن',
included_mao: '{{value, number}} MAO مضمنة',
extra_quota_price: 'ثم ${{value, number}} شهريًا / لكل واحد بعد ذلك',
+ extra_token_price: 'ثم ${{value, number}} شهريًا / {{amount, number}} بعد ذلك',
per_month_each: '${{value, number}} شهريًا / لكل واحد',
extra_mao_price: 'ثم ${{value, number}} شهريًا لكل MAO',
per_month: '${{value, number}} شهريًا',
diff --git a/packages/phrases/src/locales/de/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/de/translation/admin-console/subscription/quota-table.ts
index f5ed0aab3..a6f1a901c 100644
--- a/packages/phrases/src/locales/de/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/de/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: '{{value, number}} inklusive',
included_mao: '{{value, number}} MAO enthalten',
extra_quota_price: 'Dann ${{value, number}} pro Monat / je danach',
+ extra_token_price: 'Dann ${{value, number}} pro Monat / {{amount, number}} danach',
per_month_each: '${{value, number}} pro Monat / je',
extra_mao_price: 'Dann ${{value, number}} pro MAO',
per_month: '${{value, number}} pro Monat',
diff --git a/packages/phrases/src/locales/en/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/en/translation/admin-console/subscription/quota-table.ts
index c35303e4b..7686d45e2 100644
--- a/packages/phrases/src/locales/en/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/en/translation/admin-console/subscription/quota-table.ts
@@ -104,6 +104,7 @@ const quota_table = {
included: '{{value, number}} included',
included_mao: '{{value, number}} MAO included',
extra_quota_price: 'Then ${{value, number}} per mo / ea after',
+ extra_token_price: 'Then ${{value, number}} per mo / {{amount, number}} after',
per_month_each: '${{value, number}} per mo / ea',
extra_mao_price: 'Then ${{value, number}} per MAO',
per_month: '${{value, number}} per mo',
diff --git a/packages/phrases/src/locales/es/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/es/translation/admin-console/subscription/quota-table.ts
index 4c10bf362..26fa7a114 100644
--- a/packages/phrases/src/locales/es/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/es/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: 'incluido{{value, number}}',
included_mao: '{{value, number}} MAO incluido',
extra_quota_price: 'Luego ${{value, number}} por mes / cada uno después',
+ extra_token_price: 'Luego ${{value, number}} por mes / {{amount, number}} después',
per_month_each: '${{value, number}} por mes / cada uno',
extra_mao_price: 'Luego ${{value, number}} por MAO',
per_month: '${{value, number}} por mes',
diff --git a/packages/phrases/src/locales/fr/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/fr/translation/admin-console/subscription/quota-table.ts
index 44852f5c0..c6b5856f1 100644
--- a/packages/phrases/src/locales/fr/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/fr/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: '{{value, number}} inclus',
included_mao: '{{value, number}} MAO inclus',
extra_quota_price: 'Ensuite ${{value, number}} par mois / chacun après',
+ extra_token_price: 'Ensuite ${{value, number}} par mois / {{amount, number}} après',
per_month_each: '${{value, number}} par mois / chacun',
extra_mao_price: 'Ensuite ${{value, number}} par MAO',
per_month: '${{value, number}} par mois',
diff --git a/packages/phrases/src/locales/it/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/it/translation/admin-console/subscription/quota-table.ts
index 802f49f5f..e6eb22ddc 100644
--- a/packages/phrases/src/locales/it/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/it/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: '{{value, number}} incluso',
included_mao: '{{value, number}} MAO inclusi',
extra_quota_price: 'Quindi ${{value, number}} al mese / ognuno dopo',
+ extra_token_price: 'Quindi ${{value, number}} al mese / {{amount, number}} dopo',
per_month_each: '${{value, number}} al mese / ognuno',
extra_mao_price: 'Quindi ${{value, number}} per MAO',
per_month: '${{value, number}} al mese',
diff --git a/packages/phrases/src/locales/ja/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/ja/translation/admin-console/subscription/quota-table.ts
index 589371b81..dd6abd6be 100644
--- a/packages/phrases/src/locales/ja/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/ja/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: '{{value, number}} 込み',
included_mao: '{{value, number}} MAO込み',
extra_quota_price: 'その後、各${{value, number}} / 月ごと',
+ extra_token_price: 'その後、${{value, number}} / 月ごと {{amount, number}} ごと',
per_month_each: '各${{value, number}} / 月ごと',
extra_mao_price: 'その後、MAOごとに${{value, number}}',
per_month: '${{value, number}} / 月ごと',
diff --git a/packages/phrases/src/locales/ko/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/ko/translation/admin-console/subscription/quota-table.ts
index 7caef6227..8781d8bc8 100644
--- a/packages/phrases/src/locales/ko/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/ko/translation/admin-console/subscription/quota-table.ts
@@ -100,6 +100,7 @@ const quota_table = {
included: '{{value, number}} 포함',
included_mao: '{{value, number}} MAO 포함',
extra_quota_price: '이후 월당 ${{value, number}} / 각각',
+ extra_token_price: '이후 월당 ${{value, number}} / 각각 {{amount, number}} 당',
per_month_each: '월당 ${{value, number}} / 각각',
extra_mao_price: '이후 MAO 당 ${{value, number}}',
per_month: '월당 ${{value, number}}',
diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/subscription/quota-table.ts
index 8358154bc..91d49fd8b 100644
--- a/packages/phrases/src/locales/pl-pl/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: '{{value, number}} zawarte',
included_mao: '{{value, number}} MAO wliczone',
extra_quota_price: 'Następnie ${{value, number}} za miesiąc / każdy po',
+ extra_token_price: 'Następnie ${{value, number}} za miesiąc / {{amount, number}} po',
per_month_each: '${{value, number}} za miesiąc / każdy',
extra_mao_price: 'Następnie ${{value, number}} za MAO',
per_month: '${{value, number}} za miesiąc',
diff --git a/packages/phrases/src/locales/pt-br/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/pt-br/translation/admin-console/subscription/quota-table.ts
index 502dfd292..7f8ef6e2e 100644
--- a/packages/phrases/src/locales/pt-br/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/pt-br/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: 'incluído{{value, number}}',
included_mao: '{{value, number}} MAO incluído',
extra_quota_price: 'Então ${{value, number}} por mês / cada depois',
+ extra_token_price: 'Então ${{value, number}} por mês / {{amount, number}} depois',
per_month_each: '${{value, number}} por mês / cada',
extra_mao_price: 'Então ${{value, number}} por MAO',
per_month: '${{value, number}} por mês',
diff --git a/packages/phrases/src/locales/pt-pt/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/pt-pt/translation/admin-console/subscription/quota-table.ts
index eef38cd06..d868805a3 100644
--- a/packages/phrases/src/locales/pt-pt/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/pt-pt/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: 'incluído{{value, number}}',
included_mao: '{{value, number}} MAO incluída',
extra_quota_price: 'Depois ${{value, number}} por mês / cada um depois',
+ extra_token_price: 'Depois ${{value, number}} por mês / {{amount, number}} depois',
per_month_each: '${{value, number}} por mês / cada um',
extra_mao_price: 'Depois ${{value, number}} por MAO',
per_month: '${{value, number}} por mês',
diff --git a/packages/phrases/src/locales/ru/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/ru/translation/admin-console/subscription/quota-table.ts
index 4e8153ab1..92379e7af 100644
--- a/packages/phrases/src/locales/ru/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/ru/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: 'включено {{value, number}}',
included_mao: '{{value, number}} MAO включено',
extra_quota_price: 'Затем $ {{value, number}} в месяц / за каждый после',
+ extra_token_price: 'Затем $ {{value, number}} в месяц / {{amount, number}} за каждый после',
per_month_each: '$ {{value, number}} в месяц / за каждый',
extra_mao_price: 'Затем $ {{value, number}} за MAO',
per_month: '$ {{value, number}} в месяц',
diff --git a/packages/phrases/src/locales/tr-tr/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/tr-tr/translation/admin-console/subscription/quota-table.ts
index df662ac5c..296774452 100644
--- a/packages/phrases/src/locales/tr-tr/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/tr-tr/translation/admin-console/subscription/quota-table.ts
@@ -102,6 +102,7 @@ const quota_table = {
included: '{{value, number}} dahil',
included_mao: '{{value, number}} MAO dahil',
extra_quota_price: 'Sonra aylık ${{value, number}} / sonrasında her biri',
+ extra_token_price: 'Sonra aylık ${{value, number}} / {{amount, number}} her biri',
per_month_each: 'Aylık ${{value, number}} / her biri',
extra_mao_price: 'Sonra MAO başına ${{value, number}}',
per_month: 'Aylık ${{value, number}}',
diff --git a/packages/phrases/src/locales/zh-cn/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/zh-cn/translation/admin-console/subscription/quota-table.ts
index 9ed44e845..cba9f367d 100644
--- a/packages/phrases/src/locales/zh-cn/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/zh-cn/translation/admin-console/subscription/quota-table.ts
@@ -98,6 +98,7 @@ const quota_table = {
included: '已包含{{value, number}}',
included_mao: '已包含 {{value, number}} MAO',
extra_quota_price: '然后每月 ${{value, number}} / 每个之后',
+ extra_token_price: '然后每月 ${{value, number}} / 每 {{amount, number}} 之后',
per_month_each: '每月 ${{value, number}} / 每个',
extra_mao_price: '然后每 MAO ${{value, number}}',
per_month: '每月 ${{value, number}}',
diff --git a/packages/phrases/src/locales/zh-hk/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/zh-hk/translation/admin-console/subscription/quota-table.ts
index 1078be38a..52d5eef1e 100644
--- a/packages/phrases/src/locales/zh-hk/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/zh-hk/translation/admin-console/subscription/quota-table.ts
@@ -98,6 +98,7 @@ const quota_table = {
included: '已包含 {{value, number}}',
included_mao: '已包含 {{value, number}} MAO',
extra_quota_price: '然後每月 ${{value, number}} / 每個之後',
+ extra_token_price: '然後每月 ${{value, number}} / 每 {{amount, number}} 之後',
per_month_each: '每月 ${{value, number}} / 每個',
extra_mao_price: '然後每 MAO ${{value, number}}',
per_month: '每月 ${{value, number}}',
diff --git a/packages/phrases/src/locales/zh-tw/translation/admin-console/subscription/quota-table.ts b/packages/phrases/src/locales/zh-tw/translation/admin-console/subscription/quota-table.ts
index e2376e1e6..962e7f4de 100644
--- a/packages/phrases/src/locales/zh-tw/translation/admin-console/subscription/quota-table.ts
+++ b/packages/phrases/src/locales/zh-tw/translation/admin-console/subscription/quota-table.ts
@@ -98,6 +98,7 @@ const quota_table = {
included: '已包含 {{value, number}}',
included_mao: '已包含 {{value, number}} MAO',
extra_quota_price: '然後每月 ${{value, number}} / 每個之後',
+ extra_token_price: '然後每月 ${{value, number}} / 每 {{amount, number}} 之後',
per_month_each: '每月 ${{value, number}} / 每個',
extra_mao_price: '然後每 MAO ${{value, number}}',
per_month: '每月 ${{value, number}}',