Skip to content

Commit 9ade3ae

Browse files
committed
Replace throwing error with opening modal
1 parent ca6f89c commit 9ade3ae

File tree

16 files changed

+319
-213
lines changed

16 files changed

+319
-213
lines changed

packages/clerk-js/src/core/clerk.ts

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import type {
2323
__experimental_CheckoutInstance,
2424
__experimental_CheckoutOptions,
2525
__internal_CheckoutProps,
26-
__internal_EnableOrganizationsModalProps,
26+
__internal_EnableOrganizationsPromptProps,
2727
__internal_OAuthConsentProps,
2828
__internal_PlanDetailsProps,
2929
__internal_SubscriptionDetailsProps,
@@ -175,7 +175,6 @@ declare global {
175175

176176
const CANNOT_RENDER_BILLING_DISABLED_ERROR_CODE = 'cannot_render_billing_disabled';
177177
const CANNOT_RENDER_USER_MISSING_ERROR_CODE = 'cannot_render_user_missing';
178-
const CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE = 'cannot_render_organizations_disabled';
179178
const CANNOT_RENDER_ORGANIZATION_MISSING_ERROR_CODE = 'cannot_render_organization_missing';
180179
const CANNOT_RENDER_SINGLE_SESSION_ENABLED_ERROR_CODE = 'cannot_render_single_session_enabled';
181180
const CANNOT_RENDER_API_KEYS_DISABLED_ERROR_CODE = 'cannot_render_api_keys_disabled';
@@ -716,16 +715,16 @@ export class Clerk implements ClerkInterface {
716715
void this.#componentControls.ensureMounted().then(controls => controls.closeModal('userVerification'));
717716
};
718717

719-
public __internal_openEnableOrganizations = (props?: __internal_EnableOrganizationsModalProps): void => {
718+
public __internal_openEnableOrganizationsPrompt = (props?: __internal_EnableOrganizationsPromptProps): void => {
720719
this.assertComponentsReady(this.#componentControls);
721720
void this.#componentControls
722-
.ensureMounted({ preloadHint: 'EnableOrganizations' })
723-
.then(controls => controls.openModal('enableOrganizations', props || {}));
721+
.ensureMounted({ preloadHint: 'EnableOrganizationsPrompt' })
722+
.then(controls => controls.openModal('enableOrganizationsPrompt', props || {}));
724723
};
725724

726725
public __internal_closeEnableOrganizations = (): void => {
727726
this.assertComponentsReady(this.#componentControls);
728-
void this.#componentControls.ensureMounted().then(controls => controls.closeModal('enableOrganizations'));
727+
void this.#componentControls.ensureMounted().then(controls => controls.closeModal('enableOrganizationsPrompt'));
729728
};
730729

731730
public __internal_openBlankCaptchaModal = (): Promise<unknown> => {
@@ -801,8 +800,8 @@ export class Clerk implements ClerkInterface {
801800
this.assertComponentsReady(this.#componentControls);
802801
if (disabledOrganizationsFeature(this, this.environment)) {
803802
if (this.#instanceType === 'development') {
804-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('OrganizationProfile'), {
805-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
803+
this.__internal_openEnableOrganizationsPrompt({
804+
callerName: 'OrganizationSwitcher',
806805
});
807806
}
808807
return;
@@ -831,8 +830,8 @@ export class Clerk implements ClerkInterface {
831830
this.assertComponentsReady(this.#componentControls);
832831
if (disabledOrganizationsFeature(this, this.environment)) {
833832
if (this.#instanceType === 'development') {
834-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('CreateOrganization'), {
835-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
833+
this.__internal_openEnableOrganizationsPrompt({
834+
callerName: 'OrganizationSwitcher',
836835
});
837836
}
838837
return;
@@ -973,8 +972,8 @@ export class Clerk implements ClerkInterface {
973972
this.assertComponentsReady(this.#componentControls);
974973
if (disabledOrganizationsFeature(this, this.environment)) {
975974
if (this.#instanceType === 'development') {
976-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('OrganizationProfile'), {
977-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
975+
this.__internal_openEnableOrganizationsPrompt({
976+
callerName: 'OrganizationProfile',
978977
});
979978
}
980979
return;
@@ -1013,8 +1012,8 @@ export class Clerk implements ClerkInterface {
10131012
this.assertComponentsReady(this.#componentControls);
10141013
if (disabledOrganizationsFeature(this, this.environment)) {
10151014
if (this.#instanceType === 'development') {
1016-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('CreateOrganization'), {
1017-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
1015+
this.__internal_openEnableOrganizationsPrompt({
1016+
callerName: 'OrganizationSwitcher',
10181017
});
10191018
}
10201019
return;
@@ -1044,8 +1043,8 @@ export class Clerk implements ClerkInterface {
10441043
this.assertComponentsReady(this.#componentControls);
10451044
if (disabledOrganizationsFeature(this, this.environment)) {
10461045
if (this.#instanceType === 'development') {
1047-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('OrganizationSwitcher'), {
1048-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
1046+
this.__internal_openEnableOrganizationsPrompt({
1047+
callerName: 'OrganizationSwitcher',
10491048
});
10501049
}
10511050
return;
@@ -1083,8 +1082,8 @@ export class Clerk implements ClerkInterface {
10831082
this.assertComponentsReady(this.#componentControls);
10841083
if (disabledOrganizationsFeature(this, this.environment)) {
10851084
if (this.#instanceType === 'development') {
1086-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('OrganizationList'), {
1087-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
1085+
this.__internal_openEnableOrganizationsPrompt({
1086+
callerName: 'OrganizationList',
10881087
});
10891088
}
10901089
return;
@@ -1270,8 +1269,8 @@ export class Clerk implements ClerkInterface {
12701269

12711270
if (disabledOrganizationsFeature(this, this.environment)) {
12721271
if (this.#instanceType === 'development') {
1273-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('TaskChooseOrganization'), {
1274-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
1272+
this.__internal_openEnableOrganizationsPrompt({
1273+
callerName: 'OrganizationSwitcher',
12751274
});
12761275
}
12771276
return;

packages/clerk-js/src/core/warnings.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,6 @@ const formatWarning = (msg: string) => {
44
return `🔒 Clerk:\n${msg.trim()}\n(This notice only appears in development)`;
55
};
66

7-
const createMessageForDisabledOrganizations = (
8-
componentName:
9-
| 'OrganizationProfile'
10-
| 'OrganizationSwitcher'
11-
| 'OrganizationList'
12-
| 'CreateOrganization'
13-
| 'TaskChooseOrganization',
14-
) => {
15-
return formatWarning(
16-
`The <${componentName}/> cannot be rendered when the feature is turned off. Visit 'dashboard.clerk.com' to enable the feature. Since the feature is turned off, this is no-op.`,
17-
);
18-
};
197
const createMessageForDisabledBilling = (componentName: 'PricingTable' | 'Checkout' | 'PlanDetails') => {
208
return formatWarning(
219
`The <${componentName}/> component cannot be rendered when billing is disabled. Visit 'https://dashboard.clerk.com/last-active?path=billing/settings' to follow the necessary steps to enable billing. Since billing is disabled, this is no-op.`,
@@ -37,7 +25,6 @@ const warnings = {
3725
cannotRenderComponentWhenUserDoesNotExist:
3826
'<UserProfile/> cannot render unless a user is signed in. Since no user is signed in, this is no-op.',
3927
cannotRenderComponentWhenOrgDoesNotExist: `<OrganizationProfile/> cannot render unless an organization is active. Since no organization is currently active, this is no-op.`,
40-
cannotRenderAnyOrganizationComponent: createMessageForDisabledOrganizations,
4128
cannotRenderAnyBillingComponent: createMessageForDisabledBilling,
4229
cannotOpenUserProfile:
4330
'The UserProfile modal cannot render unless a user is signed in. Since no user is signed in, this is no-op.',

packages/clerk-js/src/ui/Components.tsx

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {
22
__internal_CheckoutProps,
3-
__internal_EnableOrganizationsProps,
3+
__internal_EnableOrganizationsPromptProps,
44
__internal_PlanDetailsProps,
55
__internal_SubscriptionDetailsProps,
66
__internal_UserVerificationProps,
@@ -28,7 +28,7 @@ import type { ClerkComponentName } from './lazyModules/components';
2828
import {
2929
BlankCaptchaModal,
3030
CreateOrganizationModal,
31-
EnableOrganizationsModal,
31+
EnableOrganizationsPrompt,
3232
ImpersonationFab,
3333
KeylessPrompt,
3434
OrganizationProfileModal,
@@ -82,7 +82,7 @@ export type ComponentControls = {
8282
| 'userVerification'
8383
| 'waitlist'
8484
| 'blankCaptcha'
85-
| 'enableOrganizations',
85+
| 'enableOrganizationsPrompt',
8686
>(
8787
modal: T,
8888
props: T extends 'signIn'
@@ -93,8 +93,8 @@ export type ComponentControls = {
9393
? __internal_UserVerificationProps
9494
: T extends 'waitlist'
9595
? WaitlistProps
96-
: T extends 'enableOrganizations'
97-
? __internal_EnableOrganizationsProps
96+
: T extends 'enableOrganizationsPrompt'
97+
? __internal_EnableOrganizationsPromptProps
9898
: UserProfileProps,
9999
) => void;
100100
closeModal: (
@@ -108,7 +108,7 @@ export type ComponentControls = {
108108
| 'userVerification'
109109
| 'waitlist'
110110
| 'blankCaptcha'
111-
| 'enableOrganizations',
111+
| 'enableOrganizationsPrompt',
112112
options?: {
113113
notify?: boolean;
114114
},
@@ -158,7 +158,7 @@ interface ComponentsState {
158158
userVerificationModal: null | __internal_UserVerificationProps;
159159
organizationProfileModal: null | OrganizationProfileProps;
160160
createOrganizationModal: null | CreateOrganizationProps;
161-
enableOrganizationsModal: null | __internal_EnableOrganizationsProps;
161+
enableOrganizationsPromptModal: null | __internal_EnableOrganizationsPromptProps;
162162
blankCaptchaModal: null;
163163
organizationSwitcherPrefetch: boolean;
164164
waitlistModal: null | WaitlistProps;
@@ -252,7 +252,7 @@ const Components = (props: ComponentsProps) => {
252252
userVerificationModal: null,
253253
organizationProfileModal: null,
254254
createOrganizationModal: null,
255-
enableOrganizationsModal: null,
255+
enableOrganizationsPromptModal: null,
256256
organizationSwitcherPrefetch: false,
257257
waitlistModal: null,
258258
blankCaptchaModal: null,
@@ -282,7 +282,6 @@ const Components = (props: ComponentsProps) => {
282282
createOrganizationModal,
283283
waitlistModal,
284284
blankCaptchaModal,
285-
enableOrganizationsModal,
286285
checkoutDrawer,
287286
planDetailsDrawer,
288287
subscriptionDetailsDrawer,
@@ -352,6 +351,18 @@ const Components = (props: ComponentsProps) => {
352351
};
353352

354353
componentsControls.openModal = (name, props) => {
354+
// Prevent opening enableOrganizations modal if it's already open
355+
// to avoid duplicate mounting when component is called multiple times
356+
if (name === 'enableOrganizationsPrompt') {
357+
setState(s => {
358+
if (s.enableOrganizationsPromptModal) {
359+
return s; // Modal is already open, don't update state
360+
}
361+
return { ...s, [`${name}Modal`]: props };
362+
});
363+
return;
364+
}
365+
355366
function handleCloseModalForExperimentalUserVerification() {
356367
if (!('afterVerificationCancelled' in props)) {
357368
return;
@@ -494,22 +505,6 @@ const Components = (props: ComponentsProps) => {
494505
</LazyModalRenderer>
495506
);
496507

497-
const mountedEnableOrganizationsModal = (
498-
<LazyModalRenderer
499-
globalAppearance={state.appearance}
500-
appearanceKey={'enableOrganizations'}
501-
componentAppearance={enableOrganizationsModal?.appearance}
502-
flowName={'enableOrganizations'}
503-
onClose={() => componentsControls.closeModal('enableOrganizations')}
504-
onExternalNavigate={() => componentsControls.closeModal('enableOrganizations')}
505-
startPath={buildVirtualRouterUrl({ base: '/enable-organizations', path: urlStateParam?.path })}
506-
componentName={'EnableOrganizationsModal'}
507-
modalContainerSx={{ alignItems: 'center' }}
508-
>
509-
<EnableOrganizationsModal {...enableOrganizationsModal} />
510-
</LazyModalRenderer>
511-
);
512-
513508
const mountedOrganizationProfileModal = (
514509
<LazyModalRenderer
515510
globalAppearance={state.appearance}
@@ -613,7 +608,6 @@ const Components = (props: ComponentsProps) => {
613608
{createOrganizationModal && mountedCreateOrganizationModal}
614609
{waitlistModal && mountedWaitlistModal}
615610
{blankCaptchaModal && mountedBlankCaptchaModal}
616-
{enableOrganizationsModal && mountedEnableOrganizationsModal}
617611

618612
<MountedCheckoutDrawer
619613
appearance={state.appearance}
@@ -639,6 +633,15 @@ const Components = (props: ComponentsProps) => {
639633
</LazyImpersonationFabProvider>
640634
)}
641635

636+
{state.enableOrganizationsPromptModal && (
637+
<LazyImpersonationFabProvider globalAppearance={state.appearance}>
638+
<EnableOrganizationsPrompt
639+
callerString='useOrganization'
640+
{...state.enableOrganizationsPromptModal}
641+
/>
642+
</LazyImpersonationFabProvider>
643+
)}
644+
642645
{state.options?.__internal_keyless_claimKeylessApplicationUrl &&
643646
state.options?.__internal_keyless_copyInstanceKeysUrl && (
644647
<LazyImpersonationFabProvider globalAppearance={state.appearance}>

packages/clerk-js/src/ui/components/EnableOrganizations/index.tsx

Lines changed: 0 additions & 63 deletions
This file was deleted.

0 commit comments

Comments
 (0)