Skip to content

Commit b7966d5

Browse files
authored
refactor(console): update tenant subscription page (#8121)
* refactor(console): update tenant subscription page update tenant subscription settings page * refactor(console): remove duplicate hook statement remove duplicate hook statement
1 parent e8430cc commit b7966d5

File tree

5 files changed

+86
-39
lines changed

5 files changed

+86
-39
lines changed

packages/console/src/components/PlanUsage/PlanUsageCard/index.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export type Props = {
9898
readonly usageAddOnSku?: LogtoSkuResponse;
9999
};
100100

101+
// eslint-disable-next-line complexity
101102
function PlanUsageCard({
102103
usage,
103104
quota,
@@ -112,7 +113,7 @@ function PlanUsageCard({
112113
}: Props) {
113114
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
114115
const {
115-
currentSubscription: { planId, isEnterprisePlan },
116+
currentSubscription: { planId, isEnterprisePlan, quotaScope },
116117
} = useContext(SubscriptionDataContext);
117118

118119
const isPaidTenant = isPaidPlan(planId, isEnterprisePlan);
@@ -175,7 +176,11 @@ function PlanUsageCard({
175176
className={classNames(
176177
styles.usageTip,
177178
// Hide usage tip for free plan users.
178-
(!isPaidTenant || basicQuota === undefined || isQuotaNoticeHidden) &&
179+
(!isPaidTenant ||
180+
// Hide usage tip for shared enterprise subscription tenants.
181+
quotaScope === 'shared' ||
182+
basicQuota === undefined ||
183+
isQuotaNoticeHidden) &&
179184
styles.hidden
180185
)}
181186
/>
@@ -225,8 +230,8 @@ function PlanUsageCard({
225230
forKey={`subscription.usage.${usage ? 'status_active' : 'status_inactive'}`}
226231
/>
227232
</Tag>
228-
{/* Only show the quota notice for enterprise plan. */}
229-
{quota !== undefined && isEnterprisePlan && (
233+
{/* Only show the quota notice for enterprise plan with non-shared quota scope */}
234+
{quota !== undefined && isEnterprisePlan && quotaScope !== 'shared' && (
230235
<div className={styles.usageTip}>
231236
{/* Consider the type of quota is number, null or boolean, the following statement covers all cases. */}
232237
{(() => {

packages/console/src/hooks/use-console-routes/routes/tenant-settings.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Navigate, type RouteObject } from 'react-router-dom';
44
import { safeLazy } from 'react-safe-lazy';
55

66
import { TenantSettingsTabs } from '@/consts';
7+
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
78
import { TenantsContext } from '@/contexts/TenantsProvider';
89
import useCurrentTenantScopes from '@/hooks/use-current-tenant-scopes';
910
import NotFound from '@/pages/NotFound';
@@ -25,6 +26,9 @@ const Subscription = safeLazy(async () => import('@/pages/TenantSettings/Subscri
2526

2627
export const useTenantSettings = () => {
2728
const { isDevTenant } = useContext(TenantsContext);
29+
const {
30+
currentSubscription: { quotaScope },
31+
} = useContext(SubscriptionDataContext);
2832
const {
2933
access: { canInviteMember, canManageTenant },
3034
} = useCurrentTenantScopes();
@@ -57,11 +61,16 @@ export const useTenantSettings = () => {
5761
!isDevTenant &&
5862
canManageTenant && [
5963
{ path: TenantSettingsTabs.Subscription, element: <Subscription /> },
60-
{ path: TenantSettingsTabs.BillingHistory, element: <BillingHistory /> },
64+
...condArray(
65+
// Hide the billing history page if the tenant is associated with a shared enterprise subscription
66+
quotaScope !== 'shared' && [
67+
{ path: TenantSettingsTabs.BillingHistory, element: <BillingHistory /> },
68+
]
69+
),
6170
]
6271
),
6372
}),
64-
[canInviteMember, canManageTenant, isDevTenant]
73+
[canInviteMember, canManageTenant, isDevTenant, quotaScope]
6574
);
6675

6776
return tenantSettings;

packages/console/src/pages/TenantSettings/Subscription/CurrentPlan/index.tsx

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type Props = {
2424
function CurrentPlan({ periodicUsage, usageAddOnSkus }: Props) {
2525
const {
2626
currentSku: { unitPrice },
27-
currentSubscription: { upcomingInvoice, isEnterprisePlan, planId },
27+
currentSubscription: { upcomingInvoice, isEnterprisePlan, planId, quotaScope },
2828
} = useContext(SubscriptionDataContext);
2929

3030
/**
@@ -53,21 +53,29 @@ function CurrentPlan({ periodicUsage, usageAddOnSkus }: Props) {
5353
<FormField title="subscription.plan_usage">
5454
<PlanUsage periodicUsage={periodicUsage} usageAddOnSkus={usageAddOnSkus} />
5555
</FormField>
56-
<FormField title="subscription.next_bill">
57-
<BillInfo
58-
cost={upcomingCost}
59-
isManagePaymentVisible={isPaidPlan(planId, isEnterprisePlan)}
60-
/>
61-
</FormField>
62-
{isPaidPlan(planId, isEnterprisePlan) && !isEnterprisePlan && (
63-
<AddOnUsageChangesNotification className={styles.notification} />
56+
{/* Only show usageExceed and payment info if the subscription quota scope is dedicated */}
57+
{quotaScope === 'dedicated' && (
58+
<>
59+
<FormField title="subscription.next_bill">
60+
<BillInfo
61+
cost={upcomingCost}
62+
isManagePaymentVisible={isPaidPlan(planId, isEnterprisePlan)}
63+
/>
64+
</FormField>
65+
{isPaidPlan(planId, isEnterprisePlan) && !isEnterprisePlan && (
66+
<AddOnUsageChangesNotification className={styles.notification} />
67+
)}
68+
<TokenLimitExceededNotification
69+
periodicUsage={periodicUsage}
70+
className={styles.notification}
71+
/>
72+
<MauLimitExceedNotification
73+
periodicUsage={periodicUsage}
74+
className={styles.notification}
75+
/>
76+
<PaymentOverdueNotification className={styles.notification} />
77+
</>
6478
)}
65-
<TokenLimitExceededNotification
66-
periodicUsage={periodicUsage}
67-
className={styles.notification}
68-
/>
69-
<MauLimitExceedNotification periodicUsage={periodicUsage} className={styles.notification} />
70-
<PaymentOverdueNotification className={styles.notification} />
7179
</FormCard>
7280
);
7381
}

packages/console/src/pages/TenantSettings/Subscription/index.tsx

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type ResponseError } from '@withtyped/client';
2-
import { useContext, useEffect } from 'react';
2+
import { useContext, useEffect, useMemo } from 'react';
33
import useSWR from 'swr';
44

55
import { useCloudApi } from '@/cloud/hooks/use-cloud-api';
@@ -8,6 +8,7 @@ import PageMeta from '@/components/PageMeta';
88
import { isCloud } from '@/consts/env';
99
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
1010
import { TenantsContext } from '@/contexts/TenantsProvider';
11+
import useAvailableRegions from '@/hooks/use-available-regions';
1112
import { pickupFeaturedLogtoSkus } from '@/utils/subscription';
1213

1314
import Skeleton from '../components/Skeleton';
@@ -21,7 +22,10 @@ function Subscription() {
2122
const cloudApi = useCloudApi();
2223
const { logtoSkus, currentSku, onCurrentSubscriptionUpdated } =
2324
useContext(SubscriptionDataContext);
24-
const { currentTenantId, updateTenant } = useContext(TenantsContext);
25+
26+
const { currentTenant, currentTenantId, updateTenant } = useContext(TenantsContext);
27+
28+
const regions = useAvailableRegions();
2529

2630
const reservedSkus = pickupFeaturedLogtoSkus(logtoSkus);
2731

@@ -43,6 +47,15 @@ function Subscription() {
4347
})
4448
);
4549

50+
const isPrivateRegionTenant = useMemo(() => {
51+
if (!currentTenant) {
52+
return false;
53+
}
54+
55+
const region = regions.getRegionByName(currentTenant.regionName);
56+
return region ? region.isPrivate : false;
57+
}, [currentTenant, regions]);
58+
4659
const isLoading =
4760
(!periodicUsage && !periodicUsageError) || (!usageAddOnSkus && !usageAddOnSkusError);
4861

@@ -71,19 +84,24 @@ function Subscription() {
7184
<div className={styles.container}>
7285
<PageMeta titleKey={['tenants.tabs.subscription', 'tenants.title']} />
7386
<CurrentPlan periodicUsage={periodicUsage} usageAddOnSkus={usageAddOnSkus} />
74-
<ConsoleEmbeddedPricing />
75-
<SwitchPlanActionBar
76-
currentSkuId={currentSku.id}
77-
logtoSkus={reservedSkus}
78-
onSubscriptionUpdated={async () => {
79-
/**
80-
* The upcoming billing info is calculated based on the current subscription usage,
81-
* and the usage is based on the current subscription plan,
82-
* need to manually trigger the usage update while the subscription plan is changed.
83-
*/
84-
onCurrentSubscriptionUpdated();
85-
}}
86-
/>
87+
{/* Hide pricing table for private regions */}
88+
{!isPrivateRegionTenant && (
89+
<>
90+
<ConsoleEmbeddedPricing />
91+
<SwitchPlanActionBar
92+
currentSkuId={currentSku.id}
93+
logtoSkus={reservedSkus}
94+
onSubscriptionUpdated={async () => {
95+
/**
96+
* The upcoming billing info is calculated based on the current subscription usage,
97+
* and the usage is based on the current subscription plan,
98+
* need to manually trigger the usage update while the subscription plan is changed.
99+
*/
100+
onCurrentSubscriptionUpdated();
101+
}}
102+
/>
103+
</>
104+
)}
87105
</div>
88106
);
89107
}

packages/console/src/pages/TenantSettings/index.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useContext } from 'react';
22
import { Outlet } from 'react-router-dom';
33

44
import { logtoCloud, TenantSettingsTabs } from '@/consts';
5+
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
56
import { TenantsContext } from '@/contexts/TenantsProvider';
67
import CardTitle from '@/ds-components/CardTitle';
78
import DynamicT from '@/ds-components/DynamicT';
@@ -13,6 +14,9 @@ import styles from './index.module.scss';
1314

1415
function TenantSettings() {
1516
const { isDevTenant } = useContext(TenantsContext);
17+
const {
18+
currentSubscription: { quotaScope },
19+
} = useContext(SubscriptionDataContext);
1620
const {
1721
access: { canManageTenant },
1822
} = useCurrentTenantScopes();
@@ -41,9 +45,12 @@ function TenantSettings() {
4145
<TabNavItem href={`/tenant-settings/${TenantSettingsTabs.Subscription}`}>
4246
<DynamicT forKey="tenants.tabs.subscription" />
4347
</TabNavItem>
44-
<TabNavItem href={`/tenant-settings/${TenantSettingsTabs.BillingHistory}`}>
45-
<DynamicT forKey="tenants.tabs.billing_history" />
46-
</TabNavItem>
48+
{/* Hide the billing management and invoice pages if the tenant is associated with a shared enterprise subscription */}
49+
{quotaScope !== 'shared' && (
50+
<TabNavItem href={`/tenant-settings/${TenantSettingsTabs.BillingHistory}`}>
51+
<DynamicT forKey="tenants.tabs.billing_history" />
52+
</TabNavItem>
53+
)}
4754
</>
4855
)}
4956
</TabNav>

0 commit comments

Comments
 (0)