Skip to content

Commit b46b37d

Browse files
committed
Replace throwing error with opening modal
1 parent 3a320a6 commit b46b37d

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,
@@ -176,7 +176,6 @@ declare global {
176176

177177
const CANNOT_RENDER_BILLING_DISABLED_ERROR_CODE = 'cannot_render_billing_disabled';
178178
const CANNOT_RENDER_USER_MISSING_ERROR_CODE = 'cannot_render_user_missing';
179-
const CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE = 'cannot_render_organizations_disabled';
180179
const CANNOT_RENDER_ORGANIZATION_MISSING_ERROR_CODE = 'cannot_render_organization_missing';
181180
const CANNOT_RENDER_SINGLE_SESSION_ENABLED_ERROR_CODE = 'cannot_render_single_session_enabled';
182181
const CANNOT_RENDER_API_KEYS_DISABLED_ERROR_CODE = 'cannot_render_api_keys_disabled';
@@ -740,16 +739,16 @@ export class Clerk implements ClerkInterface {
740739
void this.#componentControls.ensureMounted().then(controls => controls.closeModal('userVerification'));
741740
};
742741

743-
public __internal_openEnableOrganizations = (props?: __internal_EnableOrganizationsModalProps): void => {
742+
public __internal_openEnableOrganizationsPrompt = (props?: __internal_EnableOrganizationsPromptProps): void => {
744743
this.assertComponentsReady(this.#componentControls);
745744
void this.#componentControls
746-
.ensureMounted({ preloadHint: 'EnableOrganizations' })
747-
.then(controls => controls.openModal('enableOrganizations', props || {}));
745+
.ensureMounted({ preloadHint: 'EnableOrganizationsPrompt' })
746+
.then(controls => controls.openModal('enableOrganizationsPrompt', props || {}));
748747
};
749748

750749
public __internal_closeEnableOrganizations = (): void => {
751750
this.assertComponentsReady(this.#componentControls);
752-
void this.#componentControls.ensureMounted().then(controls => controls.closeModal('enableOrganizations'));
751+
void this.#componentControls.ensureMounted().then(controls => controls.closeModal('enableOrganizationsPrompt'));
753752
};
754753

755754
public __internal_openBlankCaptchaModal = (): Promise<unknown> => {
@@ -825,8 +824,8 @@ export class Clerk implements ClerkInterface {
825824
this.assertComponentsReady(this.#componentControls);
826825
if (disabledOrganizationsFeature(this, this.environment)) {
827826
if (this.#instanceType === 'development') {
828-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('OrganizationProfile'), {
829-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
827+
this.__internal_openEnableOrganizationsPrompt({
828+
callerName: 'OrganizationSwitcher',
830829
});
831830
}
832831
return;
@@ -855,8 +854,8 @@ export class Clerk implements ClerkInterface {
855854
this.assertComponentsReady(this.#componentControls);
856855
if (disabledOrganizationsFeature(this, this.environment)) {
857856
if (this.#instanceType === 'development') {
858-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('CreateOrganization'), {
859-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
857+
this.__internal_openEnableOrganizationsPrompt({
858+
callerName: 'OrganizationSwitcher',
860859
});
861860
}
862861
return;
@@ -997,8 +996,8 @@ export class Clerk implements ClerkInterface {
997996
this.assertComponentsReady(this.#componentControls);
998997
if (disabledOrganizationsFeature(this, this.environment)) {
999998
if (this.#instanceType === 'development') {
1000-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('OrganizationProfile'), {
1001-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
999+
this.__internal_openEnableOrganizationsPrompt({
1000+
callerName: 'OrganizationProfile',
10021001
});
10031002
}
10041003
return;
@@ -1037,8 +1036,8 @@ export class Clerk implements ClerkInterface {
10371036
this.assertComponentsReady(this.#componentControls);
10381037
if (disabledOrganizationsFeature(this, this.environment)) {
10391038
if (this.#instanceType === 'development') {
1040-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('CreateOrganization'), {
1041-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
1039+
this.__internal_openEnableOrganizationsPrompt({
1040+
callerName: 'OrganizationSwitcher',
10421041
});
10431042
}
10441043
return;
@@ -1068,8 +1067,8 @@ export class Clerk implements ClerkInterface {
10681067
this.assertComponentsReady(this.#componentControls);
10691068
if (disabledOrganizationsFeature(this, this.environment)) {
10701069
if (this.#instanceType === 'development') {
1071-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('OrganizationSwitcher'), {
1072-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
1070+
this.__internal_openEnableOrganizationsPrompt({
1071+
callerName: 'OrganizationSwitcher',
10731072
});
10741073
}
10751074
return;
@@ -1107,8 +1106,8 @@ export class Clerk implements ClerkInterface {
11071106
this.assertComponentsReady(this.#componentControls);
11081107
if (disabledOrganizationsFeature(this, this.environment)) {
11091108
if (this.#instanceType === 'development') {
1110-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('OrganizationList'), {
1111-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
1109+
this.__internal_openEnableOrganizationsPrompt({
1110+
callerName: 'OrganizationList',
11121111
});
11131112
}
11141113
return;
@@ -1294,8 +1293,8 @@ export class Clerk implements ClerkInterface {
12941293

12951294
if (disabledOrganizationsFeature(this, this.environment)) {
12961295
if (this.#instanceType === 'development') {
1297-
throw new ClerkRuntimeError(warnings.cannotRenderAnyOrganizationComponent('TaskChooseOrganization'), {
1298-
code: CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE,
1296+
this.__internal_openEnableOrganizationsPrompt({
1297+
callerName: 'OrganizationSwitcher',
12991298
});
13001299
}
13011300
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)