@@ -22,6 +22,7 @@ import {
2222import type {
2323 __experimental_CheckoutInstance ,
2424 __experimental_CheckoutOptions ,
25+ __internal_AttemptToEnableEnvironmentSettingParams ,
2526 __internal_CheckoutProps ,
2627 __internal_EnableOrganizationsPromptProps ,
2728 __internal_OAuthConsentProps ,
@@ -98,6 +99,7 @@ import { allSettled, handleValueOrFn, noop } from '@clerk/shared/utils';
9899import type { QueryClient } from '@tanstack/query-core' ;
99100
100101import { debugLogger , initDebugLogger } from '@/utils/debug' ;
102+ import { CLERK_ENVIRONMENT_SETTING_PROMPT_REJECTED_KEY , SafeSessionStorage } from '@/utils/sessionStorage' ;
101103
102104import type { MountComponentRenderer } from '../ui/Components' ;
103105import {
@@ -176,6 +178,7 @@ declare global {
176178
177179const CANNOT_RENDER_BILLING_DISABLED_ERROR_CODE = 'cannot_render_billing_disabled' ;
178180const CANNOT_RENDER_USER_MISSING_ERROR_CODE = 'cannot_render_user_missing' ;
181+ const CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE = 'cannot_render_organizations_disabled' ;
179182const CANNOT_RENDER_ORGANIZATION_MISSING_ERROR_CODE = 'cannot_render_organization_missing' ;
180183const CANNOT_RENDER_SINGLE_SESSION_ENABLED_ERROR_CODE = 'cannot_render_single_session_enabled' ;
181184const CANNOT_RENDER_API_KEYS_DISABLED_ERROR_CODE = 'cannot_render_api_keys_disabled' ;
@@ -739,6 +742,42 @@ export class Clerk implements ClerkInterface {
739742 void this . #componentControls. ensureMounted ( ) . then ( controls => controls . closeModal ( 'userVerification' ) ) ;
740743 } ;
741744
745+ public __internal_attemptToEnableEnvironmentSetting = (
746+ params : __internal_AttemptToEnableEnvironmentSettingParams ,
747+ ) : { status : 'enabled' | 'prompt-shown' | 'rejected' } => {
748+ const { for : setting , caller, onSuccess } = params ;
749+
750+ // If not in development instance, return enabled status in order to not open the in-app prompt
751+ if ( this . #instanceType !== 'development' ) {
752+ return { status : 'enabled' } ;
753+ }
754+
755+ const rejectedCallers = SafeSessionStorage . getItem < string [ ] > ( CLERK_ENVIRONMENT_SETTING_PROMPT_REJECTED_KEY , [ ] ) ;
756+
757+ switch ( setting ) {
758+ case 'organizations' :
759+ if ( ! disabledOrganizationsFeature ( this , this . environment ) ) {
760+ return { status : 'enabled' } ;
761+ }
762+
763+ if ( rejectedCallers . includes ( caller ) ) {
764+ return { status : 'rejected' } ;
765+ }
766+
767+ this . __internal_openEnableOrganizationsPrompt ( {
768+ caller,
769+ onSuccess : ( ) => window . location . reload ( ) ,
770+ onClose : ( ) => {
771+ SafeSessionStorage . setItem ( CLERK_ENVIRONMENT_SETTING_PROMPT_REJECTED_KEY , [ caller ] ) ;
772+ } ,
773+ } as __internal_EnableOrganizationsPromptProps ) ;
774+
775+ return { status : 'prompt-shown' } ;
776+ default :
777+ return { status : 'enabled' } ;
778+ }
779+ } ;
780+
742781 public __internal_openEnableOrganizationsPrompt = ( props : __internal_EnableOrganizationsPromptProps ) : void => {
743782 this . assertComponentsReady ( this . #componentControls) ;
744783 void this . #componentControls
@@ -822,17 +861,25 @@ export class Clerk implements ClerkInterface {
822861
823862 public openOrganizationProfile = ( props ?: OrganizationProfileProps ) : void => {
824863 this . assertComponentsReady ( this . #componentControls) ;
825- if ( disabledOrganizationsFeature ( this , this . environment ) ) {
826- if ( this . #instanceType === 'development' ) {
827- this . __internal_openEnableOrganizationsPrompt ( {
828- componentName : 'OrganizationProfile' ,
829- onComplete : ( ) => {
830- this . openOrganizationProfile ( ) ;
831- } ,
832- } ) ;
833- }
864+
865+ const { status } = this . __internal_attemptToEnableEnvironmentSetting ( {
866+ for : 'organizations' ,
867+ caller : 'OrganizationProfile' ,
868+ onSuccess : ( ) => {
869+ this . openOrganizationProfile ( props ) ;
870+ } ,
871+ } ) ;
872+
873+ if ( status === 'rejected' ) {
874+ throw new ClerkRuntimeError ( warnings . cannotRenderAnyOrganizationComponent ( 'OrganizationProfile' ) , {
875+ code : CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE ,
876+ } ) ;
877+ }
878+
879+ if ( status === 'prompt-shown' ) {
834880 return ;
835881 }
882+
836883 if ( noOrganizationExists ( this ) ) {
837884 if ( this . #instanceType === 'development' ) {
838885 throw new ClerkRuntimeError ( warnings . cannotRenderComponentWhenOrgDoesNotExist , {
@@ -855,17 +902,25 @@ export class Clerk implements ClerkInterface {
855902
856903 public openCreateOrganization = ( props ?: CreateOrganizationProps ) : void => {
857904 this . assertComponentsReady ( this . #componentControls) ;
858- if ( disabledOrganizationsFeature ( this , this . environment ) ) {
859- if ( this . #instanceType === 'development' ) {
860- this . __internal_openEnableOrganizationsPrompt ( {
861- componentName : 'OrganizationSwitcher' ,
862- onComplete : ( ) => {
863- this . openCreateOrganization ( ) ;
864- } ,
865- } ) ;
866- }
905+
906+ const { status } = this . __internal_attemptToEnableEnvironmentSetting ( {
907+ for : 'organizations' ,
908+ caller : 'CreateOrganization' ,
909+ onSuccess : ( ) => {
910+ this . openCreateOrganization ( props ) ;
911+ } ,
912+ } ) ;
913+
914+ if ( status === 'rejected' ) {
915+ throw new ClerkRuntimeError ( warnings . cannotRenderAnyOrganizationComponent ( 'CreateOrganization' ) , {
916+ code : CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE ,
917+ } ) ;
918+ }
919+
920+ if ( status === 'prompt-shown' ) {
867921 return ;
868922 }
923+
869924 void this . #componentControls
870925 . ensureMounted ( { preloadHint : 'CreateOrganization' } )
871926 . then ( controls => controls . openModal ( 'createOrganization' , props || { } ) ) ;
@@ -1000,17 +1055,25 @@ export class Clerk implements ClerkInterface {
10001055
10011056 public mountOrganizationProfile = ( node : HTMLDivElement , props ?: OrganizationProfileProps ) => {
10021057 this . assertComponentsReady ( this . #componentControls) ;
1003- if ( disabledOrganizationsFeature ( this , this . environment ) ) {
1004- if ( this . #instanceType === 'development' ) {
1005- this . __internal_openEnableOrganizationsPrompt ( {
1006- componentName : 'OrganizationProfile' ,
1007- onComplete : ( ) => {
1008- this . mountOrganizationProfile ( node , props ) ;
1009- } ,
1010- } ) ;
1011- }
1058+
1059+ const { status } = this . __internal_attemptToEnableEnvironmentSetting ( {
1060+ for : 'organizations' ,
1061+ caller : 'OrganizationProfile' ,
1062+ onSuccess : ( ) => {
1063+ this . mountOrganizationProfile ( node , props ) ;
1064+ } ,
1065+ } ) ;
1066+
1067+ if ( status === 'rejected' ) {
1068+ throw new ClerkRuntimeError ( warnings . cannotRenderAnyOrganizationComponent ( 'OrganizationProfile' ) , {
1069+ code : CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE ,
1070+ } ) ;
1071+ }
1072+
1073+ if ( status === 'prompt-shown' ) {
10121074 return ;
10131075 }
1076+
10141077 const userExists = ! noUserExists ( this ) ;
10151078 if ( noOrganizationExists ( this ) && userExists ) {
10161079 if ( this . #instanceType === 'development' ) {
@@ -1043,17 +1106,25 @@ export class Clerk implements ClerkInterface {
10431106
10441107 public mountCreateOrganization = ( node : HTMLDivElement , props ?: CreateOrganizationProps ) => {
10451108 this . assertComponentsReady ( this . #componentControls) ;
1046- if ( disabledOrganizationsFeature ( this , this . environment ) ) {
1047- if ( this . #instanceType === 'development' ) {
1048- this . __internal_openEnableOrganizationsPrompt ( {
1049- componentName : 'OrganizationSwitcher' ,
1050- onComplete : ( ) => {
1051- this . mountCreateOrganization ( ) ;
1052- } ,
1053- } ) ;
1054- }
1109+
1110+ const { status } = this . __internal_attemptToEnableEnvironmentSetting ( {
1111+ for : 'organizations' ,
1112+ caller : 'CreateOrganization' ,
1113+ onSuccess : ( ) => {
1114+ this . mountCreateOrganization ( node , props ) ;
1115+ } ,
1116+ } ) ;
1117+
1118+ if ( status === 'rejected' ) {
1119+ throw new ClerkRuntimeError ( warnings . cannotRenderAnyOrganizationComponent ( 'CreateOrganization' ) , {
1120+ code : CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE ,
1121+ } ) ;
1122+ }
1123+
1124+ if ( status === 'prompt-shown' ) {
10551125 return ;
10561126 }
1127+
10571128 void this . #componentControls?. ensureMounted ( { preloadHint : 'CreateOrganization' } ) . then ( controls =>
10581129 controls . mountComponent ( {
10591130 name : 'CreateOrganization' ,
@@ -1077,17 +1148,25 @@ export class Clerk implements ClerkInterface {
10771148
10781149 public mountOrganizationSwitcher = ( node : HTMLDivElement , props ?: OrganizationSwitcherProps ) => {
10791150 this . assertComponentsReady ( this . #componentControls) ;
1080- if ( disabledOrganizationsFeature ( this , this . environment ) ) {
1081- if ( this . #instanceType === 'development' ) {
1082- this . __internal_openEnableOrganizationsPrompt ( {
1083- componentName : 'OrganizationSwitcher' ,
1084- onComplete : ( ) => {
1085- this . mountOrganizationSwitcher ( node , props ) ;
1086- } ,
1087- } ) ;
1088- }
1151+
1152+ const { status } = this . __internal_attemptToEnableEnvironmentSetting ( {
1153+ for : 'organizations' ,
1154+ caller : 'OrganizationSwitcher' ,
1155+ onSuccess : ( ) => {
1156+ this . mountOrganizationSwitcher ( node , props ) ;
1157+ } ,
1158+ } ) ;
1159+
1160+ if ( status === 'rejected' ) {
1161+ throw new ClerkRuntimeError ( warnings . cannotRenderAnyOrganizationComponent ( 'OrganizationSwitcher' ) , {
1162+ code : CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE ,
1163+ } ) ;
1164+ }
1165+
1166+ if ( status === 'prompt-shown' ) {
10891167 return ;
10901168 }
1169+
10911170 void this . #componentControls?. ensureMounted ( { preloadHint : 'OrganizationSwitcher' } ) . then ( controls =>
10921171 controls . mountComponent ( {
10931172 name : 'OrganizationSwitcher' ,
@@ -1119,17 +1198,25 @@ export class Clerk implements ClerkInterface {
11191198
11201199 public mountOrganizationList = ( node : HTMLDivElement , props ?: OrganizationListProps ) => {
11211200 this . assertComponentsReady ( this . #componentControls) ;
1122- if ( disabledOrganizationsFeature ( this , this . environment ) ) {
1123- if ( this . #instanceType === 'development' ) {
1124- this . __internal_openEnableOrganizationsPrompt ( {
1125- componentName : 'OrganizationList' ,
1126- onComplete : ( ) => {
1127- this . mountOrganizationList ( node , props ) ;
1128- } ,
1129- } ) ;
1130- }
1201+
1202+ const { status } = this . __internal_attemptToEnableEnvironmentSetting ( {
1203+ for : 'organizations' ,
1204+ caller : 'OrganizationList' ,
1205+ onSuccess : ( ) => {
1206+ this . mountOrganizationList ( node , props ) ;
1207+ } ,
1208+ } ) ;
1209+
1210+ if ( status === 'rejected' ) {
1211+ throw new ClerkRuntimeError ( warnings . cannotRenderAnyOrganizationComponent ( 'OrganizationList' ) , {
1212+ code : CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE ,
1213+ } ) ;
1214+ }
1215+
1216+ if ( status === 'prompt-shown' ) {
11311217 return ;
11321218 }
1219+
11331220 void this . #componentControls?. ensureMounted ( { preloadHint : 'OrganizationList' } ) . then ( controls =>
11341221 controls . mountComponent ( {
11351222 name : 'OrganizationList' ,
@@ -1309,15 +1396,21 @@ export class Clerk implements ClerkInterface {
13091396 public mountTaskChooseOrganization = ( node : HTMLDivElement , props ?: TaskChooseOrganizationProps ) => {
13101397 this . assertComponentsReady ( this . #componentControls) ;
13111398
1312- if ( disabledOrganizationsFeature ( this , this . environment ) ) {
1313- if ( this . #instanceType === 'development' ) {
1314- this . __internal_openEnableOrganizationsPrompt ( {
1315- componentName : 'OrganizationSwitcher' ,
1316- onComplete : ( ) => {
1317- this . mountTaskChooseOrganization ( node , props ) ;
1318- } ,
1319- } ) ;
1320- }
1399+ const { status } = this . __internal_attemptToEnableEnvironmentSetting ( {
1400+ for : 'organizations' ,
1401+ caller : 'TaskChooseOrganization' ,
1402+ onSuccess : ( ) => {
1403+ this . mountTaskChooseOrganization ( node , props ) ;
1404+ } ,
1405+ } ) ;
1406+
1407+ if ( status === 'rejected' ) {
1408+ throw new ClerkRuntimeError ( warnings . cannotRenderAnyOrganizationComponent ( 'TaskChooseOrganization' ) , {
1409+ code : CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE ,
1410+ } ) ;
1411+ }
1412+
1413+ if ( status === 'prompt-shown' ) {
13211414 return ;
13221415 }
13231416
0 commit comments