diff --git a/.changeset/public-bags-stay.md b/.changeset/public-bags-stay.md
new file mode 100644
index 00000000000..8ead721e2f4
--- /dev/null
+++ b/.changeset/public-bags-stay.md
@@ -0,0 +1,6 @@
+---
+'@clerk/clerk-js': patch
+'@clerk/types': patch
+---
+
+Adjust the cases in which the Billing item shows within the `UserProfile` and `OrgProfile` components
diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts
index 8d1f5450c43..7e2072600c7 100644
--- a/packages/clerk-js/src/core/clerk.ts
+++ b/packages/clerk-js/src/core/clerk.ts
@@ -94,8 +94,8 @@ import {
createAllowedRedirectOrigins,
createBeforeUnloadTracker,
createPageLifecycle,
+ disabledAllBillingFeatures,
disabledAPIKeysFeature,
- disabledBillingFeature,
disabledOrganizationsFeature,
errorThrower,
generateSignatureWithCoinbaseWallet,
@@ -576,7 +576,7 @@ export class Clerk implements ClerkInterface {
public __internal_openCheckout = (props?: __internal_CheckoutProps): void => {
this.assertComponentsReady(this.#componentControls);
- if (disabledBillingFeature(this, this.environment)) {
+ if (disabledAllBillingFeatures(this, this.environment)) {
if (this.#instanceType === 'development') {
throw new ClerkRuntimeError(warnings.cannotRenderAnyCommerceComponent('Checkout'), {
code: CANNOT_RENDER_BILLING_DISABLED_ERROR_CODE,
@@ -605,7 +605,7 @@ export class Clerk implements ClerkInterface {
public __internal_openPlanDetails = (props: __internal_PlanDetailsProps): void => {
this.assertComponentsReady(this.#componentControls);
- if (disabledBillingFeature(this, this.environment)) {
+ if (disabledAllBillingFeatures(this, this.environment)) {
if (this.#instanceType === 'development') {
throw new ClerkRuntimeError(warnings.cannotRenderAnyCommerceComponent('PlanDetails'), {
code: CANNOT_RENDER_BILLING_DISABLED_ERROR_CODE,
@@ -1060,7 +1060,7 @@ export class Clerk implements ClerkInterface {
public mountPricingTable = (node: HTMLDivElement, props?: PricingTableProps): void => {
this.assertComponentsReady(this.#componentControls);
- if (disabledBillingFeature(this, this.environment)) {
+ if (disabledAllBillingFeatures(this, this.environment)) {
if (this.#instanceType === 'development') {
throw new ClerkRuntimeError(warnings.cannotRenderAnyCommerceComponent('PricingTable'), {
code: CANNOT_RENDER_BILLING_DISABLED_ERROR_CODE,
diff --git a/packages/clerk-js/src/core/resources/CommerceSettings.ts b/packages/clerk-js/src/core/resources/CommerceSettings.ts
index 104ce856c43..26909c9b756 100644
--- a/packages/clerk-js/src/core/resources/CommerceSettings.ts
+++ b/packages/clerk-js/src/core/resources/CommerceSettings.ts
@@ -11,6 +11,14 @@ export class CommerceSettings extends BaseResource implements CommerceSettingsRe
enabled: false,
hasPaidUserPlans: false,
hasPaidOrgPlans: false,
+ organization: {
+ enabled: false,
+ hasPaidPlans: false,
+ },
+ user: {
+ enabled: false,
+ hasPaidPlans: false,
+ },
};
public constructor(data: CommerceSettingsJSON | CommerceSettingsJSONSnapshot | null = null) {
@@ -27,6 +35,10 @@ export class CommerceSettings extends BaseResource implements CommerceSettingsRe
this.billing.enabled = data.billing.enabled || false;
this.billing.hasPaidUserPlans = data.billing.has_paid_user_plans || false;
this.billing.hasPaidOrgPlans = data.billing.has_paid_org_plans || false;
+ this.billing.organization.enabled = data.billing.organization.enabled || false;
+ this.billing.organization.hasPaidPlans = data.billing.organization.has_paid_plans || false;
+ this.billing.user.enabled = data.billing.user.enabled || false;
+ this.billing.user.hasPaidPlans = data.billing.user.has_paid_plans || false;
return this;
}
@@ -38,6 +50,14 @@ export class CommerceSettings extends BaseResource implements CommerceSettingsRe
enabled: this.billing.enabled,
has_paid_user_plans: this.billing.hasPaidUserPlans,
has_paid_org_plans: this.billing.hasPaidOrgPlans,
+ organization: {
+ enabled: this.billing.organization.enabled,
+ has_paid_plans: this.billing.organization.hasPaidPlans,
+ },
+ user: {
+ enabled: this.billing.user.enabled,
+ has_paid_plans: this.billing.user.hasPaidPlans,
+ },
},
} as unknown as CommerceSettingsJSONSnapshot;
}
diff --git a/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx b/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx
index 863a173afd3..f153a991b93 100644
--- a/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx
+++ b/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx
@@ -83,7 +83,7 @@ export const OrganizationProfileRoutes = () => {
- {commerceSettings.billing.enabled && commerceSettings.billing.hasPaidOrgPlans && (
+ {commerceSettings.billing.organization.enabled ? (
has({ permission: 'org:sys_billing:read' }) || has({ permission: 'org:sys_billing:manage' })
@@ -96,11 +96,13 @@ export const OrganizationProfileRoutes = () => {
-
-
-
-
-
+ {commerceSettings.billing.organization.hasPaidPlans ? (
+
+
+
+
+
+ ) : null}
@@ -114,7 +116,7 @@ export const OrganizationProfileRoutes = () => {
- )}
+ ) : null}
{apiKeysSettings.enabled && (
diff --git a/packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx b/packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
index 9d6dcd6ee33..50210e65bfd 100644
--- a/packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
+++ b/packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
@@ -2,6 +2,7 @@ import { ProfileSection } from '@/ui/elements/Section';
import { useProtect } from '../../common';
import {
+ useEnvironment,
usePlansContext,
useSubscriberTypeContext,
useSubscriberTypeLocalizationRoot,
@@ -44,6 +45,7 @@ export function SubscriptionsList({
has => has({ permission: 'org:sys_billing:manage' }) || subscriberType === 'user',
);
const { navigate } = useRouter();
+ const { commerceSettings } = useEnvironment();
const sortedSubscriptions = subscriptions.sort((a, b) => {
// alway put active subscriptions first
@@ -188,22 +190,25 @@ export function SubscriptionsList({
)}
- 0 ? arrowButtonText : arrowButtonEmptyText}
- sx={[
- t => ({
- justifyContent: 'start',
- height: t.sizes.$8,
- }),
- ]}
- leftIcon={subscriptions.length > 0 ? ArrowsUpDown : Plus}
- leftIconSx={t => ({
- width: t.sizes.$4,
- height: t.sizes.$4,
- })}
- onClick={() => void navigate('plans')}
- />
+ {(commerceSettings.billing.user.hasPaidPlans && subscriberType === 'user') ||
+ (commerceSettings.billing.organization.hasPaidPlans && subscriberType === 'org') ? (
+ 0 ? arrowButtonText : arrowButtonEmptyText}
+ sx={[
+ t => ({
+ justifyContent: 'start',
+ height: t.sizes.$8,
+ }),
+ ]}
+ leftIcon={subscriptions.length > 0 ? ArrowsUpDown : Plus}
+ leftIconSx={t => ({
+ width: t.sizes.$4,
+ height: t.sizes.$4,
+ })}
+ onClick={() => void navigate('plans')}
+ />
+ ) : null}
);
}
diff --git a/packages/clerk-js/src/ui/components/UserProfile/UserProfileRoutes.tsx b/packages/clerk-js/src/ui/components/UserProfile/UserProfileRoutes.tsx
index 8455fb688d1..76151e5b809 100644
--- a/packages/clerk-js/src/ui/components/UserProfile/UserProfileRoutes.tsx
+++ b/packages/clerk-js/src/ui/components/UserProfile/UserProfileRoutes.tsx
@@ -80,7 +80,7 @@ export const UserProfileRoutes = () => {
- {commerceSettings.billing.enabled && commerceSettings.billing.hasPaidUserPlans && (
+ {commerceSettings.billing.user.enabled ? (
@@ -88,11 +88,13 @@ export const UserProfileRoutes = () => {
-
-
-
-
-
+ {commerceSettings.billing.user.hasPaidPlans ? (
+
+
+
+
+
+ ) : null}
@@ -105,7 +107,7 @@ export const UserProfileRoutes = () => {
- )}
+ ) : null}
{apiKeysSettings.enabled && (
diff --git a/packages/clerk-js/src/ui/utils/createCustomPages.tsx b/packages/clerk-js/src/ui/utils/createCustomPages.tsx
index a856048aeb7..ce9a45d0061 100644
--- a/packages/clerk-js/src/ui/utils/createCustomPages.tsx
+++ b/packages/clerk-js/src/ui/utils/createCustomPages.tsx
@@ -3,9 +3,8 @@ import type { CustomPage, EnvironmentResource, LoadedClerk } from '@clerk/types'
import {
canViewOrManageAPIKeys,
disabledAPIKeysFeature,
- disabledBillingFeature,
- hasPaidOrgPlans,
- hasPaidUserPlans,
+ disabledOrganizationBillingFeature,
+ disabledUserBillingFeature,
isValidUrl,
} from '../../utils';
import { ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID, USER_PROFILE_NAVBAR_ROUTE_ID } from '../constants';
@@ -97,9 +96,9 @@ const createCustomPages = (
organization?: boolean,
) => {
const { INITIAL_ROUTES, pageToRootNavbarRouteMap, validReorderItemLabels } = getDefaultRoutes({
- commerce:
- !disabledBillingFeature(clerk, environment) &&
- (organization ? hasPaidOrgPlans(clerk, environment) : hasPaidUserPlans(clerk, environment)),
+ commerce: organization
+ ? !disabledOrganizationBillingFeature(clerk, environment)
+ : !disabledUserBillingFeature(clerk, environment),
apiKeys: !disabledAPIKeysFeature(clerk, environment) && (organization ? canViewOrManageAPIKeys(clerk) : true),
});
diff --git a/packages/clerk-js/src/utils/componentGuards.ts b/packages/clerk-js/src/utils/componentGuards.ts
index 03770b41936..baf23904b17 100644
--- a/packages/clerk-js/src/utils/componentGuards.ts
+++ b/packages/clerk-js/src/utils/componentGuards.ts
@@ -22,16 +22,24 @@ export const disabledOrganizationsFeature: ComponentGuard = (_, environment) =>
return !environment?.organizationSettings.enabled;
};
-export const disabledBillingFeature: ComponentGuard = (_, environment) => {
- return !environment?.commerceSettings.billing.enabled;
+export const disabledUserBillingFeature: ComponentGuard = (_, environment) => {
+ return !environment?.commerceSettings.billing.user.enabled;
+};
+
+export const disabledOrganizationBillingFeature: ComponentGuard = (_, environment) => {
+ return !environment?.commerceSettings.billing.organization.enabled;
+};
+
+export const disabledAllBillingFeatures: ComponentGuard = (_, environment) => {
+ return disabledUserBillingFeature(_, environment) && disabledOrganizationBillingFeature(_, environment);
};
export const hasPaidOrgPlans: ComponentGuard = (_, environment) => {
- return environment?.commerceSettings.billing.hasPaidOrgPlans || false;
+ return environment?.commerceSettings.billing.organization.hasPaidPlans || false;
};
export const hasPaidUserPlans: ComponentGuard = (_, environment) => {
- return environment?.commerceSettings.billing.hasPaidUserPlans || false;
+ return environment?.commerceSettings.billing.user.hasPaidPlans || false;
};
export const disabledAPIKeysFeature: ComponentGuard = (_, environment) => {
diff --git a/packages/types/src/commerceSettings.ts b/packages/types/src/commerceSettings.ts
index 3be9ede7370..d41bf633ff9 100644
--- a/packages/types/src/commerceSettings.ts
+++ b/packages/types/src/commerceSettings.ts
@@ -9,6 +9,14 @@ export interface CommerceSettingsJSON extends ClerkResourceJSON {
stripe_publishable_key: string;
has_paid_user_plans: boolean;
has_paid_org_plans: boolean;
+ organization: {
+ enabled: boolean;
+ has_paid_plans: boolean;
+ };
+ user: {
+ enabled: boolean;
+ has_paid_plans: boolean;
+ };
};
}
@@ -18,6 +26,14 @@ export interface CommerceSettingsResource extends ClerkResource {
stripePublishableKey: string;
hasPaidUserPlans: boolean;
hasPaidOrgPlans: boolean;
+ organization: {
+ enabled: boolean;
+ hasPaidPlans: boolean;
+ };
+ user: {
+ enabled: boolean;
+ hasPaidPlans: boolean;
+ };
};
__internal_toSnapshot: () => CommerceSettingsJSONSnapshot;