diff --git a/.changeset/fifty-eels-work.md b/.changeset/fifty-eels-work.md new file mode 100644 index 0000000000..813aa78bab --- /dev/null +++ b/.changeset/fifty-eels-work.md @@ -0,0 +1,6 @@ +--- +'@clerk/clerk-js': minor +'@clerk/types': minor +--- + +If user does not have permission to create an org, create org button will not display in the OrganizationSwitcher UI diff --git a/packages/clerk-js/src/core/resources/User.ts b/packages/clerk-js/src/core/resources/User.ts index b0d7754dbd..f0cb69f87a 100644 --- a/packages/clerk-js/src/core/resources/User.ts +++ b/packages/clerk-js/src/core/resources/User.ts @@ -80,6 +80,7 @@ export class User extends BaseResource implements UserResource { publicMetadata: UserPublicMetadata = {}; unsafeMetadata: UserUnsafeMetadata = {}; lastSignInAt: Date | null = null; + createOrganizationEnabled = false; deleteSelfEnabled = false; updatedAt: Date | null = null; createdAt: Date | null = null; @@ -320,6 +321,7 @@ export class User extends BaseResource implements UserResource { this.backupCodeEnabled = data.backup_code_enabled; this.twoFactorEnabled = data.two_factor_enabled; + this.createOrganizationEnabled = data.create_organization_enabled; this.deleteSelfEnabled = data.delete_self_enabled; if (data.last_sign_in_at) { diff --git a/packages/clerk-js/src/core/resources/UserSettings.ts b/packages/clerk-js/src/core/resources/UserSettings.ts index 49d9e86d3b..82ec8eb6bc 100644 --- a/packages/clerk-js/src/core/resources/UserSettings.ts +++ b/packages/clerk-js/src/core/resources/UserSettings.ts @@ -1,6 +1,5 @@ import type { Attributes, - Actions, OAuthProviders, OAuthStrategy, PasswordSettingsData, @@ -17,6 +16,11 @@ import { BaseResource } from './internal'; const defaultMaxPasswordLength = 72; const defaultMinPasswordLength = 8; +export type Actions = { + create_organization: boolean; + delete_self: boolean; +}; + /** * @internal */ diff --git a/packages/clerk-js/src/ui/components/OrganizationSwitcher/OtherOrganizationActions.tsx b/packages/clerk-js/src/ui/components/OrganizationSwitcher/OtherOrganizationActions.tsx index 28a6a16f85..a37a18f664 100644 --- a/packages/clerk-js/src/ui/components/OrganizationSwitcher/OtherOrganizationActions.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationSwitcher/OtherOrganizationActions.tsx @@ -84,7 +84,7 @@ export const OrganizationActionList = (props: OrganizationActionListProps) => { ))} - {createOrganizationButton} + {user.createOrganizationEnabled && createOrganizationButton} ); }; diff --git a/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx b/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx index 915375fad2..7deeaf8934 100644 --- a/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx @@ -46,7 +46,7 @@ describe('OrganizationSwitcher', () => { it('opens the organization switcher popover when clicked', async () => { const { wrapper, props } = await createFixtures(f => { f.withOrganizations(); - f.withUser({ email_addresses: ['test@clerk.dev'] }); + f.withUser({ email_addresses: ['test@clerk.dev'], create_organization_enabled: true }); }); props.setProps({ hidePersonal: true }); const { getByText, getByRole, userEvent } = render(, { wrapper }); @@ -107,6 +107,7 @@ describe('OrganizationSwitcher', () => { f.withUser({ email_addresses: ['test@clerk.dev'], organization_memberships: [{ name: 'Org1', role: 'basic_member' }], + create_organization_enabled: true, }); }); props.setProps({ hidePersonal: true }); @@ -116,6 +117,20 @@ describe('OrganizationSwitcher', () => { expect(fixtures.clerk.openCreateOrganization).toHaveBeenCalled(); }); + it('does not display create organization button if permissions not present', async () => { + const { wrapper, props } = await createFixtures(f => { + f.withOrganizations(); + f.withUser({ + email_addresses: ['test@clerk.dev'], + organization_memberships: [{ name: 'Org1', role: 'basic_member' }], + create_organization_enabled: false, + }); + }); + props.setProps({ hidePersonal: true }); + const { queryByRole } = render(, { wrapper }); + expect(queryByRole('button', { name: 'Create Organization' })).not.toBeInTheDocument(); + }); + it.todo('switches between active organizations when one is clicked'); }); }); diff --git a/packages/types/src/json.ts b/packages/types/src/json.ts index 7fa01eee3a..2373283a35 100644 --- a/packages/types/src/json.ts +++ b/packages/types/src/json.ts @@ -214,6 +214,7 @@ export interface UserJSON extends ClerkResourceJSON { public_metadata: UserPublicMetadata; unsafe_metadata: UserUnsafeMetadata; last_sign_in_at: number | null; + create_organization_enabled: boolean; delete_self_enabled: boolean; updated_at: number; created_at: number; diff --git a/packages/types/src/user.ts b/packages/types/src/user.ts index 24cefdf0d4..751abc84b4 100644 --- a/packages/types/src/user.ts +++ b/packages/types/src/user.ts @@ -77,6 +77,7 @@ export interface UserResource extends ClerkResource { publicMetadata: UserPublicMetadata; unsafeMetadata: UserUnsafeMetadata; lastSignInAt: Date | null; + createOrganizationEnabled: boolean; deleteSelfEnabled: boolean; updatedAt: Date | null; createdAt: Date | null; diff --git a/packages/types/src/userSettings.ts b/packages/types/src/userSettings.ts index 6ecff6a0fc..053992a097 100644 --- a/packages/types/src/userSettings.ts +++ b/packages/types/src/userSettings.ts @@ -91,6 +91,7 @@ export interface UserSettingsJSON extends ClerkResourceJSON { id: never; object: never; attributes: AttributesJSON; + actions: Actions; social: OAuthProviders; /** @@ -101,7 +102,6 @@ export interface UserSettingsJSON extends ClerkResourceJSON { sign_in: SignInData; sign_up: SignUpData; password_settings: PasswordSettingsData; - actions: Actions; } export interface UserSettingsResource extends ClerkResource {